From df93b9f242bbfc7ba51e66c2914931eb62035753 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 20 Jun 2019 11:36:43 -0700 Subject: [PATCH] cleaned source tree --- .../128x128/application-vnd.olive-project.png | Bin .../128x128/org.olivevideoeditor.Olive.png | Bin .../16x16/application-vnd.olive-project.png | Bin .../16x16/org.olivevideoeditor.Olive.png | Bin .../256x256/application-vnd.olive-project.png | Bin .../256x256/org.olivevideoeditor.Olive.png | Bin .../32x32/application-vnd.olive-project.png | Bin .../32x32/org.olivevideoeditor.Olive.png | Bin .../48x48/application-vnd.olive-project.png | Bin .../48x48/org.olivevideoeditor.Olive.png | Bin .../512x512/application-vnd.olive-project.png | Bin .../512x512/org.olivevideoeditor.Olive.png | Bin .../64x64/application-vnd.olive-project.png | Bin .../64x64/org.olivevideoeditor.Olive.png | Bin .../org.olivevideoeditor.Olive.appdata.xml | 0 .../linux/org.olivevideoeditor.Olive.desktop | 0 .../linux/org.olivevideoeditor.Olive.xml | 0 {packaging => app/packaging}/macos/olive.icns | Bin .../packaging}/windows/cv2pdb.LICENSE | 0 .../packaging}/windows/cv2pdb.exe | Bin .../packaging}/windows/nsis/install icon.ico | Bin .../packaging}/windows/nsis/olive.nsi | 0 .../windows/nsis/uninstall icon.ico | Bin .../packaging}/windows/olive.ico | Bin .../packaging}/windows/olive_ove.ico | Bin .../packaging}/windows/resources.rc | 0 .../packaging}/windows/version.h | 0 app/panel/project/project.h | 4 +- app/project/CMakeLists.txt | 6 + app/project/project.cpp | 6 + app/project/project.h | 11 + debian/changelog | 5 - debian/compat | 1 - debian/control | 13 - debian/copyright | 29 - debian/gitfromlog.sh | 3 - debian/rules | 9 - debian/source/format | 1 - decoders/audio/ffmpegaudiodecoder.cpp | 6 - decoders/audio/ffmpegaudiodecoder.h | 17 - decoders/decoder.cpp | 28 - decoders/decoder.h | 106 - decoders/ffmpegdecoder.cpp | 144 - decoders/ffmpegdecoder.h | 29 - decoders/ffmpegvideodecoder.cpp | 66 - decoders/ffmpegvideodecoder.h | 16 - decoders/frame.cpp | 89 - decoders/frame.h | 96 - decoders/pixelformatconverter.cpp | 241 - decoders/pixelformatconverter.h | 144 - dialogs/aboutdialog.cpp | 66 - dialogs/aboutdialog.h | 48 - dialogs/actionsearch.cpp | 244 - dialogs/actionsearch.h | 170 - dialogs/advancedvideodialog.cpp | 107 - dialogs/advancedvideodialog.h | 80 - dialogs/autocutsilencedialog.cpp | 215 - dialogs/autocutsilencedialog.h | 59 - dialogs/clippropertiesdialog.cpp | 145 - dialogs/clippropertiesdialog.h | 72 - dialogs/crashdialog.cpp | 46 - dialogs/crashdialog.h | 22 - dialogs/debugdialog.cpp | 63 - dialogs/debugdialog.h | 79 - dialogs/demonotice.cpp | 62 - dialogs/demonotice.h | 47 - dialogs/exportdialog.cpp | 807 --- dialogs/exportdialog.h | 277 - dialogs/loaddialog.cpp | 63 - dialogs/loaddialog.h | 76 - dialogs/mediapropertiesdialog.cpp | 238 - dialogs/mediapropertiesdialog.h | 97 - dialogs/newsequencedialog.cpp | 323 -- dialogs/newsequencedialog.h | 168 - dialogs/preferencesdialog.cpp | 1197 ---- dialogs/preferencesdialog.h | 432 -- dialogs/proxydialog.cpp | 184 - dialogs/proxydialog.h | 107 - dialogs/replaceclipmediadialog.cpp | 130 - dialogs/replaceclipmediadialog.h | 82 - dialogs/speeddialog.cpp | 461 -- dialogs/speeddialog.h | 132 - dialogs/texteditdialog.cpp | 213 - dialogs/texteditdialog.h | 179 - effects/effectfield.cpp | 344 -- effects/effectfield.h | 420 -- effects/effectfields.h | 40 - effects/effectgizmo.cpp | 63 - effects/effectgizmo.h | 73 - effects/effectloaders.cpp | 170 - effects/effectloaders.h | 55 - effects/fields/boolfield.cpp | 99 - effects/fields/boolfield.h | 101 - effects/fields/buttonfield.cpp | 66 - effects/fields/buttonfield.h | 111 - effects/fields/colorfield.cpp | 73 - effects/fields/colorfield.h | 88 - effects/fields/combofield.cpp | 93 - effects/fields/combofield.h | 113 - effects/fields/doublefield.cpp | 151 - effects/fields/doublefield.h | 210 - effects/fields/filefield.cpp | 68 - effects/fields/filefield.h | 79 - effects/fields/fontfield.cpp | 95 - effects/fields/fontfield.h | 88 - effects/fields/labelfield.cpp | 49 - effects/fields/labelfield.h | 55 - effects/fields/stringfield.cpp | 101 - effects/fields/stringfield.h | 87 - effects/internal/audionoiseeffect.cpp | 94 - effects/internal/audionoiseeffect.h | 49 - effects/internal/common.vert | 8 - effects/internal/cornerpin.frag | 46 - effects/internal/cornerpin.vert | 66 - effects/internal/cornerpineffect.cpp | 116 - effects/internal/cornerpineffect.h | 56 - effects/internal/crossdissolvetransition.cpp | 70 - effects/internal/crossdissolvetransition.h | 41 - effects/internal/cubetransition.h | 32 - effects/internal/dropshadow.frag | 46 - effects/internal/dropshadoweffect.cpp | 25 - effects/internal/dropshadoweffect.h | 31 - .../internal/exponentialfadetransition.cpp | 83 - effects/internal/exponentialfadetransition.h | 45 - effects/internal/fillleftrighteffect.cpp | 84 - effects/internal/fillleftrighteffect.h | 48 - effects/internal/frei0reffect.cpp | 196 - effects/internal/frei0reffect.h | 55 - effects/internal/internalshaders.qrc | 9 - effects/internal/linearfadetransition.cpp | 79 - effects/internal/linearfadetransition.h | 45 - .../internal/logarithmicfadetransition.cpp | 83 - effects/internal/logarithmicfadetransition.h | 45 - effects/internal/ocio.frag | 10 - effects/internal/paneffect.cpp | 96 - effects/internal/paneffect.h | 48 - effects/internal/premultiply.frag | 10 - effects/internal/richtexteffect.cpp | 225 - effects/internal/richtexteffect.h | 58 - effects/internal/shakeeffect.cpp | 116 - effects/internal/shakeeffect.h | 49 - effects/internal/solideffect.cpp | 241 - effects/internal/solideffect.h | 59 - effects/internal/texteffect.cpp | 317 -- effects/internal/texteffect.h | 72 - effects/internal/timecodeeffect.cpp | 167 - effects/internal/timecodeeffect.h | 59 - effects/internal/toneeffect.cpp | 114 - effects/internal/toneeffect.h | 54 - effects/internal/transformeffect.cpp | 256 - effects/internal/transformeffect.h | 68 - effects/internal/voideffect.cpp | 123 - effects/internal/voideffect.h | 54 - effects/internal/volumeeffect.cpp | 90 - effects/internal/volumeeffect.h | 49 - effects/internal/vsthost.cpp | 432 -- effects/internal/vsthost.h | 100 - effects/keyframe.cpp | 66 - effects/keyframe.h | 44 - effects/shaders/boxblur.frag | 27 - effects/shaders/boxblur.xml | 7 - effects/shaders/bulge.frag | 28 - effects/shaders/bulge.xml | 11 - effects/shaders/chromaticaberration.frag | 17 - effects/shaders/chromaticaberration.xml | 13 - effects/shaders/crop.frag | 47 - effects/shaders/crop.xml | 22 - effects/shaders/despill.frag | 69 - effects/shaders/despill.xml | 20 - effects/shaders/directionalblur.frag | 26 - effects/shaders/directionalblur.xml | 10 - effects/shaders/flip.frag | 14 - effects/shaders/flip.xml | 10 - effects/shaders/gaussianblur.frag | 47 - effects/shaders/gaussianblur.xml | 16 - effects/shaders/need checking/chromakey.frag | 67 - effects/shaders/need checking/chromakey.xml | 20 - .../need checking/colorcorrection.frag | 74 - .../shaders/need checking/colorcorrection.xml | 31 - effects/shaders/need checking/colorsel.frag | 78 - effects/shaders/need checking/colorsel.xml | 24 - effects/shaders/need checking/common.frag | 9 - effects/shaders/need checking/common.vert | 8 - .../shaders/need checking/crossstitch.frag | 44 - effects/shaders/need checking/crossstitch.xml | 10 - effects/shaders/need checking/emboss.frag | 38 - effects/shaders/need checking/emboss.xml | 16 - effects/shaders/need checking/findedges.frag | 53 - .../need checking/findedges.xml.disabled | 7 - effects/shaders/need checking/fisheye.frag | 23 - effects/shaders/need checking/fisheye.xml | 7 - effects/shaders/need checking/huesatbri.frag | 33 - effects/shaders/need checking/huesatbri.xml | 13 - effects/shaders/need checking/invert.frag | 7 - effects/shaders/need checking/invert.xml | 7 - effects/shaders/need checking/lumakey.frag | 29 - effects/shaders/need checking/lumakey.xml | 13 - effects/shaders/need checking/posterize.frag | 13 - effects/shaders/need checking/posterize.xml | 10 - effects/shaders/need checking/toonify.frag | 168 - effects/shaders/need checking/toonify.xml | 19 - .../need checking/volumetriclight.frag | 15 - .../shaders/need checking/volumetriclight.xml | 7 - effects/shaders/noise.frag | 33 - effects/shaders/noise.xml | 13 - effects/shaders/pixelate.frag | 16 - effects/shaders/pixelate.xml | 13 - effects/shaders/radialblur.frag | 34 - effects/shaders/radialblur.xml | 11 - effects/shaders/ripple.frag | 29 - effects/shaders/ripple.xml | 23 - effects/shaders/sphere.frag | 40 - effects/shaders/sphere.xml | 20 - effects/shaders/swirl.frag | 26 - effects/shaders/swirl.xml | 14 - effects/shaders/tile.frag | 25 - effects/shaders/tile.xml | 17 - effects/shaders/vignette.frag | 29 - effects/shaders/vignette.xml | 20 - effects/shaders/wave.frag | 21 - effects/shaders/wave.xml | 16 - effects/transition.cpp | 165 - effects/transition.h | 63 - global/clipboard.cpp | 104 - global/clipboard.h | 62 - global/config.cpp | 365 -- global/config.h | 681 --- global/crashhandler.cpp | 119 - global/crashhandler.h | 9 - global/crossplatformlib.cpp | 64 - global/crossplatformlib.h | 49 - global/debug.cpp | 112 - global/debug.h | 31 - global/global.cpp | 831 --- global/global.h | 573 -- global/math.cpp | 107 - global/math.h | 48 - global/path.cpp | 122 - global/path.h | 38 - global/rational.cpp | 377 -- global/rational.h | 65 - global/timing.cpp | 169 - global/timing.h | 137 - nodes/inputs.h | 15 - nodes/inputs/boolinput.cpp | 16 - nodes/inputs/boolinput.h | 36 - nodes/inputs/colorinput.cpp | 14 - nodes/inputs/colorinput.h | 28 - nodes/inputs/comboinput.cpp | 16 - nodes/inputs/comboinput.h | 36 - nodes/inputs/fileinput.cpp | 14 - nodes/inputs/fileinput.h | 28 - nodes/inputs/fontinput.cpp | 14 - nodes/inputs/fontinput.h | 28 - nodes/inputs/stringinput.cpp | 14 - nodes/inputs/stringinput.h | 33 - nodes/inputs/vecinput.cpp | 195 - nodes/inputs/vecinput.h | 78 - nodes/node.cpp | 64 - nodes/node.h | 39 - nodes/nodedatatypes.cpp | 74 - nodes/nodedatatypes.h | 102 - nodes/nodeedge.cpp | 21 - nodes/nodeedge.h | 39 - nodes/nodegraph.cpp | 86 - nodes/nodegraph.h | 79 - nodes/nodeio.cpp | 414 -- nodes/nodeio.h | 491 -- nodes/nodes.h | 8 - nodes/nodes/nodeblock.cpp | 72 - nodes/nodes/nodeblock.h | 48 - nodes/nodes/nodeclip.cpp | 7 - nodes/nodes/nodeclip.h | 25 - nodes/nodes/nodemedia.cpp | 101 - nodes/nodes/nodemedia.h | 56 - nodes/nodes/nodeshader.cpp | 222 - nodes/nodes/nodeshader.h | 32 - nodes/nodes/nodetexturepassthru.cpp | 38 - nodes/nodes/nodetexturepassthru.h | 24 - nodes/nodes/nodevideoclip.cpp | 16 - nodes/nodes/nodevideoclip.h | 19 - nodes/oldeffectnode.cpp | 920 ---- nodes/oldeffectnode.h | 281 - nodes/widgets/buttonwidget.cpp | 23 - nodes/widgets/buttonwidget.h | 35 - nodes/widgets/labelwidget.cpp | 7 - nodes/widgets/labelwidget.h | 12 - panels/effectcontrols.cpp | 425 -- panels/effectcontrols.h | 122 - panels/effectspanel.cpp | 275 - panels/effectspanel.h | 42 - panels/grapheditor.cpp | 256 - panels/grapheditor.h | 68 - panels/nodeeditor.cpp | 214 - panels/nodeeditor.h | 46 - panels/panels.cpp | 128 - panels/panels.h | 45 - panels/project.cpp | 658 --- panels/project.h | 97 - panels/timeline.cpp | 1126 ---- panels/timeline.h | 220 - panels/viewer.cpp | 944 ---- panels/viewer.h | 182 - project/footage.cpp | 179 - project/footage.h | 130 - project/loadthread.cpp | 803 --- project/loadthread.h | 92 - project/media.cpp | 394 -- project/media.h | 104 - project/previewgenerator.cpp | 628 --- project/previewgenerator.h | 65 - project/projectelements.h | 34 - project/projectfilter.cpp | 84 - project/projectfilter.h | 57 - project/projectfunctions.cpp | 83 - project/projectfunctions.h | 18 - project/projectmodel.cpp | 661 --- project/projectmodel.h | 132 - project/proxygenerator.cpp | 427 -- project/proxygenerator.h | 72 - project/savethread.cpp | 99 - project/savethread.h | 8 - project/sourcescommon.cpp | 466 -- project/sourcescommon.h | 77 - rendering/audio.cpp | 426 -- rendering/audio.h | 85 - rendering/cacher.cpp | 1459 ----- rendering/cacher.h | 602 -- rendering/clipqueue.cpp | 105 - rendering/clipqueue.h | 185 - rendering/exportthread.cpp | 705 --- rendering/exportthread.h | 141 - rendering/framebuffercollection.cpp | 68 - rendering/framebuffercollection.h | 27 - rendering/framebufferobject.cpp | 155 - rendering/framebufferobject.h | 50 - rendering/imagecache.cpp | 296 - rendering/imagecache.h | 91 - rendering/memorybuffer.cpp | 43 - rendering/memorybuffer.h | 28 - rendering/pixelformats.cpp | 60 - rendering/pixelformats.h | 65 - rendering/qopenglshaderprogramptr.h | 29 - rendering/renderfunctions.cpp | 850 --- rendering/renderfunctions.h | 247 - rendering/renderthread.cpp | 387 -- rendering/renderthread.h | 116 - rendering/shadergenerators.cpp | 230 - rendering/shadergenerators.h | 26 - snap/gui/olive-editor.desktop | 10 - snap/gui/olive-editor.png | Bin 83647 -> 0 bytes snap/snapcraft.yaml | 78 - thirdparty/vestige/include/vestige.h | 342 -- timeline/clip.cpp | 720 --- timeline/clip.h | 191 - timeline/ghost.cpp | 13 - timeline/ghost.h | 51 - timeline/marker.cpp | 165 - timeline/marker.h | 46 - timeline/mediaimportdata.cpp | 17 - timeline/mediaimportdata.h | 29 - timeline/selection.cpp | 86 - timeline/selection.h | 53 - timeline/sequence.cpp | 1404 ----- timeline/sequence.h | 161 - timeline/timelinefunctions.cpp | 172 - timeline/timelinefunctions.h | 42 - timeline/timelineshared.cpp | 6 - timeline/timelineshared.h | 11 - timeline/timelinetools.cpp | 3 - timeline/timelinetools.h | 47 - timeline/track.cpp | 421 -- timeline/track.h | 124 - timeline/tracktypes.h | 13 - ts/olive_ar.ts | 4866 ---------------- ts/olive_bs.ts | 4362 --------------- ts/olive_cs.ts | 3841 ------------- ts/olive_de.ts | 4902 ----------------- ts/olive_es.ts | 4209 -------------- ts/olive_fr.ts | 4833 ---------------- ts/olive_id.ts | 4532 --------------- ts/olive_it.ts | 4612 ---------------- ts/olive_ru.ts | 4386 --------------- ts/olive_sr.ts | 4349 --------------- ts/olive_uk.ts | 3813 ------------- ui/audiomonitor.cpp | 122 - ui/audiomonitor.h | 122 - ui/blur.cpp | 85 - ui/blur.h | 52 - ui/checkboxex.cpp | 33 - ui/checkboxex.h | 35 - ui/clickablelabel.cpp | 38 - ui/clickablelabel.h | 43 - ui/collapsiblewidget.cpp | 198 - ui/collapsiblewidget.h | 91 - ui/colorbutton.cpp | 53 - ui/colorbutton.h | 43 - ui/columnedgridlayout.cpp | 34 - ui/columnedgridlayout.h | 27 - ui/comboboxex.cpp | 42 - ui/comboboxex.h | 37 - ui/cursors.cpp | 69 - ui/cursors.h | 39 - ui/effectui.cpp | 358 -- ui/effectui.h | 223 - ui/embeddedfilechooser.cpp | 75 - ui/embeddedfilechooser.h | 45 - ui/flowlayout.cpp | 200 - ui/flowlayout.h | 87 - ui/focusfilter.cpp | 279 - ui/focusfilter.h | 231 - ui/graphview.cpp | 950 ---- ui/graphview.h | 122 - ui/icons.cpp | 114 - ui/icons.h | 66 - ui/keyframedrawing.cpp | 64 - ui/keyframedrawing.h | 34 - ui/keyframenavigator.cpp | 98 - ui/keyframenavigator.h | 55 - ui/keyframeview.cpp | 450 -- ui/keyframeview.h | 92 - ui/labelslider.cpp | 368 -- ui/labelslider.h | 231 - ui/mainwindow.cpp | 1230 ----- ui/mainwindow.h | 353 -- ui/mediaiconservice.cpp | 105 - ui/mediaiconservice.h | 60 - ui/menu.cpp | 40 - ui/menu.h | 33 - ui/menuhelper.cpp | 325 -- ui/menuhelper.h | 241 - ui/nodeedgeui.cpp | 67 - ui/nodeedgeui.h | 26 - ui/nodeui.cpp | 323 -- ui/nodeui.h | 49 - ui/nodeview.cpp | 69 - ui/nodeview.h | 28 - ui/panel.cpp | 65 - ui/panel.h | 46 - ui/playbutton.cpp | 9 - ui/playbutton.h | 15 - ui/rectangleselect.cpp | 27 - ui/rectangleselect.h | 45 - ui/resizablescrollbar.cpp | 126 - ui/resizablescrollbar.h | 49 - ui/sourceiconview.cpp | 215 - ui/sourceiconview.h | 61 - ui/sourcetable.cpp | 97 - ui/sourcetable.h | 52 - ui/styling.cpp | 44 - ui/styling.h | 87 - ui/texteditex.cpp | 117 - ui/texteditex.h | 52 - ui/timelinearea.cpp | 194 - ui/timelinearea.h | 41 - ui/timelineheader.cpp | 496 -- ui/timelineheader.h | 99 - ui/timelinelabel.cpp | 112 - ui/timelinelabel.h | 39 - ui/timelineview.cpp | 3398 ------------ ui/timelineview.h | 128 - ui/timelinewidget.cpp | 3451 ------------ ui/updatenotification.cpp | 58 - ui/updatenotification.h | 39 - ui/viewercontainer.cpp | 174 - ui/viewercontainer.h | 69 - ui/viewerwidget.cpp | 806 --- ui/viewerwidget.h | 115 - ui/viewerwindow.cpp | 193 - ui/viewerwindow.h | 63 - ui/waveform.cpp | 70 - ui/waveform.h | 25 - undo/comboaction.cpp | 60 - undo/comboaction.h | 116 - undo/undo.cpp | 1226 ----- undo/undo.h | 634 --- undo/undostack.cpp | 23 - undo/undostack.h | 33 - 478 files changed, 25 insertions(+), 114765 deletions(-) rename {packaging => app/packaging}/linux/icons/128x128/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/128x128/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/icons/16x16/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/16x16/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/icons/256x256/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/256x256/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/icons/32x32/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/32x32/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/icons/48x48/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/48x48/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/icons/512x512/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/512x512/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/icons/64x64/application-vnd.olive-project.png (100%) rename {packaging => app/packaging}/linux/icons/64x64/org.olivevideoeditor.Olive.png (100%) rename {packaging => app/packaging}/linux/org.olivevideoeditor.Olive.appdata.xml (100%) rename {packaging => app/packaging}/linux/org.olivevideoeditor.Olive.desktop (100%) rename {packaging => app/packaging}/linux/org.olivevideoeditor.Olive.xml (100%) rename {packaging => app/packaging}/macos/olive.icns (100%) rename {packaging => app/packaging}/windows/cv2pdb.LICENSE (100%) rename {packaging => app/packaging}/windows/cv2pdb.exe (100%) rename {packaging => app/packaging}/windows/nsis/install icon.ico (100%) rename {packaging => app/packaging}/windows/nsis/olive.nsi (100%) rename {packaging => app/packaging}/windows/nsis/uninstall icon.ico (100%) rename {packaging => app/packaging}/windows/olive.ico (100%) rename {packaging => app/packaging}/windows/olive_ove.ico (100%) rename {packaging => app/packaging}/windows/resources.rc (100%) rename {packaging => app/packaging}/windows/version.h (100%) create mode 100644 app/project/project.cpp create mode 100644 app/project/project.h delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100644 debian/gitfromlog.sh delete mode 100755 debian/rules delete mode 100644 debian/source/format delete mode 100644 decoders/audio/ffmpegaudiodecoder.cpp delete mode 100644 decoders/audio/ffmpegaudiodecoder.h delete mode 100644 decoders/decoder.cpp delete mode 100644 decoders/decoder.h delete mode 100644 decoders/ffmpegdecoder.cpp delete mode 100644 decoders/ffmpegdecoder.h delete mode 100644 decoders/ffmpegvideodecoder.cpp delete mode 100644 decoders/ffmpegvideodecoder.h delete mode 100644 decoders/frame.cpp delete mode 100644 decoders/frame.h delete mode 100644 decoders/pixelformatconverter.cpp delete mode 100644 decoders/pixelformatconverter.h delete mode 100644 dialogs/aboutdialog.cpp delete mode 100644 dialogs/aboutdialog.h delete mode 100644 dialogs/actionsearch.cpp delete mode 100644 dialogs/actionsearch.h delete mode 100644 dialogs/advancedvideodialog.cpp delete mode 100644 dialogs/advancedvideodialog.h delete mode 100644 dialogs/autocutsilencedialog.cpp delete mode 100644 dialogs/autocutsilencedialog.h delete mode 100644 dialogs/clippropertiesdialog.cpp delete mode 100644 dialogs/clippropertiesdialog.h delete mode 100644 dialogs/crashdialog.cpp delete mode 100644 dialogs/crashdialog.h delete mode 100644 dialogs/debugdialog.cpp delete mode 100644 dialogs/debugdialog.h delete mode 100644 dialogs/demonotice.cpp delete mode 100644 dialogs/demonotice.h delete mode 100644 dialogs/exportdialog.cpp delete mode 100644 dialogs/exportdialog.h delete mode 100644 dialogs/loaddialog.cpp delete mode 100644 dialogs/loaddialog.h delete mode 100644 dialogs/mediapropertiesdialog.cpp delete mode 100644 dialogs/mediapropertiesdialog.h delete mode 100644 dialogs/newsequencedialog.cpp delete mode 100644 dialogs/newsequencedialog.h delete mode 100644 dialogs/preferencesdialog.cpp delete mode 100644 dialogs/preferencesdialog.h delete mode 100644 dialogs/proxydialog.cpp delete mode 100644 dialogs/proxydialog.h delete mode 100644 dialogs/replaceclipmediadialog.cpp delete mode 100644 dialogs/replaceclipmediadialog.h delete mode 100644 dialogs/speeddialog.cpp delete mode 100644 dialogs/speeddialog.h delete mode 100644 dialogs/texteditdialog.cpp delete mode 100644 dialogs/texteditdialog.h delete mode 100644 effects/effectfield.cpp delete mode 100644 effects/effectfield.h delete mode 100644 effects/effectfields.h delete mode 100644 effects/effectgizmo.cpp delete mode 100644 effects/effectgizmo.h delete mode 100644 effects/effectloaders.cpp delete mode 100644 effects/effectloaders.h delete mode 100644 effects/fields/boolfield.cpp delete mode 100644 effects/fields/boolfield.h delete mode 100644 effects/fields/buttonfield.cpp delete mode 100644 effects/fields/buttonfield.h delete mode 100644 effects/fields/colorfield.cpp delete mode 100644 effects/fields/colorfield.h delete mode 100644 effects/fields/combofield.cpp delete mode 100644 effects/fields/combofield.h delete mode 100644 effects/fields/doublefield.cpp delete mode 100644 effects/fields/doublefield.h delete mode 100644 effects/fields/filefield.cpp delete mode 100644 effects/fields/filefield.h delete mode 100644 effects/fields/fontfield.cpp delete mode 100644 effects/fields/fontfield.h delete mode 100644 effects/fields/labelfield.cpp delete mode 100644 effects/fields/labelfield.h delete mode 100644 effects/fields/stringfield.cpp delete mode 100644 effects/fields/stringfield.h delete mode 100644 effects/internal/audionoiseeffect.cpp delete mode 100644 effects/internal/audionoiseeffect.h delete mode 100644 effects/internal/common.vert delete mode 100644 effects/internal/cornerpin.frag delete mode 100644 effects/internal/cornerpin.vert delete mode 100644 effects/internal/cornerpineffect.cpp delete mode 100644 effects/internal/cornerpineffect.h delete mode 100644 effects/internal/crossdissolvetransition.cpp delete mode 100644 effects/internal/crossdissolvetransition.h delete mode 100644 effects/internal/cubetransition.h delete mode 100644 effects/internal/dropshadow.frag delete mode 100644 effects/internal/dropshadoweffect.cpp delete mode 100644 effects/internal/dropshadoweffect.h delete mode 100644 effects/internal/exponentialfadetransition.cpp delete mode 100644 effects/internal/exponentialfadetransition.h delete mode 100644 effects/internal/fillleftrighteffect.cpp delete mode 100644 effects/internal/fillleftrighteffect.h delete mode 100644 effects/internal/frei0reffect.cpp delete mode 100644 effects/internal/frei0reffect.h delete mode 100644 effects/internal/internalshaders.qrc delete mode 100644 effects/internal/linearfadetransition.cpp delete mode 100644 effects/internal/linearfadetransition.h delete mode 100644 effects/internal/logarithmicfadetransition.cpp delete mode 100644 effects/internal/logarithmicfadetransition.h delete mode 100644 effects/internal/ocio.frag delete mode 100644 effects/internal/paneffect.cpp delete mode 100644 effects/internal/paneffect.h delete mode 100644 effects/internal/premultiply.frag delete mode 100644 effects/internal/richtexteffect.cpp delete mode 100644 effects/internal/richtexteffect.h delete mode 100644 effects/internal/shakeeffect.cpp delete mode 100644 effects/internal/shakeeffect.h delete mode 100644 effects/internal/solideffect.cpp delete mode 100644 effects/internal/solideffect.h delete mode 100644 effects/internal/texteffect.cpp delete mode 100644 effects/internal/texteffect.h delete mode 100644 effects/internal/timecodeeffect.cpp delete mode 100644 effects/internal/timecodeeffect.h delete mode 100644 effects/internal/toneeffect.cpp delete mode 100644 effects/internal/toneeffect.h delete mode 100644 effects/internal/transformeffect.cpp delete mode 100644 effects/internal/transformeffect.h delete mode 100644 effects/internal/voideffect.cpp delete mode 100644 effects/internal/voideffect.h delete mode 100644 effects/internal/volumeeffect.cpp delete mode 100644 effects/internal/volumeeffect.h delete mode 100644 effects/internal/vsthost.cpp delete mode 100644 effects/internal/vsthost.h delete mode 100644 effects/keyframe.cpp delete mode 100644 effects/keyframe.h delete mode 100644 effects/shaders/boxblur.frag delete mode 100644 effects/shaders/boxblur.xml delete mode 100644 effects/shaders/bulge.frag delete mode 100644 effects/shaders/bulge.xml delete mode 100644 effects/shaders/chromaticaberration.frag delete mode 100644 effects/shaders/chromaticaberration.xml delete mode 100644 effects/shaders/crop.frag delete mode 100644 effects/shaders/crop.xml delete mode 100644 effects/shaders/despill.frag delete mode 100644 effects/shaders/despill.xml delete mode 100644 effects/shaders/directionalblur.frag delete mode 100644 effects/shaders/directionalblur.xml delete mode 100644 effects/shaders/flip.frag delete mode 100644 effects/shaders/flip.xml delete mode 100644 effects/shaders/gaussianblur.frag delete mode 100644 effects/shaders/gaussianblur.xml delete mode 100644 effects/shaders/need checking/chromakey.frag delete mode 100644 effects/shaders/need checking/chromakey.xml delete mode 100644 effects/shaders/need checking/colorcorrection.frag delete mode 100644 effects/shaders/need checking/colorcorrection.xml delete mode 100644 effects/shaders/need checking/colorsel.frag delete mode 100644 effects/shaders/need checking/colorsel.xml delete mode 100644 effects/shaders/need checking/common.frag delete mode 100644 effects/shaders/need checking/common.vert delete mode 100644 effects/shaders/need checking/crossstitch.frag delete mode 100644 effects/shaders/need checking/crossstitch.xml delete mode 100644 effects/shaders/need checking/emboss.frag delete mode 100644 effects/shaders/need checking/emboss.xml delete mode 100644 effects/shaders/need checking/findedges.frag delete mode 100644 effects/shaders/need checking/findedges.xml.disabled delete mode 100644 effects/shaders/need checking/fisheye.frag delete mode 100644 effects/shaders/need checking/fisheye.xml delete mode 100644 effects/shaders/need checking/huesatbri.frag delete mode 100644 effects/shaders/need checking/huesatbri.xml delete mode 100644 effects/shaders/need checking/invert.frag delete mode 100644 effects/shaders/need checking/invert.xml delete mode 100644 effects/shaders/need checking/lumakey.frag delete mode 100644 effects/shaders/need checking/lumakey.xml delete mode 100644 effects/shaders/need checking/posterize.frag delete mode 100644 effects/shaders/need checking/posterize.xml delete mode 100644 effects/shaders/need checking/toonify.frag delete mode 100644 effects/shaders/need checking/toonify.xml delete mode 100644 effects/shaders/need checking/volumetriclight.frag delete mode 100644 effects/shaders/need checking/volumetriclight.xml delete mode 100644 effects/shaders/noise.frag delete mode 100644 effects/shaders/noise.xml delete mode 100644 effects/shaders/pixelate.frag delete mode 100644 effects/shaders/pixelate.xml delete mode 100644 effects/shaders/radialblur.frag delete mode 100644 effects/shaders/radialblur.xml delete mode 100644 effects/shaders/ripple.frag delete mode 100644 effects/shaders/ripple.xml delete mode 100644 effects/shaders/sphere.frag delete mode 100644 effects/shaders/sphere.xml delete mode 100644 effects/shaders/swirl.frag delete mode 100644 effects/shaders/swirl.xml delete mode 100644 effects/shaders/tile.frag delete mode 100644 effects/shaders/tile.xml delete mode 100644 effects/shaders/vignette.frag delete mode 100644 effects/shaders/vignette.xml delete mode 100644 effects/shaders/wave.frag delete mode 100644 effects/shaders/wave.xml delete mode 100644 effects/transition.cpp delete mode 100644 effects/transition.h delete mode 100644 global/clipboard.cpp delete mode 100644 global/clipboard.h delete mode 100644 global/config.cpp delete mode 100644 global/config.h delete mode 100644 global/crashhandler.cpp delete mode 100644 global/crashhandler.h delete mode 100644 global/crossplatformlib.cpp delete mode 100644 global/crossplatformlib.h delete mode 100644 global/debug.cpp delete mode 100644 global/debug.h delete mode 100644 global/global.cpp delete mode 100644 global/global.h delete mode 100644 global/math.cpp delete mode 100644 global/math.h delete mode 100644 global/path.cpp delete mode 100644 global/path.h delete mode 100644 global/rational.cpp delete mode 100644 global/rational.h delete mode 100644 global/timing.cpp delete mode 100644 global/timing.h delete mode 100644 nodes/inputs.h delete mode 100644 nodes/inputs/boolinput.cpp delete mode 100644 nodes/inputs/boolinput.h delete mode 100644 nodes/inputs/colorinput.cpp delete mode 100644 nodes/inputs/colorinput.h delete mode 100644 nodes/inputs/comboinput.cpp delete mode 100644 nodes/inputs/comboinput.h delete mode 100644 nodes/inputs/fileinput.cpp delete mode 100644 nodes/inputs/fileinput.h delete mode 100644 nodes/inputs/fontinput.cpp delete mode 100644 nodes/inputs/fontinput.h delete mode 100644 nodes/inputs/stringinput.cpp delete mode 100644 nodes/inputs/stringinput.h delete mode 100644 nodes/inputs/vecinput.cpp delete mode 100644 nodes/inputs/vecinput.h delete mode 100644 nodes/node.cpp delete mode 100644 nodes/node.h delete mode 100644 nodes/nodedatatypes.cpp delete mode 100644 nodes/nodedatatypes.h delete mode 100644 nodes/nodeedge.cpp delete mode 100644 nodes/nodeedge.h delete mode 100644 nodes/nodegraph.cpp delete mode 100644 nodes/nodegraph.h delete mode 100644 nodes/nodeio.cpp delete mode 100644 nodes/nodeio.h delete mode 100644 nodes/nodes.h delete mode 100644 nodes/nodes/nodeblock.cpp delete mode 100644 nodes/nodes/nodeblock.h delete mode 100644 nodes/nodes/nodeclip.cpp delete mode 100644 nodes/nodes/nodeclip.h delete mode 100644 nodes/nodes/nodemedia.cpp delete mode 100644 nodes/nodes/nodemedia.h delete mode 100644 nodes/nodes/nodeshader.cpp delete mode 100644 nodes/nodes/nodeshader.h delete mode 100644 nodes/nodes/nodetexturepassthru.cpp delete mode 100644 nodes/nodes/nodetexturepassthru.h delete mode 100644 nodes/nodes/nodevideoclip.cpp delete mode 100644 nodes/nodes/nodevideoclip.h delete mode 100644 nodes/oldeffectnode.cpp delete mode 100644 nodes/oldeffectnode.h delete mode 100644 nodes/widgets/buttonwidget.cpp delete mode 100644 nodes/widgets/buttonwidget.h delete mode 100644 nodes/widgets/labelwidget.cpp delete mode 100644 nodes/widgets/labelwidget.h delete mode 100644 panels/effectcontrols.cpp delete mode 100644 panels/effectcontrols.h delete mode 100644 panels/effectspanel.cpp delete mode 100644 panels/effectspanel.h delete mode 100644 panels/grapheditor.cpp delete mode 100644 panels/grapheditor.h delete mode 100644 panels/nodeeditor.cpp delete mode 100644 panels/nodeeditor.h delete mode 100644 panels/panels.cpp delete mode 100644 panels/panels.h delete mode 100644 panels/project.cpp delete mode 100644 panels/project.h delete mode 100644 panels/timeline.cpp delete mode 100644 panels/timeline.h delete mode 100644 panels/viewer.cpp delete mode 100644 panels/viewer.h delete mode 100644 project/footage.cpp delete mode 100644 project/footage.h delete mode 100644 project/loadthread.cpp delete mode 100644 project/loadthread.h delete mode 100644 project/media.cpp delete mode 100644 project/media.h delete mode 100644 project/previewgenerator.cpp delete mode 100644 project/previewgenerator.h delete mode 100644 project/projectelements.h delete mode 100644 project/projectfilter.cpp delete mode 100644 project/projectfilter.h delete mode 100644 project/projectfunctions.cpp delete mode 100644 project/projectfunctions.h delete mode 100644 project/projectmodel.cpp delete mode 100644 project/projectmodel.h delete mode 100644 project/proxygenerator.cpp delete mode 100644 project/proxygenerator.h delete mode 100644 project/savethread.cpp delete mode 100644 project/savethread.h delete mode 100644 project/sourcescommon.cpp delete mode 100644 project/sourcescommon.h delete mode 100644 rendering/audio.cpp delete mode 100644 rendering/audio.h delete mode 100644 rendering/cacher.cpp delete mode 100644 rendering/cacher.h delete mode 100644 rendering/clipqueue.cpp delete mode 100644 rendering/clipqueue.h delete mode 100644 rendering/exportthread.cpp delete mode 100644 rendering/exportthread.h delete mode 100644 rendering/framebuffercollection.cpp delete mode 100644 rendering/framebuffercollection.h delete mode 100644 rendering/framebufferobject.cpp delete mode 100644 rendering/framebufferobject.h delete mode 100644 rendering/imagecache.cpp delete mode 100644 rendering/imagecache.h delete mode 100644 rendering/memorybuffer.cpp delete mode 100644 rendering/memorybuffer.h delete mode 100644 rendering/pixelformats.cpp delete mode 100644 rendering/pixelformats.h delete mode 100644 rendering/qopenglshaderprogramptr.h delete mode 100644 rendering/renderfunctions.cpp delete mode 100644 rendering/renderfunctions.h delete mode 100644 rendering/renderthread.cpp delete mode 100644 rendering/renderthread.h delete mode 100644 rendering/shadergenerators.cpp delete mode 100644 rendering/shadergenerators.h delete mode 100644 snap/gui/olive-editor.desktop delete mode 100644 snap/gui/olive-editor.png delete mode 100644 snap/snapcraft.yaml delete mode 100755 thirdparty/vestige/include/vestige.h delete mode 100644 timeline/clip.cpp delete mode 100644 timeline/clip.h delete mode 100644 timeline/ghost.cpp delete mode 100644 timeline/ghost.h delete mode 100644 timeline/marker.cpp delete mode 100644 timeline/marker.h delete mode 100644 timeline/mediaimportdata.cpp delete mode 100644 timeline/mediaimportdata.h delete mode 100644 timeline/selection.cpp delete mode 100644 timeline/selection.h delete mode 100644 timeline/sequence.cpp delete mode 100644 timeline/sequence.h delete mode 100644 timeline/timelinefunctions.cpp delete mode 100644 timeline/timelinefunctions.h delete mode 100644 timeline/timelineshared.cpp delete mode 100644 timeline/timelineshared.h delete mode 100644 timeline/timelinetools.cpp delete mode 100644 timeline/timelinetools.h delete mode 100644 timeline/track.cpp delete mode 100644 timeline/track.h delete mode 100644 timeline/tracktypes.h delete mode 100644 ts/olive_ar.ts delete mode 100644 ts/olive_bs.ts delete mode 100644 ts/olive_cs.ts delete mode 100644 ts/olive_de.ts delete mode 100644 ts/olive_es.ts delete mode 100644 ts/olive_fr.ts delete mode 100644 ts/olive_id.ts delete mode 100644 ts/olive_it.ts delete mode 100644 ts/olive_ru.ts delete mode 100644 ts/olive_sr.ts delete mode 100644 ts/olive_uk.ts delete mode 100644 ui/audiomonitor.cpp delete mode 100644 ui/audiomonitor.h delete mode 100644 ui/blur.cpp delete mode 100644 ui/blur.h delete mode 100644 ui/checkboxex.cpp delete mode 100644 ui/checkboxex.h delete mode 100644 ui/clickablelabel.cpp delete mode 100644 ui/clickablelabel.h delete mode 100644 ui/collapsiblewidget.cpp delete mode 100644 ui/collapsiblewidget.h delete mode 100644 ui/colorbutton.cpp delete mode 100644 ui/colorbutton.h delete mode 100644 ui/columnedgridlayout.cpp delete mode 100644 ui/columnedgridlayout.h delete mode 100644 ui/comboboxex.cpp delete mode 100644 ui/comboboxex.h delete mode 100644 ui/cursors.cpp delete mode 100644 ui/cursors.h delete mode 100644 ui/effectui.cpp delete mode 100644 ui/effectui.h delete mode 100644 ui/embeddedfilechooser.cpp delete mode 100644 ui/embeddedfilechooser.h delete mode 100644 ui/flowlayout.cpp delete mode 100644 ui/flowlayout.h delete mode 100644 ui/focusfilter.cpp delete mode 100644 ui/focusfilter.h delete mode 100644 ui/graphview.cpp delete mode 100644 ui/graphview.h delete mode 100644 ui/icons.cpp delete mode 100644 ui/icons.h delete mode 100644 ui/keyframedrawing.cpp delete mode 100644 ui/keyframedrawing.h delete mode 100644 ui/keyframenavigator.cpp delete mode 100644 ui/keyframenavigator.h delete mode 100644 ui/keyframeview.cpp delete mode 100644 ui/keyframeview.h delete mode 100644 ui/labelslider.cpp delete mode 100644 ui/labelslider.h delete mode 100644 ui/mainwindow.cpp delete mode 100644 ui/mainwindow.h delete mode 100644 ui/mediaiconservice.cpp delete mode 100644 ui/mediaiconservice.h delete mode 100644 ui/menu.cpp delete mode 100644 ui/menu.h delete mode 100644 ui/menuhelper.cpp delete mode 100644 ui/menuhelper.h delete mode 100644 ui/nodeedgeui.cpp delete mode 100644 ui/nodeedgeui.h delete mode 100644 ui/nodeui.cpp delete mode 100644 ui/nodeui.h delete mode 100644 ui/nodeview.cpp delete mode 100644 ui/nodeview.h delete mode 100644 ui/panel.cpp delete mode 100644 ui/panel.h delete mode 100644 ui/playbutton.cpp delete mode 100644 ui/playbutton.h delete mode 100644 ui/rectangleselect.cpp delete mode 100644 ui/rectangleselect.h delete mode 100644 ui/resizablescrollbar.cpp delete mode 100644 ui/resizablescrollbar.h delete mode 100644 ui/sourceiconview.cpp delete mode 100644 ui/sourceiconview.h delete mode 100644 ui/sourcetable.cpp delete mode 100644 ui/sourcetable.h delete mode 100644 ui/styling.cpp delete mode 100644 ui/styling.h delete mode 100644 ui/texteditex.cpp delete mode 100644 ui/texteditex.h delete mode 100644 ui/timelinearea.cpp delete mode 100644 ui/timelinearea.h delete mode 100644 ui/timelineheader.cpp delete mode 100644 ui/timelineheader.h delete mode 100644 ui/timelinelabel.cpp delete mode 100644 ui/timelinelabel.h delete mode 100644 ui/timelineview.cpp delete mode 100644 ui/timelineview.h delete mode 100644 ui/timelinewidget.cpp delete mode 100644 ui/updatenotification.cpp delete mode 100644 ui/updatenotification.h delete mode 100644 ui/viewercontainer.cpp delete mode 100644 ui/viewercontainer.h delete mode 100644 ui/viewerwidget.cpp delete mode 100644 ui/viewerwidget.h delete mode 100644 ui/viewerwindow.cpp delete mode 100644 ui/viewerwindow.h delete mode 100644 ui/waveform.cpp delete mode 100644 ui/waveform.h delete mode 100644 undo/comboaction.cpp delete mode 100644 undo/comboaction.h delete mode 100644 undo/undo.cpp delete mode 100644 undo/undo.h delete mode 100644 undo/undostack.cpp delete mode 100644 undo/undostack.h diff --git a/packaging/linux/icons/128x128/application-vnd.olive-project.png b/app/packaging/linux/icons/128x128/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/128x128/application-vnd.olive-project.png rename to app/packaging/linux/icons/128x128/application-vnd.olive-project.png diff --git a/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/icons/16x16/application-vnd.olive-project.png b/app/packaging/linux/icons/16x16/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/16x16/application-vnd.olive-project.png rename to app/packaging/linux/icons/16x16/application-vnd.olive-project.png diff --git a/packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/16x16/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/icons/256x256/application-vnd.olive-project.png b/app/packaging/linux/icons/256x256/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/256x256/application-vnd.olive-project.png rename to app/packaging/linux/icons/256x256/application-vnd.olive-project.png diff --git a/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/icons/32x32/application-vnd.olive-project.png b/app/packaging/linux/icons/32x32/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/32x32/application-vnd.olive-project.png rename to app/packaging/linux/icons/32x32/application-vnd.olive-project.png diff --git a/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/icons/48x48/application-vnd.olive-project.png b/app/packaging/linux/icons/48x48/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/48x48/application-vnd.olive-project.png rename to app/packaging/linux/icons/48x48/application-vnd.olive-project.png diff --git a/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/icons/512x512/application-vnd.olive-project.png b/app/packaging/linux/icons/512x512/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/512x512/application-vnd.olive-project.png rename to app/packaging/linux/icons/512x512/application-vnd.olive-project.png diff --git a/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/icons/64x64/application-vnd.olive-project.png b/app/packaging/linux/icons/64x64/application-vnd.olive-project.png similarity index 100% rename from packaging/linux/icons/64x64/application-vnd.olive-project.png rename to app/packaging/linux/icons/64x64/application-vnd.olive-project.png diff --git a/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png b/app/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png similarity index 100% rename from packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png rename to app/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png diff --git a/packaging/linux/org.olivevideoeditor.Olive.appdata.xml b/app/packaging/linux/org.olivevideoeditor.Olive.appdata.xml similarity index 100% rename from packaging/linux/org.olivevideoeditor.Olive.appdata.xml rename to app/packaging/linux/org.olivevideoeditor.Olive.appdata.xml diff --git a/packaging/linux/org.olivevideoeditor.Olive.desktop b/app/packaging/linux/org.olivevideoeditor.Olive.desktop similarity index 100% rename from packaging/linux/org.olivevideoeditor.Olive.desktop rename to app/packaging/linux/org.olivevideoeditor.Olive.desktop diff --git a/packaging/linux/org.olivevideoeditor.Olive.xml b/app/packaging/linux/org.olivevideoeditor.Olive.xml similarity index 100% rename from packaging/linux/org.olivevideoeditor.Olive.xml rename to app/packaging/linux/org.olivevideoeditor.Olive.xml diff --git a/packaging/macos/olive.icns b/app/packaging/macos/olive.icns similarity index 100% rename from packaging/macos/olive.icns rename to app/packaging/macos/olive.icns diff --git a/packaging/windows/cv2pdb.LICENSE b/app/packaging/windows/cv2pdb.LICENSE similarity index 100% rename from packaging/windows/cv2pdb.LICENSE rename to app/packaging/windows/cv2pdb.LICENSE diff --git a/packaging/windows/cv2pdb.exe b/app/packaging/windows/cv2pdb.exe similarity index 100% rename from packaging/windows/cv2pdb.exe rename to app/packaging/windows/cv2pdb.exe diff --git a/packaging/windows/nsis/install icon.ico b/app/packaging/windows/nsis/install icon.ico similarity index 100% rename from packaging/windows/nsis/install icon.ico rename to app/packaging/windows/nsis/install icon.ico diff --git a/packaging/windows/nsis/olive.nsi b/app/packaging/windows/nsis/olive.nsi similarity index 100% rename from packaging/windows/nsis/olive.nsi rename to app/packaging/windows/nsis/olive.nsi diff --git a/packaging/windows/nsis/uninstall icon.ico b/app/packaging/windows/nsis/uninstall icon.ico similarity index 100% rename from packaging/windows/nsis/uninstall icon.ico rename to app/packaging/windows/nsis/uninstall icon.ico diff --git a/packaging/windows/olive.ico b/app/packaging/windows/olive.ico similarity index 100% rename from packaging/windows/olive.ico rename to app/packaging/windows/olive.ico diff --git a/packaging/windows/olive_ove.ico b/app/packaging/windows/olive_ove.ico similarity index 100% rename from packaging/windows/olive_ove.ico rename to app/packaging/windows/olive_ove.ico diff --git a/packaging/windows/resources.rc b/app/packaging/windows/resources.rc similarity index 100% rename from packaging/windows/resources.rc rename to app/packaging/windows/resources.rc diff --git a/packaging/windows/version.h b/app/packaging/windows/version.h similarity index 100% rename from packaging/windows/version.h rename to app/packaging/windows/version.h diff --git a/app/panel/project/project.h b/app/panel/project/project.h index 3bea6f785..bbcf975c9 100644 --- a/app/panel/project/project.h +++ b/app/panel/project/project.h @@ -1,5 +1,5 @@ -#ifndef PROJECT_H -#define PROJECT_H +#ifndef PROJECT_PANEL_H +#define PROJECT_PANEL_H #include "widget/panel/panel.h" #include "widget/projectexplorer/projectexplorer.h" diff --git a/app/project/CMakeLists.txt b/app/project/CMakeLists.txt index 3cfb0783f..421066ffe 100644 --- a/app/project/CMakeLists.txt +++ b/app/project/CMakeLists.txt @@ -14,3 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + project/project.h + project/project.cpp + PARENT_SCOPE +) diff --git a/app/project/project.cpp b/app/project/project.cpp new file mode 100644 index 000000000..bb8dccb02 --- /dev/null +++ b/app/project/project.cpp @@ -0,0 +1,6 @@ +#include "project.h" + +Project::Project() +{ + +} diff --git a/app/project/project.h b/app/project/project.h new file mode 100644 index 000000000..a28a2d676 --- /dev/null +++ b/app/project/project.h @@ -0,0 +1,11 @@ +#ifndef PROJECT_H +#define PROJECT_H + + +class Project +{ +public: + Project(); +}; + +#endif // PROJECT_H diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 0f9a79b8e..000000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -olive-editor (201902160026-0ac9dd9+805~ubuntu19.04.1) disco; urgency=low - - * Auto build. - - -- Launchpad Package Builder Sat, 16 Feb 2019 00:26:45 +0000 \ No newline at end of file diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec635144f..000000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control deleted file mode 100644 index 5a96631d9..000000000 --- a/debian/control +++ /dev/null @@ -1,13 +0,0 @@ -Source: olive-editor -Section: video -Priority: optional -Maintainer: Olive Team -Build-Depends: debhelper (>=9), build-essential, qt5-default, qtmultimedia5-dev, libqt5opengl5-dev, libqt5svg5-dev, libqt5multimedia5-plugins, libavformat-dev, libavcodec-dev, libavutil-dev, libswscale-dev, libswresample-dev, libavfilter-dev, libpostproc-dev, git, frei0r-plugins-dev, qttools5-dev-tools, cmake, qttools5-dev -Standards-Version: 3.9.6 -Homepage: https://olivevideoeditor.org/ - -Package: olive-editor -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, libqt5multimedia5-plugins -Description: Nonlinear video editor focused on performance and simplicity - diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 056628290..000000000 --- a/debian/copyright +++ /dev/null @@ -1,29 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: olive-editor -Source: https://olivevideoeditor.org/ - -Files: * -Copyright: 2018 Olive Team -License: GPL-3.0+ - -Files: debian/* -Copyright: 2014 Olive Team -License: GPL-3.0+ - -License: GPL-3.0+ - 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 package 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 . - . - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". - diff --git a/debian/gitfromlog.sh b/debian/gitfromlog.sh deleted file mode 100644 index 92edf7e5d..000000000 --- a/debian/gitfromlog.sh +++ /dev/null @@ -1,3 +0,0 @@ -# A simple script to extract the Git hash from an auto-generated debian/changelog - -grep -Po '(?<=-)(([a-z0-9])\w+)(?=\+)' -m 1 $1 \ No newline at end of file diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 9a794c695..000000000 --- a/debian/rules +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/make -f -export QT_SELECT := qt5 - -%: - dh $@ - -override_dh_auto_build: - lrelease olive.pro - dh_auto_build diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 163aaf8d8..000000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/decoders/audio/ffmpegaudiodecoder.cpp b/decoders/audio/ffmpegaudiodecoder.cpp deleted file mode 100644 index 8f0fd8d3b..000000000 --- a/decoders/audio/ffmpegaudiodecoder.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "ffmpegaudiodecoder.h" - -FFmpegAudioDecoder::FFmpegAudioDecoder() -{ - -} diff --git a/decoders/audio/ffmpegaudiodecoder.h b/decoders/audio/ffmpegaudiodecoder.h deleted file mode 100644 index d07945684..000000000 --- a/decoders/audio/ffmpegaudiodecoder.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef FFMPEGAUDIODECODER_H -#define FFMPEGAUDIODECODER_H - -#include "decoders/ffmpegdecoder.h" - -/** - * @brief The FFmpegAudioDecoder class - * - * The role of an audio decoder is to simply convert audio to - */ -class FFmpegAudioDecoder : public FFmpegDecoder -{ -public: - FFmpegAudioDecoder(); -}; - -#endif // FFMPEGAUDIODECODER_H diff --git a/decoders/decoder.cpp b/decoders/decoder.cpp deleted file mode 100644 index 14b7c2018..000000000 --- a/decoders/decoder.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "decoder.h" - -Decoder::Decoder() : - open_(false) -{ -} - -Decoder::Decoder(FootageStream *fs) : - open_(false), - stream_(fs) -{ -} - -Decoder::~Decoder() -{ -} - -FootageStream *Decoder::stream() -{ - return stream_; -} - -void Decoder::set_stream(FootageStream *fs) -{ - Close(); - - stream_ = fs; -} diff --git a/decoders/decoder.h b/decoders/decoder.h deleted file mode 100644 index 62b0f452a..000000000 --- a/decoders/decoder.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef DECODER_H -#define DECODER_H - -#include - -#include "global/rational.h" -#include "project/footage.h" -#include "frame.h" - -/** - * @brief The Decoder class - * - * A decoder's is the main class for bringing external media into Olive. Its responsibilities are to serve as - * abstraction from codecs/decoders and provide complete frames. These frames can be video or audio data and are - * provided as Frame objects in shared pointers to alleviate the responsibility of memory handling. - * - * The main function in a decoder is Retrieve() which should return complete image/audio data. A decoder should - * alleviate all the complexities of codec compression from the rest of the application (i.e. a decoder should never - * return a partial frame or require other parts of the system to interface directly with the codec). Often this will - * necessitate pre-emptively caching, indexing, or even fully transcoding media before using it which can be implemented - * through the Analyze() function. - * - * A decoder does NOT perform any pixel/sample format conversion. Frames should pass through the PixelFormatConverter - * (olive::pix_fmt_conv) to be utilized in the rest of the rendering pipeline. - */ -class Decoder : public QObject -{ - Q_OBJECT -public: - Decoder(); - - Decoder(FootageStream* fs); - - virtual ~Decoder(); - - FootageStream* stream(); - void set_stream(FootageStream* fs); - - /** - * @brief Open media/allocate memory - * - * Any file handles or memory allocation that needs to be done before this instance of a Decoder can return data - * should be done here. - * - * @return - * - * TRUE if successful and ready to return data, FALSE if failed to open and unable to retrieve data. If the function - * fails, any memory allocated should be free'd before returning FALSE, possibly by calling Close(). - */ - virtual bool Open() = 0; - - /** - * @brief Retrieve frame/data - * - * The main function for retrieving data from the Decoder. This function should always provide complete frame data - * (i.e. no partial frames or missing samples) at the timecode provided. The Decoder should perform any steps - * required to retrieve a complete frame separate from the rest of the program, using any form of caching/indexing - * to keep this as performant as possible. - * - * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns - * false, this function should return nullptr. - * - * @param timecode - * - * The timecode (a rational in seconds) to retrieve the data at. - * - * @param length - * - * Audio only - ignored for video decoders. The total length of audio data to retrieve (a rational in seconds). - * - * @return - * - * A FramePtr of valid data at this timecode (of the requested length if this is audio media), or nullptr if there - * was nothing to retrieve at the provided timecode or the media could not be opened. - */ - virtual FramePtr Retrieve(const rational& timecode, const rational& length = 0) = 0; - - /** - * @brief Close media/deallocate memory - * - * Any file handles or memory allocations opened in Open() should be cleaned up here. - * - * As the main memory freeing function, it's good practice to call this in Open() if there's an error that prevents - * correct function before Open() returns. As such, Close() should be prepared for not all memory/file handles to - * have been opened successfully. - */ - virtual void Close() = 0; - - /** - * @brief Prepare footage for use by a Decoder later - * - * Needs fleshing out. This functions purpose will be to perform initial analyses of a video file. Any caching, - * indexing, or transcoding to help make this media performant and reliable should be done here. - */ - virtual void Analyze();// = 0; - -protected: - bool open_; - -private: - FootageStream* stream_; -}; - -using DecoderPtr = std::shared_ptr; - -#endif // DECODER_H diff --git a/decoders/ffmpegdecoder.cpp b/decoders/ffmpegdecoder.cpp deleted file mode 100644 index 0885fc709..000000000 --- a/decoders/ffmpegdecoder.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "ffmpegdecoder.h" - -extern "C" { -#include -#include -} - -#include -#include -#include -#include - -#include "ui/mainwindow.h" - -FFmpegDecoder::FFmpegDecoder() : - fmt_ctx_(nullptr), - codec_ctx_(nullptr), - opts_(nullptr) -{ -} - -bool FFmpegDecoder::Open() -{ - if (open_) { - return true; - } - - int error_code; - - qDebug() << "shid"; - qDebug() << stream()->footage; - qDebug() << stream()->footage->url; - - QByteArray ba = stream()->footage->url.toUtf8(); - const char* filename = ba.constData(); - - // Open file in a format context - error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr); - - // Handle format context error - if (error_code != 0) { - FFmpegErr(error_code); - return false; - } - - // Get stream information from format - error_code = avformat_find_stream_info(fmt_ctx_, nullptr); - - // Handle get stream information error - if (error_code < 0) { - FFmpegErr(error_code); - return false; - } - - // Dump format information - av_dump_format(fmt_ctx_, stream()->file_index, filename, 0); - - // Get reference to correct AVStream - avstream_ = fmt_ctx_->streams[stream()->file_index]; - - // Find decoder - AVCodec* codec = avcodec_find_decoder(avstream_->codecpar->codec_id); - - // Handle failure to find decoder - if (codec == nullptr) { - Error(tr("Failed to find appropriate decoder for this codec (%1 :: %2)") - .arg(stream()->footage->url, avstream_->codecpar->codec_id)); - return false; - } - - // Allocate context for the decoder - codec_ctx_ = avcodec_alloc_context3(codec); - if (codec_ctx_ == nullptr) { - Error(tr("Failed to allocate codec context (%1 :: %2)").arg(stream()->footage->url, stream()->file_index)); - return false; - } - - // Copy parameters from the AVStream to the AVCodecContext - error_code = avcodec_parameters_to_context(codec_ctx_, avstream_->codecpar); - - // Handle failure to copy parameters - if (error_code < 0) { - FFmpegErr(error_code); - return false; - } - - // enable multithreading on decoding - error_code = av_dict_set(&opts_, "threads", "auto", 0); - - // Handle failure to set multithreaded decoding - if (error_code < 0) { - FFmpegErr(error_code); - return false; - } - - // Open codec - error_code = avcodec_open2(codec_ctx_, codec, &opts_); - if (error_code < 0) { - FFmpegErr(error_code); - return false; - } - - open_ = true; - - return true; -} - -void FFmpegDecoder::Close() -{ - if (opts_ != nullptr) { - av_dict_free(&opts_); - opts_ = nullptr; - } - - if (codec_ctx_ != nullptr) { - avcodec_free_context(&codec_ctx_); - codec_ctx_ = nullptr; - } - - if (fmt_ctx_ != nullptr) { - avformat_close_input(&fmt_ctx_); - fmt_ctx_ = nullptr; - } - - open_ = false; -} - -void FFmpegDecoder::FFmpegErr(int error_code) -{ - char err[1024]; - av_strerror(error_code, err, 1024); - - Error(tr("Error decoding %1 - %2 %3").arg(stream()->footage->url, - QString::number(error_code), - err)); -} - -void FFmpegDecoder::Error(const QString &s) -{ - qWarning() << s; - olive::MainWindow->statusBar()->showMessage(s); - - Close(); -} diff --git a/decoders/ffmpegdecoder.h b/decoders/ffmpegdecoder.h deleted file mode 100644 index 68b23800f..000000000 --- a/decoders/ffmpegdecoder.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef FFMPEGDECODER_H -#define FFMPEGDECODER_H - -#include "decoder.h" - -class FFmpegDecoder : public Decoder -{ -public: - FFmpegDecoder(); - - virtual bool Open() override; - virtual void Close() override; - -protected: - void FFmpegErr(int error_code); - void Error(const QString& s); - - AVFormatContext* fmt_ctx_; - AVCodecContext* codec_ctx_; - AVStream* avstream_; - AVPacket* pkt_; - AVFrame* frame_; - AVDictionary* opts_; - - QVector frame_index_; - -}; - -#endif // FFMPEGDECODER_H diff --git a/decoders/ffmpegvideodecoder.cpp b/decoders/ffmpegvideodecoder.cpp deleted file mode 100644 index c4b33eee4..000000000 --- a/decoders/ffmpegvideodecoder.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "ffmpegvideodecoder.h" - -#include - -FFmpegVideoDecoder::FFmpegVideoDecoder() -{ - -} - -FramePtr FFmpegVideoDecoder::Retrieve(const rational &timecode, const rational &length) -{ - if (!open_ && !Open()) { - qWarning() << "Failed to open FFmpeg stream"; - return nullptr; - } - // TODO index frames - - int receive_ret; - - // Allocate new frame - AVFrame* frame = av_frame_alloc(); - AVPacket* pkt = av_packet_alloc(); - - while ((receive_ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN)) { - int read_ret = 0; - do { - - // Make sure any previous packet buffers are cleared before reading new ones - av_packet_unref(pkt); - - // Read next packet from file - read_ret = av_read_frame(fmt_ctx_, pkt); - - } while (read_ret >= 0 && pkt->stream_index != stream()->file_index); - - if (read_ret >= 0) { - int send_ret = avcodec_send_packet(codec_ctx_, pkt); - if (send_ret < 0) { - qCritical() << "Failed to send packet to decoder." << send_ret; - return nullptr; - } - } else { - if (read_ret == AVERROR_EOF) { - int send_ret = avcodec_send_packet(codec_ctx_, nullptr); - if (send_ret < 0) { - qCritical() << "Failed to send packet to decoder." << send_ret; - return nullptr; - } - } else { - qCritical() << "Could not read frame." << read_ret; - return nullptr; - } - } - } - if (receive_ret < 0) { - if (receive_ret != AVERROR_EOF) { - qCritical() << "Failed to receive packet from decoder." << receive_ret; - } - } - - // Free AVPacket - av_packet_free(&pkt); - - // AVFrame is wrapped in Frame object and shared ptr to automatically clear it - return std::make_shared(frame); -} diff --git a/decoders/ffmpegvideodecoder.h b/decoders/ffmpegvideodecoder.h deleted file mode 100644 index 46cb29588..000000000 --- a/decoders/ffmpegvideodecoder.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef FFMPEGVIDEODECODER_H -#define FFMPEGVIDEODECODER_H - -#include "ffmpegdecoder.h" - -class FFmpegVideoDecoder : public FFmpegDecoder -{ -public: - FFmpegVideoDecoder(); - - virtual FramePtr Retrieve(const rational& timecode, const rational& length = 0); - -private: -}; - -#endif // FFMPEGVIDEODECODER_H diff --git a/decoders/frame.cpp b/decoders/frame.cpp deleted file mode 100644 index 6c470d695..000000000 --- a/decoders/frame.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "frame.h" - -Frame::Frame() : - frame_(nullptr) -{ -} - -Frame::Frame(AVFrame *f) : - frame_(f) -{ -} - -Frame::Frame(const Frame &f) : - frame_(nullptr) -{ -} - -Frame::Frame(Frame &&f) : - frame_(f.frame_) -{ - f.frame_ = nullptr; -} - -Frame &Frame::operator=(const Frame &f) -{ - frame_ = nullptr; - return *this; -} - -Frame &Frame::operator=(Frame &&f) -{ - if (&f != this) { - frame_ = f.frame_; - f.frame_ = nullptr; - } - - return *this; -} - -Frame::~Frame() -{ - FreeChild(); -} - -void Frame::SetAVFrame(AVFrame *f, AVRational timebase) -{ - FreeChild(); - - f = frame_; - timestamp_ = rational(timebase.num*f->pts, timebase.den); -} - -const int &Frame::width() -{ - return frame_->width; -} - -const int &Frame::height() -{ - return frame_->height; -} - -const rational &Frame::timestamp() -{ - return timestamp_; -} - -const int &Frame::format() -{ - return frame_->format; -} - -uint8_t **Frame::data() -{ - return frame_->data; -} - -int *Frame::linesize() -{ - return frame_->linesize; -} - -void Frame::FreeChild() -{ - if (frame_ != nullptr) { - av_frame_free(&frame_); - frame_ = nullptr; - } -} diff --git a/decoders/frame.h b/decoders/frame.h deleted file mode 100644 index 0a21d436e..000000000 --- a/decoders/frame.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef FRAME_H -#define FRAME_H - -#include - -#include "global/rational.h" - -/** - * @brief The Frame class - * - * Abstraction from AVFrame. Currently a simple AVFrame wrapper. - * - * This class does not support copying at this time. - */ -class Frame -{ -public: - // Normal constructor - Frame(); - - // AVFrame constructor - Frame(AVFrame* f); - - // Copy constructor - Frame(const Frame& f); - - // Move constructor - Frame(Frame&& f); - - // Copy assignment operator - Frame& operator=(const Frame& f); - - // Move assignment operator - Frame& operator=(Frame&& f); - - // Destructor - ~Frame(); - - /** - * @brief Set frame child - * - * This class currently primarily functions as a wrapper for AVFrame for use outside of the Decoder classes. - * The internal AVFrame is set here. This class will also take ownership of the AVFrame and automatically - * clear it when deconstructed. - * - * @param f - */ - void SetAVFrame(AVFrame* f, AVRational timebase); - - /** - * @brief Get frame's width in pixels - */ - const int& width(); - - /** - * @brief Get frame's height in pixels - */ - const int& height(); - - /** - * @brief Get frame's timestamp. - * - * This timestamp is always a rational that will equate to the time in seconds. - */ - const rational& timestamp(); - - /** - * @brief Get frame's format - * - * @return - * - * Currently this will either be an AVPixelFormat (video) or an AVSampleFormat (audio). - */ - const int& format(); - - /** - * @brief Get the data buffer of this frame - */ - uint8_t** data(); - - /** - * @brief Get the linesize information for this frame - */ - int* linesize(); - -private: - - void FreeChild(); - - AVFrame* frame_; - rational timestamp_; -}; - -using FramePtr = std::shared_ptr; - -#endif // FRAME_H diff --git a/decoders/pixelformatconverter.cpp b/decoders/pixelformatconverter.cpp deleted file mode 100644 index 5b2a28dc0..000000000 --- a/decoders/pixelformatconverter.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "pixelformatconverter.h" - -extern "C" { - #include - #include -} - -#include -#include - -PixelFormatConverter* olive::pix_fmt_conv; - -PixelFormatConverter::PixelFormatConverter() -{ - threads_.resize(qMax(1, QThread::idealThreadCount()-1)); - - for (int i=0;istart(QThread::HighPriority); - } -} - -PixelFormatConverter::~PixelFormatConverter() -{ - for (int i=0;iConvert(input_buffer, - input_linesize, - width, - line_start, - qMin(lines_per_thread, height - line_start), - input_fmt, - output_buffer, - output_fmt); - } - - // Wait for each thread to complete - for (int i=0;iWaitUntilComplete(); - } - - - mutex_.unlock(); - - delete [] converted_buffer; -} - -int PixelFormatConverter::GetBufferSize(olive::PixelFormat format, const int &width, const int &height) -{ - int rgba_channels = 4; - - switch (format) { - case olive::PIX_FMT_RGBA8: - return width * height * rgba_channels; - case olive::PIX_FMT_RGBA16: - case olive::PIX_FMT_RGBA16F: - return 2 * width * height * rgba_channels; - case olive::PIX_FMT_RGBA32F: - return 4 * width * height * rgba_channels; - default: - return 0; - } -} - -PixFmtConvertThread::PixFmtConvertThread() : - cancelled_(false) -{ -} - -void PixFmtConvertThread::run() -{ - mutex_.lock(); - - while (!cancelled_) { - wait_cond_.wait(&mutex_); - if (cancelled_) break; - - Process(); - } - - mutex_.unlock(); -} - -void PixFmtConvertThread::Convert(uint8_t **input_buffer, - int *input_linesize, - const int &width, - const int &line_start, - const int &line_count, - AVPixelFormat input_fmt, - void *output_buffer, - olive::PixelFormat output_fmt) -{ - mutex2_.lock(); - mutex_.lock(); - - input_buffer_ = input_buffer; - input_linesize_ = input_linesize; - width_ = width; - line_start_ = line_start; - line_count_ = line_count; - input_fmt_ = input_fmt; - output_buffer_ = output_buffer; - output_fmt_ = output_fmt; - - wait_cond_.wakeAll(); - - mutex_.unlock(); -} - -void PixFmtConvertThread::WaitUntilComplete() -{ - mutex2_.lock(); - mutex_.lock(); - mutex2_.unlock(); - mutex_.unlock(); -} - -void PixFmtConvertThread::Cancel() -{ - cancelled_ = true; - wait_cond_.wakeAll(); - wait(); -} - -void PixFmtConvertThread::Process() -{ - mutex2_.unlock(); - - switch (input_fmt_) { - case AV_PIX_FMT_RGBA: - { - int channels = 4; // FIXME RGBA magic number - - int byte_linesize = input_linesize_[0]*channels; - - int input_start = byte_linesize*line_start_; - int output_start = width_*channels*line_start_; - - for (int i=0;i(output_buffer_)[output_line_start+j] = input_buffer_[0][input_line_start+j] / 255.0f; - - } - } - break; - } - default: - qWarning() << "PixFmtConvertThread doesn't yet know how to convert pixel format" << input_fmt_; - } -} diff --git a/decoders/pixelformatconverter.h b/decoders/pixelformatconverter.h deleted file mode 100644 index 5957ef942..000000000 --- a/decoders/pixelformatconverter.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef PIXELFORMATCONVERTER_H -#define PIXELFORMATCONVERTER_H - -extern "C" { -#include -} - -#include -#include -#include - -#include "rendering/pixelformats.h" - -class PixFmtConvertThread : public QThread { -public: - PixFmtConvertThread(); - - virtual void run() override; - - void Convert(uint8_t** input_buffer, - int* input_linesize, - const int &width, - const int &line_start, - const int &line_count, - AVPixelFormat input_fmt, - void* output_buffer, - olive::PixelFormat output_fmt); - - void WaitUntilComplete(); - - void Cancel(); - -private: - // Main processing function - void Process(); - - // Threading variables - QWaitCondition wait_cond_; - QMutex mutex_; - QMutex mutex2_; - bool cancelled_; - - // Input variables for conversion - uint8_t** input_buffer_; - int* input_linesize_; - int width_; - int line_start_; - int line_count_; - AVPixelFormat input_fmt_; - - // Output variables for conversion - void* output_buffer_; - olive::PixelFormat output_fmt_; -}; - -/** - * @brief The PixelFormatConverter class - * - * A background process for optimized conversion of frames to Olive's internal pipeline format. It is designed as a - * replacement of FFmpeg's swscale for all pixel format conversions. It's main advantages over swscale are: - * - * * Support for floating-point pixel formats - * * Better control over the conversion from YCbCr to RGB - * * Multithreaded by design - * - * In the old system, frame pixel formats were converted twice - once to RGBA32 or RGBA64 by swscale, then a second - * time to RGBA16F or RGBA32F by OpenGL. In addition to the aforementioned advantages, a future goal of this class is to - * reduce those two steps to one. - */ -class PixelFormatConverter -{ -public: - PixelFormatConverter(); - - ~PixelFormatConverter(); - - /** - * @brief Converts data from FFmpeg (or equivalent data) to data ready for Olive's buffer - * - * @param input_buffer - * - * The buffer of data to convert. This can be fed AVFrame->data directly. - * - * @param input_linesize - * - * The linesize of the data to convert. This can be fed AVFrame->linesize directly. - * - * @param width - * - * Width of the frame. This will be the same in the output buffer. - * - * @param height - * - * Height of the frame. This will be the same in the output buffer. - * - * @param input_fmt - * - * Expects a value from the AVPixelFormat enum. - * - * @param output_buffer - * - * The buffer to place the converted data. This function does NOT allocate data, this must be done beforehand. - * The helper function GetBufferSize() can be used to determine the minimum size (in bytes) that this buffer - * needs to have allocated for this function to be successful. - * - * @param output_fmt - * - * The format to convert to. Must be a member of the olive::PixelFormat enum. - */ - void AVFrameToPipeline(uint8_t** input_buffer, - int* input_linesize, - const int &width, - const int &height, - AVPixelFormat input_fmt, - void* output_buffer, - olive::PixelFormat output_fmt); - - /** - * @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height. - * - * @param format - * - * The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum. - * - * @param width - * - * The width (in pixels) of the buffer. - * - * @param height - * - * The height (in pixels) of the buffer. - */ - static int GetBufferSize(olive::PixelFormat format, const int& width, const int& height); - -private: - QMutex mutex_; - QVector threads_; -}; - -namespace olive { -extern PixelFormatConverter* pix_fmt_conv; -} - -#endif // PIXELFORMATCONVERTER_H diff --git a/dialogs/aboutdialog.cpp b/dialogs/aboutdialog.cpp deleted file mode 100644 index 9501e1483..000000000 --- a/dialogs/aboutdialog.cpp +++ /dev/null @@ -1,66 +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 "aboutdialog.h" - -#include -#include -#include - -#include "global/global.h" - -AboutDialog::AboutDialog(QWidget *parent) : - QDialog(parent) -{ - setWindowTitle("About Olive"); - - QVBoxLayout* layout = new QVBoxLayout(this); - layout->setSpacing(20); - - // Construct About text - QLabel* label = - new QLabel(QString("" - "

" - "

" - "" - "https://www.olivevideoeditor.org/" - "

" - "

%1

" // AppName (version identifier) - "

%2

" // First statement - "

%3

" // Second statement - "").arg(olive::AppName, - tr("Olive is a non-linear video editor. This software is free and " - "protected by the GNU GPL."), - tr("Olive Team is obliged to inform users that Olive source code is " - "available for download from its website.")), this); - - // Set text formatting - label->setAlignment(Qt::AlignCenter); - label->setTextInteractionFlags(Qt::TextSelectableByMouse); - label->setCursor(Qt::IBeamCursor); - label->setWordWrap(true); - layout->addWidget(label); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this); - buttons->setCenterButtons(true); - layout->addWidget(buttons); - - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); -} diff --git a/dialogs/aboutdialog.h b/dialogs/aboutdialog.h deleted file mode 100644 index ae7e22b7c..000000000 --- a/dialogs/aboutdialog.h +++ /dev/null @@ -1,48 +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 ABOUTDIALOG_H -#define ABOUTDIALOG_H - -#include - -/** - * @brief The AboutDialog class - * - * The About dialog (accessible through Help > About). Contains license and version information. This can be run from - * anywhere - */ -class AboutDialog : public QDialog -{ - Q_OBJECT -public: - /** - * @brief AboutDialog Constructor - * - * Creates About dialog. - * - * @param parent - * - * QWidget parent object. Usually this will be MainWindow. - */ - explicit AboutDialog(QWidget *parent = nullptr); -}; - -#endif // ABOUTDIALOG_H diff --git a/dialogs/actionsearch.cpp b/dialogs/actionsearch.cpp deleted file mode 100644 index 75515278f..000000000 --- a/dialogs/actionsearch.cpp +++ /dev/null @@ -1,244 +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 "actionsearch.h" - -#include -#include -#include -#include - -#include "ui/mainwindow.h" - -ActionSearch::ActionSearch(QWidget *parent) : - QDialog(parent) -{ - // ActionSearch requires a parent widget - Q_ASSERT(parent != nullptr); - - // Set styling (object name is required for CSS specific to this object) - setObjectName("ASDiag"); - setStyleSheet("#ASDiag{border: 2px solid #808080;}"); - - // Size proportionally to the parent (usually MainWindow). - resize(parent->width()/3, parent->height()/3); - - // Show dialog as a "popup", which will make the dialog close if the user clicks out of it. - setWindowFlags(Qt::Popup); - - QVBoxLayout* layout = new QVBoxLayout(this); - - // Construct the main entry text field. - ActionSearchEntry* entry_field = new ActionSearchEntry(this); - - // Set the main entry field font size to 1.2x its standard font size. - QFont entry_field_font = entry_field->font(); - entry_field_font.setPointSize(qRound(entry_field_font.pointSize()*1.2)); - entry_field->setFont(entry_field_font); - - // Set placeholder text for the main entry field - entry_field->setPlaceholderText(tr("Search for action...")); - - // Connect signals/slots - connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &))); - connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action())); - - // moveSelectionUp() and moveSelectionDown() are emitted when the user pressed up or down on the text field. - // We override it here to select the upper or lower item in the list. - connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up())); - connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down())); - layout->addWidget(entry_field); - - // Construct list of actions - list_widget = new ActionSearchList(this); - - // Set list's font to 1.2x its standard font size - QFont list_widget_font = list_widget->font(); - list_widget_font.setPointSize(qRound(list_widget_font.pointSize()*1.2)); - list_widget->setFont(list_widget_font); - - layout->addWidget(list_widget); - - connect(list_widget, SIGNAL(dbl_click()), this, SLOT(perform_action())); - - // Instantly focus on the entry field to allow for fully keyboard operation (if this popup was initiated by keyboard - // shortcut for example). - entry_field->setFocus(); -} - -void ActionSearch::search_update(const QString &s, const QString &p, QMenu *parent) { - - // This function is recursive, using the `parent` parameter to loop through a menu's items. It functions in two - // modes - the parent being NULL, meaning it'll get MainWindow's menubar and loop over its menus, and the parent - // referring to a menu at which point it'll loop over its actions (and call itself recursively if it finds any - // submenus). - - if (parent == nullptr) { - - // If parent is NULL, we'll pull from the MainWindow's menubar and call this recursively on all of its submenus - // (and their submenus). - - // We'll clear all the current items in the list since if we're here, we're just starting. - list_widget->clear(); - - QList menus = olive::MainWindow->menuBar()->actions(); - - // Loop through all menus from the menubar and run this function on each one. - for (int i=0;imenu(); - - search_update(s, p, menu); - } - - // Once we're here, all the recursion/item retrieval is complete. We auto-select the first item for better - // keyboard-exclusive functionality. - if (list_widget->count() > 0) { - list_widget->item(0)->setSelected(true); - } - - } else { - - // Parent was not NULL, so we loop over the actions in the menu we were given in `parent`. - - // The list shows a '>' delimited hierarchy of the menus in which this action came from. We construct it here by - // adding the current menu's text to the existing hierarchy (passed in `p`). - QString menu_text; - if (!p.isEmpty()) menu_text += p + " > "; - menu_text += parent->title().replace("&", ""); // Strip out any &s used in menu action names - - // Loop over the menu's actions - QList actions = parent->actions(); - for (int i=0;iisSeparator()) { - - if (a->menu() != nullptr) { - - // If the action is a menu, run this function recursively on it - search_update(s, menu_text, a->menu()); - - } else { - - // This is a valid non-separator non-menu action, so check it against the currently entered string. - - // Strip out all &s from the action's name - QString comp = a->text().replace("&", ""); - - // See if the action's name contains any of the currently entered string - if (comp.contains(s, Qt::CaseInsensitive)) { - - // If so, we add it to the list widget. - QListWidgetItem* item = new QListWidgetItem(QString("%1\n(%2)").arg(comp, menu_text), list_widget); - - // Add a pointer to the original QAction in the item's data - item->setData(Qt::UserRole+1, reinterpret_cast(a)); - - list_widget->addItem(item); - - } - - } - } - } - } -} - -void ActionSearch::perform_action() { - - // Loop over all the items in the list and if we find one that's selected, we trigger it. - QList selected_items = list_widget->selectedItems(); - if (list_widget->count() > 0 && selected_items.size() > 0) { - - QListWidgetItem* item = selected_items.at(0); - - // Get QAction pointer from item's data - QAction* a = reinterpret_cast(item->data(Qt::UserRole+1).value()); - - a->trigger(); - - } - - // Close this popup - accept(); - -} - -void ActionSearch::move_selection_up() { - - // Here we loop over all the items to find the currently selected one, and then select the one above it. We start - // iterating at 1 (instead of 0) to efficiently ignore the first item (since the selection can't go below the very - // bottom item). - - int lim = list_widget->count(); - for (int i=1;iitem(i)->isSelected()) { - list_widget->item(i-1)->setSelected(true); - list_widget->scrollToItem(list_widget->item(i-1)); - break; - } - } -} - -void ActionSearch::move_selection_down() { - - // Here we loop over all the items to find the currently selected one, and then select the one below it. We limit it - // one entry before count() to efficiently ignore the item at the end (since the selection can't go below the very - // bottom item). - - int lim = list_widget->count()-1; - for (int i=0;iitem(i)->isSelected()) { - list_widget->item(i+1)->setSelected(true); - list_widget->scrollToItem(list_widget->item(i+1)); - break; - } - } -} - -ActionSearchEntry::ActionSearchEntry(QWidget *parent) : QLineEdit(parent) {} - -void ActionSearchEntry::keyPressEvent(QKeyEvent * event) { - - // Listen for up/down, otherwise pass the key event to the base class. - - switch (event->key()) { - case Qt::Key_Up: - emit moveSelectionUp(); - break; - case Qt::Key_Down: - emit moveSelectionDown(); - break; - default: - QLineEdit::keyPressEvent(event); - } - -} - -ActionSearchList::ActionSearchList(QWidget *parent) : QListWidget(parent) {} - -void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) { - - // Indiscriminately emit a signal on any double click - emit dbl_click(); - -} diff --git a/dialogs/actionsearch.h b/dialogs/actionsearch.h deleted file mode 100644 index bf3457432..000000000 --- a/dialogs/actionsearch.h +++ /dev/null @@ -1,170 +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 ACTIONSEARCH_H -#define ACTIONSEARCH_H - -#include -#include -#include -#include - -class ActionSearchList; - -/** - * @brief The ActionSearch class - * - * A popup window (accessible through Help > Action Search) that allows users to search for a menu command by typing - * rather than browsing through the menu bar. This can be created from anywhere provided olive::MainWindow is valid. - */ -class ActionSearch : public QDialog -{ - Q_OBJECT -public: - /** - * @brief ActionSearch Constructor - * - * Create ActionSearch popup. - * - * @param parent - * - * QWidget parent. Usually MainWindow. - */ - ActionSearch(QWidget* parent); -private slots: - /** - * @brief Update the list of actions according to a search query - * - * This function adds/removes actions in the action list according to a given search query entered by the user. - * - * To loop over the menubar and all of its menus and submenus, this function will call itself recursively. As such - * some of its parameters do not need to be set externally, as these will be set by the function itself as it calls - * itself. - * - * @param s - * - * The search text. This is the only parameter that should be set externally. - * - * @param p - * - * The current parent hierarchy. In most cases, this should be left as nullptr when called externally. - * search_update() will fill this automatically as it needs while calling itself recursively. - * - * @param parent - * - * The current menu to loop over. In most cases, this should be left as nullptr when called externally. - * search_update() will fill this automatically as it needs while calling itself recursively. - */ - void search_update(const QString& s, const QString &p = nullptr, QMenu *parent = nullptr); - - /** - * @brief Perform the currently selected action - * - * Usually triggered by pressing Enter on the ActionSearchEntry field, this will trigger whatever action is currently - * highlighted and then close this popup. If no entries are highlighted (i.e. the list is empty), no action is - * triggered and the popup closes anyway. - */ - void perform_action(); - - /** - * @brief Move selection up - * - * A slot for pressing up on the ActionSearchEntry field. Moves the selection in the list up once. If the - * selection is already at the top of the list, this is a no-op. - */ - void move_selection_up(); - - /** - * @brief Move selection down - * - * A slot for pressing down on the ActionSearchEntry field. Moves the selection in the list down once. If the - * selection is already at the bottom of the list, this is a no-op. - */ - void move_selection_down(); -private: - /** - * @brief Main widget that shows the list of commands - */ - ActionSearchList* list_widget; -}; - -/** - * @brief The ActionSearchList class - * - * Simple wrapper around QListWidget that emits a signal when an item is double clicked that ActionSearch connects - * to a slot that triggers the currently selected action. - */ -class ActionSearchList : public QListWidget { - Q_OBJECT -public: - /** - * @brief ActionSearchList Constructor - * @param parent - * - * Usually ActionSearch. - */ - ActionSearchList(QWidget* parent); -protected: - /** - * @brief Override of QListWidget's double click event that emits a signal. - */ - void mouseDoubleClickEvent(QMouseEvent *); -signals: - /** - * @brief Signal emitted when a QListWidget item is double clicked. - */ - void dbl_click(); -}; - -/** - * @brief The ActionSearchEntry class - * - * Simple wrapper around QLineEdit that emits signals when the up or down arrow keys are pressed so that ActionSearch - * can connect them to moving the current selection up or down. - */ -class ActionSearchEntry : public QLineEdit { - Q_OBJECT -public: - /** - * @brief ActionSearchEntry - * @param parent - * - * Usually ActionSearch. - */ - ActionSearchEntry(QWidget* parent); -protected: - /** - * @brief Override of QLineEdit's key press event that listens for up/down key presses. - * @param event - */ - void keyPressEvent(QKeyEvent * event); -signals: - /** - * @brief Emitted when the user presses the up arrow key. - */ - void moveSelectionUp(); - - /** - * @brief Emitted when the user presses the down arrow key. - */ - void moveSelectionDown(); -}; - -#endif // ACTIONSEARCH_H diff --git a/dialogs/advancedvideodialog.cpp b/dialogs/advancedvideodialog.cpp deleted file mode 100644 index 1119a3832..000000000 --- a/dialogs/advancedvideodialog.cpp +++ /dev/null @@ -1,107 +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 "advancedvideodialog.h" - -#include -#include -#include -#include - -#include - -extern "C" { -#include -#include -} - -AdvancedVideoDialog::AdvancedVideoDialog(QWidget *parent, - AVCodecID encoding_codec, - VideoCodecParams &iparams) : - QDialog(parent), - params_(iparams) -{ - setWindowTitle(tr("Advanced Video Settings")); - - // use variable for row to assist adding new fields to the grid layout - int row = 0; - - // get encoder information for this codec from FFmpeg - AVCodec* codec_info = avcodec_find_encoder(static_cast(encoding_codec)); - - // set up grid layout for dialog - QGridLayout* layout = new QGridLayout(this); - - // create row for codec pixel formats - layout->addWidget(new QLabel(tr("Pixel Format:")), row, 0); - pix_fmt_combo_ = new QComboBox(); - - // loop through available pixel formats for this codec - int pix_fmt_index = 0; - while (codec_info->pix_fmts[pix_fmt_index] != -1) { // AVCodec->pix_fmts is terminated by "-1" - - // get the name of the pixel format and add it to the combobox (with the pixel format constant) - pix_fmt_combo_->addItem(av_get_pix_fmt_name(codec_info->pix_fmts[pix_fmt_index]), - codec_info->pix_fmts[pix_fmt_index]); - - // if the user has already selected a pixel format, set the combobox to it as well - if (codec_info->pix_fmts[pix_fmt_index] == params_.pix_fmt) { - pix_fmt_combo_->setCurrentIndex(pix_fmt_combo_->count()-1); - } - - pix_fmt_index++; - } - - layout->addWidget(pix_fmt_combo_, row, 1); - - row++; - - // create row for multithreading thread count - layout->addWidget(new QLabel(tr("Threads:")), row, 0); - - thread_spinbox_ = new QSpinBox(); - - // with the thread count, "0" is considered automatics - thread_spinbox_->setMinimum(0); - thread_spinbox_->setSpecialValueText("Auto"); - - // load current thread value - thread_spinbox_->setValue(params_.threads); - - layout->addWidget(thread_spinbox_); - - row++; - - // buttons - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - buttons->setCenterButtons(true); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); - layout->addWidget(buttons, row, 0, 1, 2); -} - -void AdvancedVideoDialog::accept() { - // store settings back into struct - - params_.pix_fmt = pix_fmt_combo_->currentData().toInt(); - params_.threads = thread_spinbox_->value(); - - QDialog::accept(); -} diff --git a/dialogs/advancedvideodialog.h b/dialogs/advancedvideodialog.h deleted file mode 100644 index 4ac09cae0..000000000 --- a/dialogs/advancedvideodialog.h +++ /dev/null @@ -1,80 +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 ADVANCEDVIDEODIALOG_H -#define ADVANCEDVIDEODIALOG_H - -#include -#include -#include - -#include "rendering/exportthread.h" - -/** - * @brief The AdvancedVideoDialog class - * - * A dialog for interfacing with VideoCodecParams, a struct for more advanced video settings sometimes specific to - * one codec. Primarily a companion to ExportDialog which will provide the VideoCodecParams reference, - */ -class AdvancedVideoDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief AdvancedVideoDialog Constructor - * - * @param parent - * - * QWidget parent. Usually ExportDialog. - * - * @param encoding_codec - * - * The AVCodecID of the selected export codec. - * - * @param iparams - * - * A VideoCodecParams struct containing the extra codec data. - */ - AdvancedVideoDialog(QWidget* parent, - AVCodecID encoding_codec, - VideoCodecParams& iparams); - -public slots: - /** - * @brief Overridden accept for saving the UI data into the provided VideoCodecParams struct. - */ - virtual void accept() override; -private: - /** - * @brief Internal reference to VideoCodecParams struct provided by ExportDialog. - */ - VideoCodecParams& params_; - - /** - * @brief ComboBox to show available pixel formats for this codec - */ - QComboBox* pix_fmt_combo_; - - /** - * @brief SpinBox for multithreading settings - */ - QSpinBox* thread_spinbox_; -}; - -#endif // ADVANCEDVIDEODIALOG_H diff --git a/dialogs/autocutsilencedialog.cpp b/dialogs/autocutsilencedialog.cpp deleted file mode 100644 index e5176bcb2..000000000 --- a/dialogs/autocutsilencedialog.cpp +++ /dev/null @@ -1,215 +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 "autocutsilencedialog.h" - -#include -#include -#include -#include -#include - -#include "timeline/sequence.h" -#include "rendering/renderfunctions.h" -#include "panels/panels.h" -#include "panels/timeline.h" - -AutoCutSilenceDialog::AutoCutSilenceDialog(QWidget *parent, QVector clips) : - QDialog(parent), - clips_(clips) -{ - setWindowTitle(tr("Cut Silence")); - - 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())); - -} - -int AutoCutSilenceDialog::exec() -{ - 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); - - return QDialog::exec(); -} - -void AutoCutSilenceDialog::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 AutoCutSilenceDialog::cut_silence() { - ComboAction* ca = new ComboAction(); - - // Loop over clips provided to this dialog - for (int j=0;jtype() == olive::kTypeAudio - && clip->media() != nullptr - && clip->media_stream()->preview_done) { // TODO provide warning for preview not being done - - QVector split_positions; - - long 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; - - QVector vols; - vols.resize(sample_size); - vols.fill(0); - - // loop through the entire sequence - for (long i=clip_start;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){ - split_positions.append(i-cut_idx); - attack = true; - release = false; - //qInfo() << "\n\n Current vol: "<= current_release_time){ // must be <= sample_size - attack = false; - release = true; - split_positions.append(i); - //qInfo() << "\n\n Current vol: "<track()->sequence()->SplitClipAtPositions(ca, clips_.at(j), split_positions); - } - - } - - if (ca->hasActions()) { - olive::undo_stack.push(ca); - } else { - delete ca; - } -} diff --git a/dialogs/autocutsilencedialog.h b/dialogs/autocutsilencedialog.h deleted file mode 100644 index 37fe57a61..000000000 --- a/dialogs/autocutsilencedialog.h +++ /dev/null @@ -1,59 +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 SILENCEDIALOG_H -#define SILENCEDIALOG_H - -#include -#include - -#include "timeline/clip.h" -#include "ui/labelslider.h" - -class AutoCutSilenceDialog : public QDialog -{ - Q_OBJECT -public: - AutoCutSilenceDialog(QWidget* parent, QVector clips); -public slots: - virtual int exec() override; -private slots: - virtual void accept() override; -private: - void cut_silence(); - - 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/dialogs/clippropertiesdialog.cpp b/dialogs/clippropertiesdialog.cpp deleted file mode 100644 index 05028f346..000000000 --- a/dialogs/clippropertiesdialog.cpp +++ /dev/null @@ -1,145 +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 "clippropertiesdialog.h" - -#include -#include -#include - -#include "panels/panels.h" -#include "undo/undo.h" - -ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clips) : - QDialog(parent) -{ - setWindowTitle((clips.size() == 1) ? - tr("\"%1\" Properties").arg(clips.at(0)->name()) : - tr("Multiple Clip Properties")); - - clips_ = clips; - - QGridLayout* layout = new QGridLayout(this); - - int row = 0; - - // Clip Name field - layout->addWidget(new QLabel(tr("Name:")), row, 0); - - clip_name_field_ = new QLineEdit(); - - layout->addWidget(clip_name_field_, row, 1); - - row++; - - // Clip Duration field - layout->addWidget(new QLabel(tr("Duration:")), row, 0); - - duration_field_ = new LabelSlider(); - duration_field_->SetDisplayType(LabelSlider::FrameNumber); - duration_field_->SetMinimum(1); - layout->addWidget(duration_field_, row, 1); - - row++; - - // Dialog buttons (OK and Cancel) - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - buttons->setCenterButtons(true); - layout->addWidget(buttons, row, 0, 1, 2); - - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); - - // analyze list of clips for default values - - bool all_clips_have_same_name = true; - bool all_clips_have_same_duration = true; - - for (int i=1;iname() != clips.at(i)->name()) { - all_clips_have_same_name = false; - } - if (clips.at(i-1)->length() != clips.at(i)->length()) { - all_clips_have_same_duration = false; - } - } - - Clip* first_clip = clips_.first(); - - if (all_clips_have_same_name) { - // if there's only one clip selected, set all defaults to that clip's properties - clip_name_field_->setText(first_clip->name()); - } else { - // if there are multiple clips, use different properties - clip_name_field_->setPlaceholderText(tr("(multiple)")); - } - - // it's assumed all the clips come from the same sequence - duration_field_->SetFrameRate(first_clip->track()->sequence()->frame_rate()); - - if (all_clips_have_same_duration) { - duration_field_->SetDefault(first_clip->length()); - duration_field_->SetValue(first_clip->length()); - duration_field_->SetMaximum(first_clip->media_length()); - } else { - duration_field_->SetDefault(qSNaN()); - duration_field_->SetValue(qSNaN()); - } -} - -void ClipPropertiesDialog::accept() -{ - const QString& clip_name = clip_name_field_->text(); - double clip_duration = duration_field_->value(); - - ComboAction* ca = new ComboAction(); - - for (int i=0;iname()) { - ca->append(new RenameClipCommand(clip, clip_name)); - } - - // If the user entered a clip duration (and the duration has changed), create a "clip move" command - if (!qIsNaN(clip_duration)) { - long clip_duration_rounded = qRound(clip_duration); - - if (clip->length() != clip_duration_rounded) { - clip->Move(ca, - clip->timeline_in(), - clip->timeline_in() + clip_duration_rounded, - clip->clip_in(), - clip->track()); - } - - } - } - - if (ca->hasActions()) { - olive::undo_stack.push(ca); - update_ui(false); - } else { - delete ca; - } - - QDialog::accept(); -} diff --git a/dialogs/clippropertiesdialog.h b/dialogs/clippropertiesdialog.h deleted file mode 100644 index e6716162d..000000000 --- a/dialogs/clippropertiesdialog.h +++ /dev/null @@ -1,72 +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 CLIPPROPERTIESDIALOG_H -#define CLIPPROPERTIESDIALOG_H - -#include -#include - -#include "timeline/clip.h" -#include "ui/labelslider.h" - -/** - * @brief The ClipPropertiesDialog class - * - * A dialog for setting Clip properties, accessible by right clicking a Clip and clicking "Properties". This can be - * run from anywhere provided it's given a valid array of Clip objects. - */ -class ClipPropertiesDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief ClipPropertiesDialog Constructor - * @param parent - * - * Parent widget. - * - * @param clips - * - * Array of Clip objects to set the properties of. - */ - ClipPropertiesDialog(QWidget* parent, QVector clips); -protected: - /** - * @brief Accept override. Saves the current properties to the array of Clips. - */ - virtual void accept() override; -private: - /** - * @brief Internal clip array (set in the constructor) - */ - QVector clips_; - - /** - * @brief Widget for setting the Clip names - */ - QLineEdit* clip_name_field_; - - /** - * @brief Widget for setting the Clip durations - */ - LabelSlider* duration_field_; -}; - -#endif // CLIPPROPERTIESDIALOG_H diff --git a/dialogs/crashdialog.cpp b/dialogs/crashdialog.cpp deleted file mode 100644 index 6d31537f3..000000000 --- a/dialogs/crashdialog.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "crashdialog.h" - -#include -#include -#include -#include - -CrashDialog* olive::crash_dialog; - -CrashDialog::CrashDialog() -{ - resize(480, 640); - - QVBoxLayout* layout = new QVBoxLayout(this); - - layout->addWidget(new QLabel(tr("We're very sorry, Olive has crashed. " - "Please send the following data to developers:"))); - - text_edit = new QTextEdit(); - text_edit->setReadOnly(true); - layout->addWidget(text_edit); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok); - buttons->setCenterButtons(true); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - layout->addWidget(buttons); - - // Set some default data for the crash report so we do as little as possible when we actually crash -#ifdef GITHASH - text_edit->append(QString("Version: %1").arg(GITHASH)); -#else - text_edit->append(QString("Version: (unknown)")); -#endif - text_edit->append(QString("Operating System: %1 %2").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture())); - text_edit->append(QString("Build ABI: %1").arg(QSysInfo::buildAbi())); - text_edit->append(QString()); -} - -void CrashDialog::SetData(int signal, const QStringList& strings) -{ - text_edit->append(QString("Signal: %1").arg(signal)); - text_edit->append(QString()); - for (int i=0;iappend(strings.at(i)); - } -} diff --git a/dialogs/crashdialog.h b/dialogs/crashdialog.h deleted file mode 100644 index 23133f7c3..000000000 --- a/dialogs/crashdialog.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CRASHDIALOG_H -#define CRASHDIALOG_H - -#include -#include - -class CrashDialog : public QDialog -{ -public: - CrashDialog(); - - void SetData(int signal, const QStringList &strings); - -private: - QTextEdit* text_edit; -}; - -namespace olive { - extern CrashDialog* crash_dialog; -} - -#endif // CRASHDIALOG_H diff --git a/dialogs/debugdialog.cpp b/dialogs/debugdialog.cpp deleted file mode 100644 index 64aab959e..000000000 --- a/dialogs/debugdialog.cpp +++ /dev/null @@ -1,63 +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 "debugdialog.h" - -#include -#include -#include -#include - -#include "global/debug.h" - -DebugDialog* olive::DebugDialog = nullptr; - -DebugDialog::DebugDialog(QWidget *parent) : QDialog(parent) { - QVBoxLayout* layout = new QVBoxLayout(this); - - textEdit = new QTextEdit(this); - textEdit->setWordWrapMode(QTextOption::NoWrap); - layout->addWidget(textEdit); - - Retranslate(); -} - -void DebugDialog::Retranslate() -{ - setWindowTitle(tr("Debug Log")); -} - -void DebugDialog::update_log() { - textEdit->setHtml(get_debug_str()); - textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum()); -} - -void DebugDialog::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } else { - QDialog::changeEvent(e); - } -} - -void DebugDialog::showEvent(QShowEvent *) { - update_log(); -} diff --git a/dialogs/debugdialog.h b/dialogs/debugdialog.h deleted file mode 100644 index 229e1bd90..000000000 --- a/dialogs/debugdialog.h +++ /dev/null @@ -1,79 +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 DEBUGDIALOG_H -#define DEBUGDIALOG_H - -#include -#include - -/** - * @brief The DebugDialog class - * - * A dialog to display the current debug output. This dialog is omnipresent and shown and hidden when the user wants - * to see it. For efficiency, it will not update if it's hidden. - */ -class DebugDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief DebugDialog Constructor - * @param parent - * - * Parent widget. Usually MainWindow. - */ - DebugDialog(QWidget* parent = nullptr); - - /** - * @brief Retranslate window title - * - * Sets title based on the current translation. - */ - void Retranslate(); -public slots: - /** - * @brief Update the visual log with the debug text from get_debug_str() - */ - void update_log(); -protected: - /** - * @brief Overrides change event to trigger Retranslate() on a LanguageChange event. - */ - virtual void changeEvent(QEvent* e) override; - /** - * @brief Overrides show event to trigger an update of the visual log (the visual log does not update while the - * debug dialog is hidden). - */ - virtual void showEvent(QShowEvent* event) override; -private: - /** - * @brief Display widget for the debug dialog. - */ - QTextEdit* textEdit; -}; - -namespace olive { -/** - * @brief Omnipresent instance of DebugDialog to be shown or hidden as the user wants - */ -extern DebugDialog* DebugDialog; -} - -#endif // DEBUGDIALOG_H diff --git a/dialogs/demonotice.cpp b/dialogs/demonotice.cpp deleted file mode 100644 index 2289cfe41..000000000 --- a/dialogs/demonotice.cpp +++ /dev/null @@ -1,62 +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 "demonotice.h" - -#include -#include -#include - -DemoNotice::DemoNotice(QWidget *parent) : - QDialog(parent) -{ - setWindowTitle(tr("Welcome to Olive!")); - - QVBoxLayout* vlayout = new QVBoxLayout(this); - - QHBoxLayout* layout = new QHBoxLayout(); - layout->setMargin(10); - layout->setSpacing(20); - - QLabel* icon = new QLabel("" - "

" - "", this); - layout->addWidget(icon); - - QLabel* text = new QLabel("

" - "" - + tr("Welcome to Olive!") - + "

" - + tr("Olive is a free open-source video editor released under the GNU GPL. If you have paid for this software, you have been scammed.") - + "

" - + tr("This software is currently in ALPHA which means it is unstable and very likely to crash, have bugs, and have missing features. We offer no warranty so use at your own risk. Please report any bugs or feature requests at %1").arg("www.olivevideoeditor.org") - + "

" - + tr("Thank you for trying Olive and we hope you enjoy it!") - + "

", this); - text->setWordWrap(true); - layout->addWidget(text); - - vlayout->addLayout(layout); - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this); - buttons->setCenterButtons(true); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - vlayout->addWidget(buttons); -} diff --git a/dialogs/demonotice.h b/dialogs/demonotice.h deleted file mode 100644 index a716da84c..000000000 --- a/dialogs/demonotice.h +++ /dev/null @@ -1,47 +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 DEMONOTICE_H -#define DEMONOTICE_H - -#include - -/** - * @brief The DemoNotice class - * - * Simple dialog shown on startup to introduce Olive as alpha software (in release builds). Can be run from anywhere, - * but there should be no reason to create it outside of the application launch. - * - * To be phased out as Olive gains maturity. - */ -class DemoNotice : public QDialog -{ - Q_OBJECT -public: - /** - * @brief DemoNotice Constructor - * @param parent - * - * QWidget parent. Usually MainWindow. - */ - explicit DemoNotice(QWidget *parent = nullptr); -}; - -#endif // DEMONOTICE_H diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp deleted file mode 100644 index afd8b9321..000000000 --- a/dialogs/exportdialog.cpp +++ /dev/null @@ -1,807 +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 "exportdialog.h" - -extern "C" { -#include -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "dialogs/advancedvideodialog.h" -#include "panels/panels.h" -#include "ui/viewerwidget.h" -#include "rendering/renderfunctions.h" -#include "rendering/audio.h" -#include "rendering/exportthread.h" -#include "ui/mainwindow.h" - -enum ExportFormats { - FORMAT_3GPP, - FORMAT_AIFF, - FORMAT_APNG, - FORMAT_AVI, - FORMAT_DNXHD, - FORMAT_AC3, - FORMAT_FLV, - FORMAT_GIF, - FORMAT_IMG, - FORMAT_MP2, - FORMAT_MP3, - FORMAT_MPEG1, - FORMAT_MPEG2, - FORMAT_MPEG4, - FORMAT_MPEGTS, - FORMAT_MKV, - FORMAT_OGG, - FORMAT_MOV, - FORMAT_WAV, - FORMAT_WEBM, - FORMAT_WMV, - FORMAT_SIZE -}; - -ExportDialog::ExportDialog(QWidget *parent, Sequence* sequence) : - QDialog(parent), - sequence_(sequence) -{ - setWindowTitle(tr("Export \"%1\"").arg(sequence->name())); - setup_ui(); - - rangeCombobox->setCurrentIndex(0); - if (sequence->using_workarea) { - rangeCombobox->setEnabled(true); - rangeCombobox->setCurrentIndex(1); - } - - format_strings.resize(FORMAT_SIZE); - format_strings[FORMAT_3GPP] = "3GPP"; - format_strings[FORMAT_AIFF] = "AIFF"; - format_strings[FORMAT_APNG] = "Animated PNG"; - format_strings[FORMAT_AVI] = "AVI"; - format_strings[FORMAT_DNXHD] = "DNxHD"; - format_strings[FORMAT_AC3] = "Dolby Digital (AC3)"; - format_strings[FORMAT_FLV] = "FLV"; - format_strings[FORMAT_GIF] = "GIF"; - format_strings[FORMAT_IMG] = "Image Sequence"; - format_strings[FORMAT_MP2] = "MP2 Audio"; - format_strings[FORMAT_MP3] = "MP3 Audio"; - format_strings[FORMAT_MPEG1] = "MPEG-1 Video"; - format_strings[FORMAT_MPEG2] = "MPEG-2 Video"; - format_strings[FORMAT_MPEG4] = "MPEG-4 Video"; - format_strings[FORMAT_MPEGTS] = "MPEG-TS"; - format_strings[FORMAT_MKV] = "Matroska MKV"; - format_strings[FORMAT_OGG] = "Ogg"; - format_strings[FORMAT_MOV] = "QuickTime MOV"; - format_strings[FORMAT_WAV] = "WAVE Audio"; - format_strings[FORMAT_WEBM] = "WebM"; - format_strings[FORMAT_WMV] = "Windows Media"; - - for (int i=0;iaddItem(format_strings[i]); - } - formatCombobox->setCurrentIndex(FORMAT_MPEG4); - - // default to sequence's native dimensions - widthSpinbox->setValue(sequence->width()); - heightSpinbox->setValue(sequence->height()); - samplingRateSpinbox->setValue(sequence->audio_frequency()); - framerateSpinbox->setValue(sequence->frame_rate()); - - // set some advanced defaults - vcodec_params.threads = 0; -} - -void ExportDialog::add_codec_to_combobox(QComboBox* box, enum AVCodecID codec) { - QString codec_name; - - AVCodec* codec_info = avcodec_find_encoder(codec); - - if (codec_info == nullptr) { - codec_name = tr("Unknown codec name %1").arg(static_cast(codec)); - } else { - codec_name = codec_info->long_name; - } - - box->addItem(codec_name, codec); -} - -void ExportDialog::format_changed(int index) { - vcodecCombobox->clear(); - acodecCombobox->clear(); - - int default_vcodec = 0; - int default_acodec = 0; - - switch (index) { - case FORMAT_3GPP: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG4); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H264); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H265); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AAC); - - default_vcodec = 1; - break; - case FORMAT_AIFF: - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - break; - case FORMAT_APNG: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_APNG); - break; - case FORMAT_AVI: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H264); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG4); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MJPEG); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MSVIDEO1); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_RAWVIDEO); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_HUFFYUV); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_DVVIDEO); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_FLAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - - default_vcodec = 3; - default_acodec = 5; - break; - case FORMAT_DNXHD: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_DNXHD); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - break; - case FORMAT_AC3: - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_EAC3); - break; - case FORMAT_FLV: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_FLV1); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - break; - case FORMAT_GIF: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_GIF); - break; - case FORMAT_IMG: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_BMP); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MJPEG); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_JPEG2000); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_PSD); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_PNG); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_TIFF); - - default_vcodec = 4; - break; - case FORMAT_MP2: - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - break; - case FORMAT_MP3: - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - break; - case FORMAT_MPEG1: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG1VIDEO); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - - default_acodec = 1; - break; - case FORMAT_MPEG2: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG2VIDEO); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - - default_acodec = 1; - break; - case FORMAT_MPEG4: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG4); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H264); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H265); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - - default_vcodec = 1; - break; - case FORMAT_MPEGTS: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG2VIDEO); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - - default_acodec = 2; - break; - case FORMAT_MKV: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG4); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H264); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H265); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_EAC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_FLAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_OPUS); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_VORBIS); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_WAVPACK); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_WMAV1); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_WMAV2); - - default_vcodec = 1; - break; - case FORMAT_OGG: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_THEORA); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_OPUS); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_VORBIS); - - default_acodec = 1; - break; - case FORMAT_MOV: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_QTRLE); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG4); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H264); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H265); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MJPEG); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_PRORES); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AAC); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_AC3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP2); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_MP3); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - - default_vcodec = 2; - break; - case FORMAT_WAV: - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_PCM_S16LE); - break; - case FORMAT_WEBM: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_VP8); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_VP9); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_OPUS); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_VORBIS); - - default_vcodec = 1; - break; - case FORMAT_WMV: - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_WMV1); - add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_WMV2); - - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_WMAV1); - add_codec_to_combobox(acodecCombobox, AV_CODEC_ID_WMAV2); - - default_vcodec = 1; - default_acodec = 1; - break; - default: - qCritical() << "Invalid format selection - this is a bug, please inform the developers"; - } - - vcodecCombobox->setCurrentIndex(default_vcodec); - acodecCombobox->setCurrentIndex(default_acodec); - - bool video_enabled = vcodecCombobox->count() != 0; - bool audio_enabled = acodecCombobox->count() != 0; - videoGroupbox->setChecked(video_enabled); - audioGroupbox->setChecked(audio_enabled); - videoGroupbox->setEnabled(video_enabled); - audioGroupbox->setEnabled(audio_enabled); -} - -void ExportDialog::export_thread_finished() { - // Determine if the export succeeded - bool succeeded = (progressBar->value() == 100); - - // If it failed and we didn't cancel it, it must have errored out. Show an error message. - if (!succeeded && !export_thread_->WasInterrupted()) { - QMessageBox::critical( - this, - tr("Export Failed"), - tr("Export failed - %1").arg(export_thread_->GetError()), - QMessageBox::Ok - ); - } - - // Clear audio buffer - clear_audio_ibuffer(); - - // Re-enable/disable UI widgets based on the rendering state - prep_ui_for_render(false); - - // Move OpenGL context back to the sequence viewer - panel_sequence_viewer->viewer_widget()->makeCurrent(); - panel_sequence_viewer->viewer_widget()->initializeGL(); - - // Update the application UI - update_ui(false); - - // Disconnect cancel button from export thread - disconnect(renderCancel, SIGNAL(clicked(bool)), export_thread_, SLOT(Interrupt())); - - // Free the export thread - export_thread_->deleteLater(); - - // If the export succeeded, close the dialog - if (succeeded) { - accept(); - } -} - -void ExportDialog::prep_ui_for_render(bool r) { - export_button->setEnabled(!r); - cancel_button->setEnabled(!r); - videoGroupbox->setEnabled(!r); - audioGroupbox->setEnabled(!r); - renderCancel->setEnabled(r); -} - -void ExportDialog::StartExport() { - if (widthSpinbox->value()%2 == 1 || heightSpinbox->value()%2 == 1) { - QMessageBox::critical( - this, - tr("Invalid dimensions"), - tr("Export width and height must both be even numbers/divisible by 2."), - QMessageBox::Ok - ); - return; - } - - QString ext; - switch (formatCombobox->currentIndex()) { - case FORMAT_3GPP: - ext = "3gp"; - break; - case FORMAT_AIFF: - ext = "aiff"; - break; - case FORMAT_APNG: - ext = "apng"; - break; - case FORMAT_AVI: - ext = "avi"; - break; - case FORMAT_DNXHD: - ext = "mxf"; - break; - case FORMAT_AC3: - ext = "ac3"; - break; - case FORMAT_FLV: - ext = "flv"; - break; - case FORMAT_GIF: - ext = "gif"; - break; - case FORMAT_IMG: - switch (vcodecCombobox->currentData().toInt()) { - case AV_CODEC_ID_BMP: - ext = "bmp"; - break; - case AV_CODEC_ID_MJPEG: - ext = "jpg"; - break; - case AV_CODEC_ID_JPEG2000: - ext = "jp2"; - break; - case AV_CODEC_ID_PSD: - ext = "psd"; - break; - case AV_CODEC_ID_PNG: - ext = "png"; - break; - case AV_CODEC_ID_TIFF: - ext = "tif"; - break; - default: - qCritical() << "Invalid codec selection for an image sequence"; - QMessageBox::critical( - this, - tr("Invalid codec"), - tr("Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers."), - QMessageBox::Ok - ); - return; - } - break; - case FORMAT_MP3: - ext = "mp3"; - break; - case FORMAT_MPEG1: - if (videoGroupbox->isChecked() && !audioGroupbox->isChecked()) { - ext = "m1v"; - } else if (!videoGroupbox->isChecked() && audioGroupbox->isChecked()) { - ext = "m1a"; - } else { - ext = "mpg"; - } - break; - case FORMAT_MPEG2: - if (videoGroupbox->isChecked() && !audioGroupbox->isChecked()) { - ext = "m2v"; - } else if (!videoGroupbox->isChecked() && audioGroupbox->isChecked()) { - ext = "m2a"; - } else { - ext = "mpg"; - } - break; - case FORMAT_MPEG4: - if (videoGroupbox->isChecked() && !audioGroupbox->isChecked()) { - ext = "m4v"; - } else if (!videoGroupbox->isChecked() && audioGroupbox->isChecked()) { - ext = "m4a"; - } else { - ext = "mp4"; - } - break; - case FORMAT_MPEGTS: - ext = "ts"; - break; - case FORMAT_MKV: - if (!videoGroupbox->isChecked()) { - ext = "mka"; - } else { - ext = "mkv"; - } - break; - case FORMAT_OGG: - ext = "ogg"; - break; - case FORMAT_MOV: - ext = "mov"; - break; - case FORMAT_WAV: - ext = "wav"; - break; - case FORMAT_WEBM: - ext = "webm"; - break; - case FORMAT_WMV: - if (videoGroupbox->isChecked()) { - ext = "wmv"; - } else { - ext = "wma"; - } - break; - default: - qCritical() << "Invalid format - this is a bug, please inform the developers"; - QMessageBox::critical( - this, - tr("Invalid format"), - tr("Couldn't determine output format. This is a bug, please contact the developers."), - QMessageBox::Ok - ); - return; - } - QString filename = QFileDialog::getSaveFileName( - this, - tr("Export Media"), - "", - format_strings[formatCombobox->currentIndex()] + " (*." + ext + ")" - ); - if (!filename.isEmpty()) { - if (!filename.endsWith("." + ext, Qt::CaseInsensitive)) { - filename += "." + ext; - } - - if (formatCombobox->currentIndex() == FORMAT_IMG) { - int ext_location = filename.lastIndexOf('.'); - if (ext_location > filename.lastIndexOf('/')) { - filename.insert(ext_location, 'd'); - filename.insert(ext_location, '5'); - filename.insert(ext_location, '0'); - filename.insert(ext_location, '%'); - } - } - - // Set up export parameters to send to the ExportThread - ExportParams params; - params.sequence = sequence_; - params.filename = filename; - params.video_enabled = videoGroupbox->isChecked(); - if (params.video_enabled) { - params.video_codec = vcodecCombobox->currentData().toInt(); - params.video_width = widthSpinbox->value(); - params.video_height = heightSpinbox->value(); - params.video_frame_rate = framerateSpinbox->value(); - params.video_compression_type = compressionTypeCombobox->currentData().toInt(); - params.video_bitrate = videobitrateSpinbox->value(); - } - params.audio_enabled = audioGroupbox->isChecked(); - if (params.audio_enabled) { - params.audio_codec = acodecCombobox->currentData().toInt(); - params.audio_sampling_rate = samplingRateSpinbox->value(); - params.audio_bitrate = audiobitrateSpinbox->value(); - } - - params.start_frame = 0; - params.end_frame = sequence_->GetEndFrame(); // entire sequence - if (rangeCombobox->currentIndex() == 1) { - params.start_frame = qMax(sequence_->workarea_in, params.start_frame); - params.end_frame = qMin(sequence_->workarea_out, params.end_frame); - } - - // Create export thread - export_thread_ = new ExportThread(params, vcodec_params, this); - - // Connect export thread signals/slots - connect(export_thread_, SIGNAL(finished()), this, SLOT(export_thread_finished())); - 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 - sequence_->Close(); - - olive::Global->set_export_state(true); - - olive::Global->save_autorecovery_file(); - - prep_ui_for_render(true); - - total_export_time_start = QDateTime::currentMSecsSinceEpoch(); - - export_thread_->start(); - } -} - -void ExportDialog::update_progress_bar(int value, qint64 remaining_ms) { - if (value == 100) { - // if value is 100%, show total render time rather than remaining - remaining_ms = QDateTime::currentMSecsSinceEpoch() - total_export_time_start; - } - - // convert ms to H:MM:SS - int seconds = qFloor(remaining_ms*0.001)%60; - int minutes = qFloor(remaining_ms/60000)%60; - int hours = qFloor(remaining_ms/3600000); - - if (value == 100) { - // show value as "total" - progressBar->setFormat(tr("%p% (Total: %1:%2:%3)").arg(QString::number(hours), - QString::number(minutes).rightJustified(2, '0'), - QString::number(seconds).rightJustified(2, '0'))); - } else { - // show value as "remaining" - progressBar->setFormat(tr("%p% (ETA: %1:%2:%3)").arg(QString::number(hours), - QString::number(minutes).rightJustified(2, '0'), - QString::number(seconds).rightJustified(2, '0'))); - } - - progressBar->setValue(value); -} - -void ExportDialog::vcodec_changed(int index) { - compressionTypeCombobox->clear(); - - if (vcodecCombobox->count() > 0) { - if (vcodecCombobox->itemData(index) == AV_CODEC_ID_H264 - || vcodecCombobox->itemData(index) == AV_CODEC_ID_H265) { - compressionTypeCombobox->setEnabled(true); - compressionTypeCombobox->addItem(tr("Quality-based (Constant Rate Factor)"), COMPRESSION_TYPE_CFR); - // compressionTypeCombobox->addItem("File size-based (Two-Pass)", COMPRESSION_TYPE_TARGETSIZE); - // compressionTypeCombobox->addItem("Average bitrate (Two-Pass)", COMPRESSION_TYPE_TARGETBR); - } else { - compressionTypeCombobox->addItem(tr("Constant Bitrate"), COMPRESSION_TYPE_CBR); - compressionTypeCombobox->setCurrentIndex(0); - compressionTypeCombobox->setEnabled(false); - } - - // set default pix_fmt for this codec - AVCodec* codec_info = avcodec_find_encoder(static_cast(vcodecCombobox->itemData(index).toInt())); - if (codec_info == nullptr) { - QMessageBox::critical(this, - tr("Invalid Codec"), - tr("Failed to find a suitable encoder for this codec. Export will likely fail.")); - } else { - vcodec_params.pix_fmt = codec_info->pix_fmts[0]; - if (vcodec_params.pix_fmt == -1) { - QMessageBox::critical(this, - tr("Invalid Codec"), - tr("Failed to find pixel format for this encoder. Export will likely fail.")); - } - } - } -} - -void ExportDialog::comp_type_changed(int) { - videobitrateSpinbox->setToolTip(""); - videobitrateSpinbox->setMinimum(0); - videobitrateSpinbox->setMaximum(99.99); - switch (compressionTypeCombobox->currentData().toInt()) { - case COMPRESSION_TYPE_CBR: - case COMPRESSION_TYPE_TARGETBR: - videoBitrateLabel->setText(tr("Bitrate (Mbps):")); - videobitrateSpinbox->setValue(qMax(0.5, (double) qRound((0.01528 * sequence_->height()) - 4.5))); - break; - case COMPRESSION_TYPE_CFR: - videoBitrateLabel->setText(tr("Quality (CRF):")); - videobitrateSpinbox->setValue(23); - videobitrateSpinbox->setMaximum(51); - videobitrateSpinbox->setToolTip(tr("Quality Factor:\n\n0 = lossless\n17-18 = visually lossless (compressed, but unnoticeable)\n23 = high quality\n51 = lowest quality possible")); - break; - case COMPRESSION_TYPE_TARGETSIZE: - videoBitrateLabel->setText(tr("Target File Size (MB):")); - videobitrateSpinbox->setValue(100); - break; - } -} - -void ExportDialog::open_advanced_video_dialog() { - AdvancedVideoDialog avd(this, static_cast(vcodecCombobox->currentData().toInt()), vcodec_params); - avd.exec(); -} - -void ExportDialog::setup_ui() { - QVBoxLayout* verticalLayout = new QVBoxLayout(this); - - QHBoxLayout* format_layout = new QHBoxLayout(); - - format_layout->addWidget(new QLabel(tr("Format:"), this)); - - formatCombobox = new QComboBox(); - format_layout->addWidget(formatCombobox); - - verticalLayout->addLayout(format_layout); - - QHBoxLayout* range_layout = new QHBoxLayout(); - - range_layout->addWidget(new QLabel(tr("Range:"), this)); - - rangeCombobox = new QComboBox(this); - rangeCombobox->addItem(tr("Entire Sequence")); - rangeCombobox->addItem(tr("In to Out")); - - range_layout->addWidget(rangeCombobox); - - verticalLayout->addLayout(range_layout); - - videoGroupbox = new QGroupBox(this); - videoGroupbox->setTitle(tr("Video")); - videoGroupbox->setFlat(false); - videoGroupbox->setCheckable(true); - - QGridLayout* videoGridLayout = new QGridLayout(videoGroupbox); - - videoGridLayout->addWidget(new QLabel(tr("Codec:"), this), 0, 0, 1, 1); - vcodecCombobox = new QComboBox(videoGroupbox); - videoGridLayout->addWidget(vcodecCombobox, 0, 1, 1, 1); - - videoGridLayout->addWidget(new QLabel(tr("Width:"), this), 1, 0, 1, 1); - widthSpinbox = new QSpinBox(videoGroupbox); - widthSpinbox->setMaximum(16777216); - videoGridLayout->addWidget(widthSpinbox, 1, 1, 1, 1); - - videoGridLayout->addWidget(new QLabel(tr("Height:"), this), 2, 0, 1, 1); - heightSpinbox = new QSpinBox(videoGroupbox); - heightSpinbox->setMaximum(16777216); - videoGridLayout->addWidget(heightSpinbox, 2, 1, 1, 1); - - videoGridLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 3, 0, 1, 1); - framerateSpinbox = new QDoubleSpinBox(videoGroupbox); - framerateSpinbox->setMaximum(60); - framerateSpinbox->setValue(0); - videoGridLayout->addWidget(framerateSpinbox, 3, 1, 1, 1); - - videoGridLayout->addWidget(new QLabel(tr("Compression Type:"), this), 4, 0, 1, 1); - compressionTypeCombobox = new QComboBox(videoGroupbox); - videoGridLayout->addWidget(compressionTypeCombobox, 4, 1, 1, 1); - - videoBitrateLabel = new QLabel(videoGroupbox); - videoGridLayout->addWidget(videoBitrateLabel, 5, 0, 1, 1); - videobitrateSpinbox = new QDoubleSpinBox(videoGroupbox); - videobitrateSpinbox->setMaximum(100); - videobitrateSpinbox->setValue(2); - videoGridLayout->addWidget(videobitrateSpinbox, 5, 1, 1, 1); - - QPushButton* advanced_video_button = new QPushButton(tr("Advanced")); - connect(advanced_video_button, SIGNAL(clicked(bool)), this, SLOT(open_advanced_video_dialog())); - videoGridLayout->addWidget(advanced_video_button, 6, 1); - - verticalLayout->addWidget(videoGroupbox); - - audioGroupbox = new QGroupBox(this); - audioGroupbox->setTitle(tr("Audio")); - audioGroupbox->setCheckable(true); - - QGridLayout* audioGridLayout = new QGridLayout(audioGroupbox); - - audioGridLayout->addWidget(new QLabel(tr("Codec:"), this), 0, 0, 1, 1); - acodecCombobox = new QComboBox(audioGroupbox); - audioGridLayout->addWidget(acodecCombobox, 0, 1, 1, 1); - - audioGridLayout->addWidget(new QLabel(tr("Sampling Rate:"), this), 1, 0, 1, 1); - samplingRateSpinbox = new QSpinBox(audioGroupbox); - samplingRateSpinbox->setMaximum(96000); - samplingRateSpinbox->setValue(0); - audioGridLayout->addWidget(samplingRateSpinbox, 1, 1, 1, 1); - - audioGridLayout->addWidget(new QLabel(tr("Bitrate (Kbps/CBR):"), this), 3, 0, 1, 1); - audiobitrateSpinbox = new QSpinBox(audioGroupbox); - audiobitrateSpinbox->setMaximum(320); - audiobitrateSpinbox->setValue(256); - audioGridLayout->addWidget(audiobitrateSpinbox, 3, 1, 1, 1); - - verticalLayout->addWidget(audioGroupbox); - - QHBoxLayout* progressLayout = new QHBoxLayout(); - progressBar = new QProgressBar(this); - progressBar->setFormat("%p% (ETA: 0:00:00)"); - progressBar->setEnabled(false); - progressBar->setValue(0); - progressLayout->addWidget(progressBar); - - renderCancel = new QPushButton(this); - renderCancel->setIcon(QIcon(":/icons/error.svg")); - renderCancel->setEnabled(false); - progressLayout->addWidget(renderCancel); - - verticalLayout->addLayout(progressLayout); - - QHBoxLayout* buttonLayout = new QHBoxLayout(); - buttonLayout->addStretch(); - - export_button = new QPushButton(this); - export_button->setText("Export"); - connect(export_button, SIGNAL(clicked(bool)), this, SLOT(StartExport())); - - buttonLayout->addWidget(export_button); - - cancel_button = new QPushButton(this); - cancel_button->setText("Cancel"); - connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject())); - - buttonLayout->addWidget(cancel_button); - - buttonLayout->addStretch(); - - verticalLayout->addLayout(buttonLayout); - - connect(formatCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(format_changed(int))); - connect(compressionTypeCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(comp_type_changed(int))); - connect(vcodecCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(vcodec_changed(int))); -} diff --git a/dialogs/exportdialog.h b/dialogs/exportdialog.h deleted file mode 100644 index d24e57e18..000000000 --- a/dialogs/exportdialog.h +++ /dev/null @@ -1,277 +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 EXPORTDIALOG_H -#define EXPORTDIALOG_H - -#include -#include -#include -#include -#include -#include -#include - -#include "timeline/sequence.h" -#include "rendering/exportthread.h" - -/** - * @brief The ExportDialog class - * - * The dialog to initiate an export. Requires a valid Sequence to be set in olive::ActiveSequence or the result is - * defined (most likely a crash), so you should always do a `nullptr` check on olive::ActiveSequence before constructing - * this dialog. - */ -class ExportDialog : public QDialog -{ - Q_OBJECT -public: - /** - * @brief ExportDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow. - */ - explicit ExportDialog(QWidget *parent, Sequence *sequence); - -private slots: - /** - * @brief Slot for when the user changes the format - * - * Used to populate the available codecs list for this format. - * - * @param index - * - * Current format index (corresponding to enum ExportFormats) - */ - void format_changed(int index); - - /** - * @brief Slot for when the user clicks the Export button - * - * Asks the user for the file to save to. - */ - void StartExport(); - - /** - * @brief Slot for the export thread to update the progress bar's value - * - * @param value - * - * An value between 0 - 100. A percentage of the Sequence that has been exported so far. - * - * @param remaining_ms - * - * The estimated time in milliseconds that it will take to complete the rest of the Sequence. - */ - void update_progress_bar(int value, qint64 remaining_ms); - - /** - * @brief Slot for the export thread completing (both succeeding and failing) - * - * Runs whenever the thread has finished. Determines whether the thread succeeded or not (and shows an error message - * if not), cleans up the ExportThread object, sets the UI state back to normal. - * - * Connect to ExportThread::finished(). - */ - void export_thread_finished(); - - /** - * @brief Slot for when the video codec changes - * - * Some video codecs require different settings. In the case of that, this function sorts through those. - * - * @param index - * - * Current vcodecCombobox index - its item data contains the AVCodecID. - */ - void vcodec_changed(int index); - - /** - * @brief Slot for when the compression type changes - * - * Different UI objects should be displayed for different compression types. - * - * @param index - * - * Unused. - */ - void comp_type_changed(int index); - - /** - * @brief Slot to open the Advanced Video Dialog - * - * Opens a dialog for setting more advanced video settings and passes a reference to vcodec_params to it. - */ - void open_advanced_video_dialog(); - -private: - /** - * @brief Function to create UI objects. - */ - void setup_ui(); - - /** - * @brief Enables/disables certain UI objects based on the exporting state. - * - * Some UI controls don't need to be set while exporting. This function enables/disables them appropriately. - * - * @param r - * - * TRUE if we're exporting, FALSE if we finished. - */ - void prep_ui_for_render(bool r); - - /** - * @brief Retrieves the human-readable name of an AVCodecID and adds it to a QComboBox - * - * Also sets that item's data to the AVCodecID so it can be retrieved directly from the QComboBox. - * - * @param box - * - * The QComboBox to add the item to. - * - * @param codec - * - * The codec to add to the QComboBox. - */ - void add_codec_to_combobox(QComboBox* box, enum AVCodecID codec); - - /** - * @brief Internal array of human-readable names corresponding to enum ExportFormats - */ - QVector format_strings; - - /** - * @brief Pointer to an ExportThread - * - * Set when exporting starts, and deleted by export_thread_finished() when the thread is complete. - */ - ExportThread* export_thread_; - - /** - * @brief Struct for advanced video codec parameters. - * - * More advanced video encoding parameters to be sent to the ExportThread. These variables are not directly editable - * in this dialog, instead calling open_advanced_video_dialog() will open an AdvancedVideoDialog for setting these - * values directly. vcodec_changed() should also set these to the defaults for that codec where appropriate. - */ - VideoCodecParams vcodec_params; - - /** - * @brief ComboBox for selecting the time range of the Sequence to export - */ - QComboBox* rangeCombobox; - - /** - * @brief SpinBox for the exported video's width - */ - QSpinBox* widthSpinbox; - - /** - * @brief SpinBox for the exported video's bitrate - */ - QDoubleSpinBox* videobitrateSpinbox; - - /** - * @brief Label for the exported video's bitrate - changes depending on the compression type - */ - QLabel* videoBitrateLabel; - - /** - * @brief SpinBox for the exported video's frame rate - */ - QDoubleSpinBox* framerateSpinbox; - - /** - * @brief ComboBox for the exported video codec - */ - QComboBox* vcodecCombobox; - - /** - * @brief ComboBox for the exported audio's codec - */ - QComboBox* acodecCombobox; - - /** - * @brief SpinBox for the exported audio's sample rate - */ - QSpinBox* samplingRateSpinbox; - - /** - * @brief SpinBox for the exported audio's bitrate - */ - QSpinBox* audiobitrateSpinbox; - - /** - * @brief Progress bar for visually showing the export progress - */ - QProgressBar* progressBar; - - /** - * @brief ComboBox for the exported video's format - */ - QComboBox* formatCombobox; - - /** - * @brief SpinBox for the exported video's height - */ - QSpinBox* heightSpinbox; - - /** - * @brief Export button to trigger the start of an export - */ - QPushButton* export_button; - - /** - * @brief Dialog cancel button to close this dialog - */ - QPushButton* cancel_button; - - /** - * @brief Cancel button to abort the export before completion - */ - QPushButton* renderCancel; - - /** - * @brief GroupBox containing all video-related UI objects - */ - QGroupBox* videoGroupbox; - - /** - * @brief GroupBox containing all audio-related UI objects - */ - QGroupBox* audioGroupbox; - - /** - * @brief ComboBox for the exported video compression type - */ - QComboBox* compressionTypeCombobox; - - /** - * @brief Time value set when exporting begins to determine the total duration of the export - */ - qint64 total_export_time_start; - - Sequence* sequence_; -}; - -#endif // EXPORTDIALOG_H diff --git a/dialogs/loaddialog.cpp b/dialogs/loaddialog.cpp deleted file mode 100644 index cee5d64e4..000000000 --- a/dialogs/loaddialog.cpp +++ /dev/null @@ -1,63 +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 "loaddialog.h" - -#include -#include -#include - -#include "global/global.h" - -#include "panels/panels.h" - -#include "ui/sourcetable.h" -#include "ui/mainwindow.h" - -LoadDialog::LoadDialog(QWidget *parent) : - QDialog(parent) -{ - setWindowTitle(tr("Loading...")); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - - QVBoxLayout* layout = new QVBoxLayout(this); - - layout->addWidget(new QLabel(tr("Loading '%1'...").arg(olive::ActiveProjectFilename.mid(olive::ActiveProjectFilename.lastIndexOf('/')+1)), this)); - - bar = new QProgressBar(this); - bar->setValue(0); - layout->addWidget(bar); - - QPushButton* cancel_button = new QPushButton(tr("Cancel"), this); - connect(cancel_button, SIGNAL(clicked(bool)), this, SIGNAL(cancel())); - - // Wrap cancel button in a horizontal layout so it can be centered - QHBoxLayout* hboxLayout = new QHBoxLayout(); - hboxLayout->addStretch(); - hboxLayout->addWidget(cancel_button); - hboxLayout->addStretch(); - - layout->addLayout(hboxLayout); -} - -void LoadDialog::setValue(int i) -{ - bar->setValue(i); -} diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h deleted file mode 100644 index f9b10676c..000000000 --- a/dialogs/loaddialog.h +++ /dev/null @@ -1,76 +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 LOADDIALOG_H -#define LOADDIALOG_H - -#include -#include -#include - -#include "project/projectelements.h" -#include "project/loadthread.h" - -/** - * @brief The LoadDialog class - * - * Shows a modal dialog for loading a project. Designed to be connected to a LoadThread object. This dialog should - * generally not be created directly, use OliveGlobal::LoadProject (or its variants) to correctly set up a LoadDialog - * and LoadThread and connect them to each other. - */ -class LoadDialog : public QDialog -{ - Q_OBJECT -public: - /** - * @brief LoadDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow. - */ - LoadDialog(QWidget* parent); - -public slots: - /** - * @brief Set the progress bar value - * - * Ideally, connect this to LoadThread::report_progress(). - * - * @param i - * - * Should be a value between 0-100. - */ - void setValue(int i); -signals: - /** - * @brief Signal emitted when the cancel button is clicked. - * - * Ideally, connect this to LoadThread::cancel(); - */ - void cancel(); -private: - /** - * @brief Progress bar widget - */ - QProgressBar* bar; -}; - -#endif // LOADDIALOG_H diff --git a/dialogs/mediapropertiesdialog.cpp b/dialogs/mediapropertiesdialog.cpp deleted file mode 100644 index 060d9192b..000000000 --- a/dialogs/mediapropertiesdialog.cpp +++ /dev/null @@ -1,238 +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 "mediapropertiesdialog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -#include "project/footage.h" -#include "project/media.h" -#include "panels/project.h" -#include "undo/undo.h" -#include "undo/undostack.h" - -MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) : - QDialog(parent), - item(i) -{ - setWindowTitle(tr("\"%1\" Properties").arg(i->get_name())); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - QGridLayout* grid = new QGridLayout(this); - - int row = 0; - - Footage* f = item->to_footage(); - - grid->addWidget(new QLabel(tr("Tracks:"), this), row, 0, 1, 2); - row++; - - track_list = new QListWidget(this); - for (int i=0;ivideo_tracks.size();i++) { - const FootageStream& fs = f->video_tracks.at(i); - - QListWidgetItem* item = new QListWidgetItem( - tr("Video %1: %2x%3 %4FPS").arg( - QString::number(fs.file_index), - QString::number(fs.video_width), - QString::number(fs.video_height), - QString::number(fs.video_frame_rate) - ), - track_list - ); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked); - item->setData(Qt::UserRole+1, fs.file_index); - track_list->addItem(item); - } - for (int i=0;iaudio_tracks.size();i++) { - const FootageStream& fs = f->audio_tracks.at(i); - QListWidgetItem* item = new QListWidgetItem( - tr("Audio %1: %2Hz %3").arg( - QString::number(fs.file_index), - QString::number(fs.audio_frequency), - tr("%n channel(s)", "", fs.audio_channels) - ), - track_list - ); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked); - item->setData(Qt::UserRole+1, fs.file_index); - track_list->addItem(item); - } - grid->addWidget(track_list, row, 0, 1, 2); - row++; - - if (f->video_tracks.size() > 0) { - // frame conforming - if (!f->video_tracks.at(0).infinite_length) { - grid->addWidget(new QLabel(tr("Conform to Frame Rate:"), this), row, 0); - conform_fr = new QDoubleSpinBox(this); - conform_fr->setMinimum(0.01); - conform_fr->setValue(f->video_tracks.at(0).video_frame_rate * f->speed); - grid->addWidget(conform_fr, row, 1); - } - - row++; - - // premultiplied alpha mode - premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this); - premultiply_alpha_setting->setChecked(f->alpha_is_associated); - grid->addWidget(premultiply_alpha_setting, row, 0); - - row++; - - // deinterlacing mode - interlacing_box = new QComboBox(this); - interlacing_box->addItem( - tr("Auto (%1)").arg( - Footage::get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing) - ) - ); - interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_PROGRESSIVE)); - interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_TOP_FIELD_FIRST)); - interlacing_box->addItem(Footage::get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST)); - - interlacing_box->setCurrentIndex( - (f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing) - ? 0 - : f->video_tracks.at(0).video_interlacing + 1); - - grid->addWidget(new QLabel(tr("Interlacing:"), this), row, 0); - grid->addWidget(interlacing_box, row, 1); - - row++; - - input_color_space = new QComboBox(this); - - OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); - - QString footage_colorspace = f->Colorspace(); - - for (int i=0;igetNumColorSpaces();i++) { - QString colorspace = config->getColorSpaceNameByIndex(i); - - input_color_space->addItem(colorspace); - - if (colorspace == footage_colorspace) { - input_color_space->setCurrentIndex(i); - } - } - - grid->addWidget(new QLabel(tr("Color Space:")), row, 0); - grid->addWidget(input_color_space, row, 1); - - row++; - - } - - name_box = new QLineEdit(item->get_name(), this); - grid->addWidget(new QLabel(tr("Name:"), this), row, 0); - grid->addWidget(name_box, row, 1); - row++; - - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - buttons->setCenterButtons(true); - grid->addWidget(buttons, row, 0, 1, 2); - - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); -} - -void MediaPropertiesDialog::accept() { - Footage* f = item->to_footage(); - - ComboAction* ca = new ComboAction(); - - // set track enable - for (int i=0;icount();i++) { - QListWidgetItem* item = track_list->item(i); - const QVariant& data = item->data(Qt::UserRole+1); - if (!data.isNull()) { - int index = data.toInt(); - bool found = false; - for (int j=0;jvideo_tracks.size();j++) { - if (f->video_tracks.at(j).file_index == index) { - f->video_tracks[j].enabled = (item->checkState() == Qt::Checked); - found = true; - break; - } - } - if (!found) { - for (int j=0;jaudio_tracks.size();j++) { - if (f->audio_tracks.at(j).file_index == index) { - f->audio_tracks[j].enabled = (item->checkState() == Qt::Checked); - break; - } - } - } - } - } - - bool refresh_clips = false; - - // set interlacing - if (f->video_tracks.size() > 0) { - if (interlacing_box->currentIndex() > 0) { - ca->append(new SetInt(&f->video_tracks[0].video_interlacing, interlacing_box->currentIndex() - 1)); - } else { - ca->append(new SetInt(&f->video_tracks[0].video_interlacing, f->video_tracks.at(0).video_auto_interlacing)); - } - - // set frame rate conform - if (!f->video_tracks.at(0).infinite_length) { - if (!qFuzzyCompare(conform_fr->value(), f->video_tracks.at(0).video_frame_rate)) { - ca->append(new SetDouble(&f->speed, f->speed, conform_fr->value()/f->video_tracks.at(0).video_frame_rate)); - refresh_clips = true; - } - } - - // set premultiplied alpha - f->alpha_is_associated = premultiply_alpha_setting->isChecked(); - } - - f->SetColorspace(input_color_space->currentText()); - - // set name - MediaRename* mr = new MediaRename(item, name_box->text()); - - ca->append(mr); - ca->appendPost(new CloseAllClipsCommand()); - ca->appendPost(new UpdateFootageTooltip(item)); - if (refresh_clips) { - ca->appendPost(new RefreshClips(item)); - } - ca->appendPost(new UpdateViewer()); - - olive::undo_stack.push(ca); - - QDialog::accept(); -} diff --git a/dialogs/mediapropertiesdialog.h b/dialogs/mediapropertiesdialog.h deleted file mode 100644 index 5e86b5832..000000000 --- a/dialogs/mediapropertiesdialog.h +++ /dev/null @@ -1,97 +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 MEDIAPROPERTIESDIALOG_H -#define MEDIAPROPERTIESDIALOG_H - -#include -#include -#include -#include -#include -#include - -#include "project/footage.h" -#include "project/media.h" - -/** - * @brief The MediaPropertiesDialog class - * - * A dialog for setting properties on Media. This can be loaded from any part of the application provided it's given - * a valid Media object. - */ -class MediaPropertiesDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief MediaPropertiesDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow or Project panel. - * - * @param i - * - * Media object to set properties for. - */ - MediaPropertiesDialog(QWidget *parent, Media* i); -private: - /** - * @brief ComboBox for interlacing setting - */ - QComboBox* interlacing_box; - - /** - * @brief Media name text field - */ - QLineEdit* name_box; - - /** - * @brief Internal pointer to Media object (set in constructor) - */ - Media* item; - - /** - * @brief A list widget for listing the tracks in Media - */ - QListWidget* track_list; - - /** - * @brief Frame rate to conform to - */ - QDoubleSpinBox* conform_fr; - - /** - * @brief Setting for associated/premultiplied alpha - */ - QCheckBox* premultiply_alpha_setting; - - /** - * @brief Setting for this media's color space - */ - QComboBox* input_color_space; -private slots: - /** - * @brief Overridden accept function for saving the properties back to the Media class - */ - void accept(); -}; - -#endif // MEDIAPROPERTIESDIALOG_H diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp deleted file mode 100644 index 8d9150862..000000000 --- a/dialogs/newsequencedialog.cpp +++ /dev/null @@ -1,323 +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 "newsequencedialog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "panels/panels.h" -#include "panels/project.h" -#include "timeline/sequence.h" -#include "undo/undostack.h" -#include "undo/undo.h" -#include "timeline/clip.h" -#include "panels/timeline.h" -#include "project/media.h" -#include "rendering/audio.h" -#include "global/config.h" - -// FIXME: TEST CODE -#include "nodes/nodes/nodemedia.h" -// END TEST CODE - -extern "C" { -#include -} - -NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing, Sequence* iexisting_sequence) : - QDialog(parent), - existing_item(existing), - existing_sequence(iexisting_sequence) -{ - Q_ASSERT(!(existing != nullptr && iexisting_sequence != nullptr)); - - setup_ui(); - - if (existing != nullptr) { - existing_sequence = existing->to_sequence().get(); - } - - if (existing_sequence != nullptr) { - setWindowTitle(tr("Editing \"%1\"").arg(existing_sequence->name())); - - width_numeric->setValue(existing_sequence->width()); - height_numeric->setValue(existing_sequence->height()); - int comp_rate = qRound(existing_sequence->frame_rate()*100); - for (int i=0;icount();i++) { - if (qRound(frame_rate_combobox->itemData(i).toDouble()*100) == comp_rate) { - frame_rate_combobox->setCurrentIndex(i); - break; - } - } - sequence_name_edit->setText(existing_sequence->name()); - for (int i=0;icount();i++) { - if (audio_frequency_combobox->itemData(i) == existing_sequence->audio_frequency()) { - audio_frequency_combobox->setCurrentIndex(i); - break; - } - } - } else { - existing_sequence = nullptr; - setWindowTitle(tr("New Sequence")); - } -} - -void NewSequenceDialog::set_sequence_name(const QString& s) { - sequence_name_edit->setText(s); -} - -void NewSequenceDialog::SetNameEditable(bool enabled) -{ - sequence_name_edit->setVisible(enabled); - sequence_name_label->setVisible(enabled); -} - -void NewSequenceDialog::accept() { - if (existing_sequence == nullptr) { - - // The dialog wasn't given an existing Sequence object, so we'll make a new one - - SequencePtr s = std::make_shared(); - - s->set_name(sequence_name_edit->text()); - s->set_width(width_numeric->value()); - s->set_height(height_numeric->value()); - s->set_frame_rate(frame_rate_combobox->currentData().toDouble()); - s->set_audio_frequency(audio_frequency_combobox->currentData().toInt()); - s->set_audio_layout(AV_CH_LAYOUT_STEREO); - - ComboAction* ca = new ComboAction(); - olive::project_model.CreateSequence(ca, s, true, nullptr); - olive::undo_stack.push(ca); - - } else if (existing_item != nullptr) { - - // The dialog was given an existing Sequence object, so we'll apply the changes to it - - ComboAction* ca = new ComboAction(); - - double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate(); - - EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_item->to_sequence()); - esc->name = sequence_name_edit->text(); - esc->width = width_numeric->value(); - esc->height = height_numeric->value(); - esc->frame_rate = frame_rate_combobox->currentData().toDouble(); - esc->audio_frequency = audio_frequency_combobox->currentData().toInt(); - esc->audio_layout = AV_CH_LAYOUT_STEREO; - ca->append(esc); - - QVector existing_sequence_clips = existing_sequence->GetAllClips(); - for (int i=0;irefactor_frame_rate(ca, multiplier, true); - } - - olive::undo_stack.push(ca); - - } else if (existing_sequence != nullptr) { - - // This dialog was given an existing Sequence without a Media wrapper - therefore just directly apply the settings - - existing_sequence->set_name(sequence_name_edit->text()); - existing_sequence->set_width(width_numeric->value()); - existing_sequence->set_height(height_numeric->value()); - existing_sequence->set_frame_rate(frame_rate_combobox->currentData().toDouble()); - existing_sequence->set_audio_frequency(audio_frequency_combobox->currentData().toInt()); - existing_sequence->set_audio_layout(AV_CH_LAYOUT_STEREO); - - } - - QDialog::accept(); -} - -void NewSequenceDialog::preset_changed(int index) { - switch (index) { - case 0: // FILM 4K - width_numeric->setValue(4096); - height_numeric->setValue(2160); - break; - case 1: // TV 4K - width_numeric->setValue(3840); - height_numeric->setValue(2160); - break; - case 2: // 1080p - width_numeric->setValue(1920); - height_numeric->setValue(1080); - break; - case 3: // 720p - width_numeric->setValue(1280); - height_numeric->setValue(720); - break; - case 4: // 480p - width_numeric->setValue(640); - height_numeric->setValue(480); - break; - case 5: // 360p - width_numeric->setValue(640); - height_numeric->setValue(360); - break; - case 6: // 240p - width_numeric->setValue(320); - height_numeric->setValue(240); - break; - case 7: // 144p - width_numeric->setValue(192); - height_numeric->setValue(144); - break; - case 8: // NTSC (480i) - width_numeric->setValue(720); - height_numeric->setValue(480); - break; - case 9: // PAL (576i) - width_numeric->setValue(720); - height_numeric->setValue(576); - break; - } -} - -void NewSequenceDialog::setup_ui() { - QVBoxLayout* verticalLayout = new QVBoxLayout(this); - - QWidget* widget = new QWidget(this); - - QHBoxLayout* preset_layout = new QHBoxLayout(widget); - preset_layout->setContentsMargins(0, 0, 0, 0); - - preset_layout->addWidget(new QLabel(tr("Preset:"), this)); - - preset_combobox = new QComboBox(widget); - - preset_combobox->addItem(tr("Film 4K")); - preset_combobox->addItem(tr("TV 4K (Ultra HD/2160p)")); - preset_combobox->addItem(tr("1080p")); - preset_combobox->addItem(tr("720p")); - preset_combobox->addItem(tr("480p")); - preset_combobox->addItem(tr("360p")); - preset_combobox->addItem(tr("240p")); - preset_combobox->addItem(tr("144p")); - preset_combobox->addItem(tr("NTSC (480i)")); - preset_combobox->addItem(tr("PAL (576i)")); - preset_combobox->addItem(tr("Custom")); - preset_combobox->setCurrentIndex(2); - - preset_layout->addWidget(preset_combobox); - - verticalLayout->addWidget(widget); - - QGroupBox* videoGroupBox = new QGroupBox(this); - videoGroupBox->setTitle(tr("Video")); - - QGridLayout* videoLayout = new QGridLayout(videoGroupBox); - - videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1); - width_numeric = new QSpinBox(videoGroupBox); - width_numeric->setMaximum(9999); - width_numeric->setValue(olive::config.default_sequence_width); - videoLayout->addWidget(width_numeric, 0, 2, 1, 2); - - videoLayout->addWidget(new QLabel(tr("Height:"), this), 1, 0, 1, 2); - height_numeric = new QSpinBox(videoGroupBox); - height_numeric->setMaximum(9999); - height_numeric->setValue(olive::config.default_sequence_height); - videoLayout->addWidget(height_numeric, 1, 2, 1, 2); - - videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1); - frame_rate_combobox = new QComboBox(videoGroupBox); - frame_rate_combobox->addItem("10 FPS", 10.0); - frame_rate_combobox->addItem("12.5 FPS", 12.5); - frame_rate_combobox->addItem("15 FPS", 15.0); - frame_rate_combobox->addItem("23.976 FPS", 23.976); - frame_rate_combobox->addItem("24 FPS", 24.0); - frame_rate_combobox->addItem("25 FPS", 25.0); - frame_rate_combobox->addItem("29.97 FPS", 29.97); - frame_rate_combobox->addItem("30 FPS", 30.0); - frame_rate_combobox->addItem("50 FPS", 50.0); - frame_rate_combobox->addItem("59.94 FPS", 59.94); - frame_rate_combobox->addItem("60 FPS", 60.0); - for (int i=0;icount();i++) { - if (qFuzzyCompare(frame_rate_combobox->itemData(i).toDouble(), olive::config.default_sequence_framerate)) { - frame_rate_combobox->setCurrentIndex(i); - } - } - videoLayout->addWidget(frame_rate_combobox, 2, 2, 1, 2); - - videoLayout->addWidget(new QLabel(tr("Pixel Aspect Ratio:"), this), 4, 0, 1, 1); - par_combobox = new QComboBox(videoGroupBox); - par_combobox->addItem(tr("Square Pixels (1.0)")); - videoLayout->addWidget(par_combobox, 4, 2, 1, 2); - - videoLayout->addWidget(new QLabel(tr("Interlacing:"), this), 6, 0, 1, 1); - interlacing_combobox = new QComboBox(videoGroupBox); - interlacing_combobox->addItem(tr("None (Progressive)")); - videoLayout->addWidget(interlacing_combobox, 6, 2, 1, 2); - - verticalLayout->addWidget(videoGroupBox); - - QGroupBox* audioGroupBox = new QGroupBox(this); - audioGroupBox->setTitle(tr("Audio")); - - QGridLayout* audioLayout = new QGridLayout(audioGroupBox); - - audioLayout->addWidget(new QLabel(tr("Sample Rate: "), this), 0, 0, 1, 1); - - audio_frequency_combobox = new QComboBox(audioGroupBox); - combobox_audio_sample_rates(audio_frequency_combobox); - for (int i=0;icount();i++) { - if (audio_frequency_combobox->itemData(i) == olive::config.default_sequence_audio_frequency) { - audio_frequency_combobox->setCurrentIndex(i); - } - } - - audioLayout->addWidget(audio_frequency_combobox, 0, 1, 1, 1); - - verticalLayout->addWidget(audioGroupBox); - - QWidget* nameWidget = new QWidget(this); - QHBoxLayout* nameLayout = new QHBoxLayout(nameWidget); - nameLayout->setContentsMargins(0, 0, 0, 0); - - sequence_name_label = new QLabel(tr("Name:")); - nameLayout->addWidget(sequence_name_label); - - sequence_name_edit = new QLineEdit(nameWidget); - - nameLayout->addWidget(sequence_name_edit); - - verticalLayout->addWidget(nameWidget); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(this); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - buttonBox->setCenterButtons(true); - - verticalLayout->addWidget(buttonBox); - - connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(preset_changed(int))); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); -} diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h deleted file mode 100644 index 661dabb20..000000000 --- a/dialogs/newsequencedialog.h +++ /dev/null @@ -1,168 +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 NEWSEQUENCEDIALOG_H -#define NEWSEQUENCEDIALOG_H - -#include -#include -#include -#include - -#include "panels/project.h" -#include "project/media.h" -#include "timeline/sequence.h" - -/** - * @brief The NewSequenceDialog class - * - * A dialog that creates a new (or edits an existing) Sequence object. Can be run from any part of the application. - */ -class NewSequenceDialog : public QDialog -{ - Q_OBJECT -public: - /** - * @brief NewSequenceDialog constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow. - * - * @param existing - * - * Set this to a Sequence object (wrapped in a Media object) to edit an existing Sequence, - * or leave as nullptr to create a new one. - * - * @param existing_sequence - * - * If your Sequence object is not wrapped in a Media object, use this to reference a raw Sequence pointer. You must - * not use both existing_sequence AND existing - one must be nullptr. - */ - explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr, Sequence* iexisting_sequence = nullptr); - - /** - * @brief Set the name for the new Sequence - * - * If creating a new Sequence, use this function before calling exec() to set what the new Sequence's - * name will be. - * - * The primary use of this is to set a unique default name (i.e. one that doesn't exist - * in the Sequence already) which is done by Project panel. This is usually "Sequence" followed by a number. - * - * @param s - * - * The name to set the new Sequence. - */ - void set_sequence_name(const QString& s); - - /** - * @brief Set whether the Sequence's name can be edited - * - * This defaults to TRUE. - * - * @param enabled - * - * TRUE to allow the user to edit the Sequence's name. FALSE if not. - */ - void SetNameEditable(bool enabled); - -private slots: - /** - * @brief Override accept function to create/edit a Sequence - */ - virtual void accept() override; - - /** - * @brief Slot when the user changes the preset - * - * Sets all values according to the preset chosen. - * - * @param index - * - * Currently selected index of preset_combobox; - */ - void preset_changed(int index); - -private: - /** - * @brief Internal reference to an existing Media wrapper (if one was provided to the constructor) - */ - Media* existing_item; - - /** - * @brief Internal reference to an existing Sequence (if one was provided to the constructor) - */ - Sequence* existing_sequence; - - /** - * @brief Internal function to create the dialog's UI - */ - void setup_ui(); - - /** - * @brief ComboBox to set the preset - */ - QComboBox* preset_combobox; - - /** - * @brief SpinBox to set the Sequence height - */ - QSpinBox* height_numeric; - - /** - * @brief SpinBox to set the Sequence width - */ - QSpinBox* width_numeric; - - /** - * @brief ComboBox to set the pixel aspect ratio - */ - QComboBox* par_combobox; - - /** - * @brief ComboBox to set the interlacing mode - */ - QComboBox* interlacing_combobox; - - /** - * @brief ComboBox to set the frame rate - */ - QComboBox* frame_rate_combobox; - - /** - * @brief ComboBox to set the audio frequence - */ - QComboBox* audio_frequency_combobox; - - /** - * @brief Label marker for setting the Sequence's name - * - * Primarily a persistent class reference so it can be hidden with SetNameEditable() alongside sequence_name_edit. - */ - QLabel* sequence_name_label; - - /** - * @brief Line edit to set the Sequence's name - */ - QLineEdit* sequence_name_edit; -}; - -#endif // NEWSEQUENCEDIALOG_H diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp deleted file mode 100644 index ed9ac7dea..000000000 --- a/dialogs/preferencesdialog.cpp +++ /dev/null @@ -1,1197 +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 "preferencesdialog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "global/config.h" -#include "global/path.h" -#include "rendering/audio.h" -#include "rendering/pixelformats.h" -#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) { - setKeySequence(action->shortcut()); -} - -void KeySequenceEditor::set_action_shortcut() { - action->setShortcut(keySequence()); -} - -void KeySequenceEditor::reset_to_default() { - setKeySequence(action->property("default").toString()); -} - -QString KeySequenceEditor::action_name() { - return action->property("id").toString(); -} - -QString KeySequenceEditor::export_shortcut() { - QString ks = keySequence().toString(); - if (ks != action->property("default")) { - return action->property("id").toString() + "\t" + ks; - } - return nullptr; -} - -PreferencesDialog::PreferencesDialog(QWidget *parent) : - QDialog(parent) -{ - setWindowTitle(tr("Preferences")); - - setup_ui(); - - setup_kbd_shortcuts(olive::MainWindow->menuBar()); - - // set up default sequence - default_sequence.set_name(tr("Default Sequence")); - default_sequence.set_width(olive::config.default_sequence_width); - default_sequence.set_height(olive::config.default_sequence_height); - default_sequence.set_frame_rate(olive::config.default_sequence_framerate); - default_sequence.set_audio_frequency(olive::config.default_sequence_audio_frequency); - default_sequence.set_audio_layout(olive::config.default_sequence_audio_channel_layout); -} - -void PreferencesDialog::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { - QList actions = menu->actions(); - for (int i=0;iisSeparator() && a->property("keyignore").isNull()) { - QTreeWidgetItem* item = new QTreeWidgetItem(parent); - item->setText(0, a->text().replace("&", "")); - - parent->addChild(item); - - if (a->menu() != nullptr) { - item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); - setup_kbd_shortcut_worker(a->menu(), item); - } else { - key_shortcut_items.append(item); - key_shortcut_actions.append(a); - } - } - } -} - -void PreferencesDialog::delete_previews(PreviewDeleteTypes type) { - char delete_char = 0; - - switch (type) { - case DELETE_WAVEFORMS: - delete_char = 'w'; - break; - case DELETE_THUMBNAILS: - delete_char = 't'; - break; - case DELETE_BOTH: - delete_char = 1; - break; - case DELETE_NONE: - break; - } - - if (delete_char != 't' && delete_char != 'w' && delete_char != 1) return; - - QDir preview_path(get_data_path() + "/previews"); - - if (delete_char == 1) { - // indiscriminately delete everything - preview_path.removeRecursively(); - } else { - QStringList preview_file_list = preview_path.entryList(QDir::Files | QDir::NoDotAndDotDot); - for (int i=0;i= 0 - && preview_file_str.at(identifier_char_index) >= 48 - && preview_file_str.at(identifier_char_index) <= 57) { - identifier_char_index--; - } - - // thumbnails will have a 't' towards the end of the filenames, waveforms will have a 'w' - // if they match the type of preview we're deleting, remove them - if (preview_file_str.at(identifier_char_index) == delete_char) { - QFile::remove(preview_path.filePath(preview_file_str)); - } - } - } -} - -void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config) -{ - if (!config) { - - // Just clear everything - ocio_display->clear(); - ocio_default_input->clear(); - ocio_view->clear(); - ocio_look->clear(); - - } else { - - // Get input color spaces for setting the default input color space - ocio_default_input->clear(); - for (int i=0;igetNumColorSpaces();i++) { - QString colorspace = config->getColorSpaceNameByIndex(i); - - ocio_default_input->addItem(colorspace); - - if (colorspace == olive::config.ocio_default_input_colorspace) { - ocio_default_input->setCurrentIndex(i); - } - } - - // Get current display name (if the config is empty, get the current default display) - QString current_display = olive::config.ocio_display; - if (current_display.isEmpty()) { - current_display = config->getDefaultDisplay(); - } - - // Populate the display menu - ocio_display->clear(); - for (int i=0;igetNumDisplays();i++) { - ocio_display->addItem(config->getDisplay(i)); - - // Check if this index is the currently selected - if (config->getDisplay(i) == current_display) { - ocio_display->setCurrentIndex(i); - } - } - - update_ocio_view_menu(config); - - // Populate the look menu - ocio_look->clear(); - ocio_look->addItem(tr("(None)"), QString()); - for (int i=0;igetNumLooks();i++) { - const char* look = config->getLookNameByIndex(i); - - ocio_look->addItem(look, look); - - if (look == olive::config.ocio_look) { - ocio_look->setCurrentIndex(i+1); - } - } - - } -} - -OCIO::ConstConfigRcPtr PreferencesDialog::TestOCIOConfig(const QString &url) -{ - // Check whether OCIO can load it - OCIO::ConstConfigRcPtr config; - try { - config = OCIO::Config::CreateFromFile(url.toUtf8()); - } catch (OCIO::Exception& e) { - QMessageBox::critical(this, - tr("OpenColorIO Config Error"), - tr("Failed to set OpenColorIO configuration: %1").arg(e.what()), - QMessageBox::Ok); - } - return config; -} - -void PreferencesDialog::update_ocio_view_menu(OCIO::ConstConfigRcPtr config) -{ - - // Get views for the current display set in `ocio_display` - QString display = ocio_display->currentText(); - - // Get current view - QString current_view = olive::config.ocio_view; - if (current_view.isEmpty()) { - current_view = config->getDefaultView(display.toUtf8()); - } - - // Populate the view menu - int ocio_view_count = config->getNumViews(display.toUtf8()); - ocio_view->clear(); - for (int i=0;igetView(display.toUtf8(), i); - - ocio_view->addItem(view); - - if (current_view == view) { - ocio_view->setCurrentIndex(i); - } - } -} - -void PreferencesDialog::update_ocio_config(const QString &s) -{ - OCIO::ConstConfigRcPtr file_config; - - if (!s.isEmpty() && QFileInfo::exists(s)) { - file_config = TestOCIOConfig(s); - } - - populate_ocio_menus(file_config); -} - -void PreferencesDialog::AddBoolPair(QCheckBox *ui, bool *value, bool restart_required) -{ - bool_ui.append(ui); - bool_value.append(value); - bool_restart_required.append(restart_required); - - ui->setChecked(*value); -} - -void PreferencesDialog::setup_kbd_shortcuts(QMenuBar* menubar) { - QList menus = menubar->actions(); - - for (int i=0;imenu(); - - QTreeWidgetItem* item = new QTreeWidgetItem(keyboard_tree); - item->setText(0, menu->title().replace("&", "")); - - keyboard_tree->addTopLevelItem(item); - - setup_kbd_shortcut_worker(menu, item); - } - - for (int i=0;iproperty("id").isNull()) { - KeySequenceEditor* editor = new KeySequenceEditor(keyboard_tree, key_shortcut_actions.at(i)); - keyboard_tree->setItemWidget(key_shortcut_items.at(i), 1, editor); - key_shortcut_fields.append(editor); - } - } -} - -void PreferencesDialog::accept() { - bool restart_after_saving = false; - bool reinit_audio = false; - bool reload_language = false; - bool reload_effects = false; - bool reset_ocio_shaders = false; - bool reset_render_threads = false; - - // Validate whether the specified CSS file exists - if (!custom_css_fn->text().isEmpty() && !QFileInfo::exists(custom_css_fn->text())) { - QMessageBox::critical( - this, - tr("Invalid CSS File"), - tr("CSS file '%1' does not exist.").arg(custom_css_fn->text()) - ); - return; - } - - // Validate whether the chosen OCIO configuration file - if (enable_color_management->isChecked()) { - - // Check whether the file exists - if (!QFileInfo::exists(ocio_config_file->text())) { - - QString msg_title = tr("Invalid OpenColorIO Configuration File"); - QString msg_body; - - if (ocio_config_file->text().isEmpty()) { - msg_body = tr("You must specify an OpenColorIO configuration file if color management is enabled."); - } else { - msg_body = tr("OpenColorIO configuration file '%1' does not exist.").arg(ocio_config_file->text()); - } - - QMessageBox::critical( - this, - msg_title, - msg_body - ); - return; - - } else if (olive::config.ocio_config_path != ocio_config_file->text()) { - - // Check whether OCIO can load it - OCIO::ConstConfigRcPtr file_config = TestOCIOConfig(ocio_config_file->text().toUtf8()); - - if (!file_config) { - return; - } - - } - } - - // Validate whether one of the bool options requires a restart - bool bool_requires_restart = false; - for (int i=0;iisChecked() != *bool_value.at(i)) { - bool_requires_restart = true; - break; - } - } - - // Check if any settings will require a restart of Olive (including the bool options determined above) - if (bool_requires_restart - || olive::config.thumbnail_resolution != thumbnail_res_spinbox->value() - || olive::config.waveform_resolution != waveform_res_spinbox->value() - || olive::config.css_path != custom_css_fn->text() - || olive::config.style != static_cast(ui_style->currentData().toInt())) { - - // any changes to these settings will require a restart - ask the user if we should do one now or later - - int ret = QMessageBox::question(this, - "Restart Required", - "Some of the changed settings will require a restart of Olive. Would you like " - "to restart now?", - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); - - if (ret == QMessageBox::Cancel) { - // Return to Preferences dialog without saving any settings - return; - } else if (ret == QMessageBox::Yes) { - - // Check if we can close the current project. If not, we'll treat it as if the user clicked "Cancel". - if (olive::Global->can_close_project()) { - restart_after_saving = true; - } else { - return; - } - } - // Selecting "No" will save the settings and not restart. They will become active next time Olive opens. - - } - - - // Everything checks out, start saving settings from the UI to the backend - olive::config.css_path = custom_css_fn->text(); - olive::config.recording_mode = recordingComboBox->currentIndex() + 1; - olive::config.img_seq_formats = imgSeqFormatEdit->text(); - olive::config.upcoming_queue_size = upcoming_queue_spinbox->value(); - olive::config.upcoming_queue_type = upcoming_queue_type->currentIndex(); - olive::config.previous_queue_size = previous_queue_spinbox->value(); - olive::config.previous_queue_type = previous_queue_type->currentIndex(); - - // Audio settings may require the audio device to be re-initiated. - if (olive::config.preferred_audio_output != audio_output_devices->currentData().toString() - || olive::config.preferred_audio_input != audio_input_devices->currentData().toString() - || olive::config.audio_rate != audio_sample_rate->currentData().toInt()) { - reinit_audio = true; - } - olive::config.preferred_audio_output = audio_output_devices->currentData().toString(); - olive::config.preferred_audio_input = audio_input_devices->currentData().toString(); - olive::config.audio_rate = audio_sample_rate->currentData().toInt(); - - olive::config.effect_textbox_lines = effect_textbox_lines_field->value(); - - // see if the language file should be reloaded (not necessary if the app is restarting anyway) - if (!restart_after_saving - && olive::config.language_file != language_combobox->currentData().toString()) { - reload_language = true; - } - olive::config.language_file = language_combobox->currentData().toString(); - - // Check whether OCIO settings will require a reset of the render threads - if (olive::config.playback_bit_depth != playback_bit_depth->currentIndex() - || olive::config.export_bit_depth != export_bit_depth->currentIndex()) { - reset_render_threads = true; - } - if (olive::config.ocio_config_path != ocio_config_file->text() - || olive::config.ocio_display != ocio_display->currentText() - || olive::config.ocio_view != ocio_view->currentText() - || olive::config.ocio_look != ocio_look->currentData().toString()) { - reset_ocio_shaders = true; - } - if (olive::config.ocio_config_path != ocio_config_file->text()) { - OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(ocio_config_file->text().toUtf8())); - olive::config.ocio_config_path = ocio_config_file->text(); - } - olive::config.enable_color_management = enable_color_management->isChecked(); - olive::config.playback_bit_depth = static_cast(playback_bit_depth->currentIndex()); - olive::config.export_bit_depth = static_cast(export_bit_depth->currentIndex()); - olive::config.ocio_display = ocio_display->currentText(); - olive::config.ocio_default_input_colorspace = ocio_default_input->currentText(); - olive::config.ocio_view = ocio_view->currentText(); - - // We use data here instead of text because there's a "(None)" option with an empty string - olive::config.ocio_look = ocio_look->currentData().toString(); - - - // Set default sequence options - olive::config.default_sequence_width = default_sequence.width(); - olive::config.default_sequence_height = default_sequence.height(); - olive::config.default_sequence_framerate = default_sequence.frame_rate(); - olive::config.default_sequence_audio_frequency = default_sequence.audio_frequency(); - olive::config.default_sequence_audio_channel_layout = default_sequence.audio_layout(); - - // Set all bool options - for (int i=0;iisChecked(); - } - - // Set new style - olive::config.style = static_cast(ui_style->currentData().toInt()); - - // Check if the thumbnail or waveform icon fields have changed, we may need to recreate the previews if so - if (olive::config.thumbnail_resolution != thumbnail_res_spinbox->value() - || olive::config.waveform_resolution != waveform_res_spinbox->value()) { - // we're changing the size of thumbnails and waveforms, so let's delete them and regenerate them next start - - // delete nothing - PreviewDeleteTypes delete_type = DELETE_NONE; - - if (olive::config.thumbnail_resolution != thumbnail_res_spinbox->value()) { - // delete existing thumbnails - olive::config.thumbnail_resolution = thumbnail_res_spinbox->value(); - - // delete only thumbnails - delete_type = DELETE_THUMBNAILS; - } - - if (olive::config.waveform_resolution != waveform_res_spinbox->value()) { - // delete existing waveforms - olive::config.waveform_resolution = waveform_res_spinbox->value(); - - // if we're already deleting thumbnails - if (delete_type == DELETE_THUMBNAILS) { - // delete all - delete_type = DELETE_BOTH; - } else { - // just delete waveforms - delete_type = DELETE_WAVEFORMS; - } - } - - delete_previews(delete_type); - } - - // Save keyboard shortcuts - for (int i=0;iset_action_shortcut(); - } - - QDialog::accept(); - - if (restart_after_saving) { - - // since we already ran can_close_project(), bypass checking again by running set_modified(false) - olive::Global->set_modified(false); - - olive::MainWindow->close(); - - QProcess::startDetached(QApplication::applicationFilePath(), { olive::ActiveProjectFilename }); - } else { - - // Audio settings may require the audio device to be re-initiated. - if (reinit_audio) { - init_audio(); - } - - if (reload_effects) { - panel_effect_controls->Reload(); - } - - // reload language file if it changed - if (reload_language) { - olive::Global->load_translation_from_config(); - } - - if (reset_render_threads) { - if (panel_footage_viewer->seq != nullptr) { - panel_footage_viewer->seq->Close(); - } - panel_footage_viewer->viewer_widget()->get_renderer()->delete_ctx(); - if (panel_sequence_viewer->seq != nullptr) { - panel_sequence_viewer->seq->Close(); - } - panel_sequence_viewer->viewer_widget()->get_renderer()->delete_ctx(); - } else if (reset_ocio_shaders) { - panel_footage_viewer->viewer_widget()->get_renderer()->destroy_ocio(); - panel_sequence_viewer->viewer_widget()->get_renderer()->destroy_ocio(); - } - - } -} - -void PreferencesDialog::reset_default_shortcut() { - QList items = keyboard_tree->selectedItems(); - for (int i=0;iselectedItems().at(i); - static_cast(keyboard_tree->itemWidget(item, 1))->reset_to_default(); - } -} - -void PreferencesDialog::reset_all_shortcuts() { - if (QMessageBox::question( - this, - tr("Confirm Reset All Shortcuts"), - tr("Are you sure you wish to reset all keyboard shortcuts to their defaults?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - for (int i=0;ireset_to_default(); - } - } -} - -bool PreferencesDialog::refine_shortcut_list(const QString &s, QTreeWidgetItem* parent) { - if (parent == nullptr) { - for (int i=0;itopLevelItemCount();i++) { - refine_shortcut_list(s, keyboard_tree->topLevelItem(i)); - } - } else { - parent->setExpanded(!s.isEmpty()); - - bool all_children_are_hidden = !s.isEmpty(); - - for (int i=0;ichildCount();i++) { - QTreeWidgetItem* item = parent->child(i); - if (item->childCount() > 0) { - all_children_are_hidden = refine_shortcut_list(s, item); - } else { - item->setHidden(false); - if (s.isEmpty()) { - all_children_are_hidden = false; - } else { - QString shortcut; - if (keyboard_tree->itemWidget(item, 1) != nullptr) { - shortcut = static_cast(keyboard_tree->itemWidget(item, 1))->keySequence().toString(); - } - if (item->text(0).contains(s, Qt::CaseInsensitive) || shortcut.contains(s, Qt::CaseInsensitive)) { - all_children_are_hidden = false; - } else { - item->setHidden(true); - } - } - } - } - - if (parent->text(0).contains(s, Qt::CaseInsensitive)) all_children_are_hidden = false; - - parent->setHidden(all_children_are_hidden); - - return all_children_are_hidden; - } - return true; -} - -void PreferencesDialog::load_shortcut_file() { - QString fn = QFileDialog::getOpenFileName(this, tr("Import Keyboard Shortcuts")); - if (!fn.isEmpty()) { - QFile f(fn); - if (f.exists() && f.open(QFile::ReadOnly)) { - QByteArray ba = f.readAll(); - f.close(); - for (int i=0;iaction_name()); - if (index == 0 || (index > 0 && ba.at(index-1) == '\n')) { - while (index < ba.size() && ba.at(index) != '\t') index++; - QString ks; - index++; - while (index < ba.size() && ba.at(index) != '\n') { - ks.append(ba.at(index)); - index++; - } - key_shortcut_fields.at(i)->setKeySequence(ks); - } else { - key_shortcut_fields.at(i)->reset_to_default(); - } - } - } else { - QMessageBox::critical( - this, - tr("Error saving shortcuts"), - tr("Failed to open file for reading") - ); - } - } -} - -void PreferencesDialog::save_shortcut_file() { - QString fn = QFileDialog::getSaveFileName(this, tr("Export Keyboard Shortcuts")); - if (!fn.isEmpty()) { - QFile f(fn); - if (f.open(QFile::WriteOnly)) { - bool start = true; - for (int i=0;iexport_shortcut(); - if (!s.isEmpty()) { - if (!start) f.write("\n"); - f.write(s.toUtf8()); - start = false; - } - } - f.close(); - QMessageBox::information(this, tr("Export Shortcuts"), tr("Shortcuts exported successfully")); - } else { - QMessageBox::critical(this, tr("Error saving shortcuts"), tr("Failed to open file for writing")); - } - } -} - -void PreferencesDialog::browse_css_file() { - QString fn = QFileDialog::getOpenFileName(this, tr("Browse for CSS file")); - if (!fn.isEmpty()) { - custom_css_fn->setText(fn); - } -} - -void PreferencesDialog::browse_ocio_config() -{ - QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration")); - if (!fn.isEmpty()) { - ocio_config_file->setText(fn); - enable_color_management->setChecked(true); - } -} - -void PreferencesDialog::update_ocio_view_menu() -{ - update_ocio_view_menu(OCIO::GetCurrentConfig()); -} - -void PreferencesDialog::delete_all_previews() { - if (QMessageBox::question(this, - tr("Delete All Previews"), - tr("Are you sure you want to delete all previews?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - delete_previews(DELETE_BOTH); - QMessageBox::information(this, - tr("Previews Deleted"), - tr("All previews deleted successfully. You may have to re-open your current project for " - "changes to take effect."), - QMessageBox::Ok); - } -} - -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); - - // row counter used to ease adding new rows - int row = 0; - - // General - QWidget* general_tab = new QWidget(this); - QGridLayout* general_layout = new QGridLayout(general_tab); - - // General -> Language - general_layout->addWidget(new QLabel(tr("Language:")), row, 0); - - language_combobox = new QComboBox(); - - // add default language (en-US) - language_combobox->addItem(QLocale::languageToString(QLocale("en-US").language())); - - // add languages from file - QList translation_paths = get_language_paths(); - - // iterate through all language search paths - for (int j=0;jaddItem(QLocale(locale_str).nativeLanguageName(), locale_relative_path); - - if (olive::config.language_file == locale_relative_path) { - language_combobox->setCurrentIndex(language_combobox->count() - 1); - } - } - } - } - - general_layout->addWidget(language_combobox, row, 1, 1, 4); - - row++; - - // General -> Image Sequence Formats - general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0); - - imgSeqFormatEdit = new QLineEdit(general_tab); - imgSeqFormatEdit->setText(olive::config.img_seq_formats); - general_layout->addWidget(imgSeqFormatEdit, row, 1, 1, 4); - - row++; - - // General -> Thumbnail and Waveform Resolution - general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0); - - thumbnail_res_spinbox = new QSpinBox(this); - thumbnail_res_spinbox->setMinimum(0); - thumbnail_res_spinbox->setMaximum(INT_MAX); - thumbnail_res_spinbox->setValue(olive::config.thumbnail_resolution); - general_layout->addWidget(thumbnail_res_spinbox, row, 1); - - general_layout->addWidget(new QLabel(tr("Waveform Resolution:"), this), row, 2); - - waveform_res_spinbox = new QSpinBox(this); - waveform_res_spinbox->setMinimum(0); - waveform_res_spinbox->setMaximum(INT_MAX); - waveform_res_spinbox->setValue(olive::config.waveform_resolution); - general_layout->addWidget(waveform_res_spinbox, row, 3); - - QPushButton* delete_preview_btn = new QPushButton(tr("Delete Previews")); - general_layout->addWidget(delete_preview_btn, row, 4); - connect(delete_preview_btn, SIGNAL(clicked(bool)), this, SLOT(delete_all_previews())); - - row++; - - QHBoxLayout* misc_general = new QHBoxLayout(); - - // General -> Use Software Fallbacks When Possible - QCheckBox* use_software_fallbacks_checkbox = new QCheckBox(tr("Use Software Fallbacks When Possible")); - AddBoolPair(use_software_fallbacks_checkbox, &olive::config.use_software_fallback, true); - misc_general->addWidget(use_software_fallbacks_checkbox); - - // General -> Don't Use Proxies When Exporting - QCheckBox* dont_use_proxies_when_exporting = new QCheckBox(tr("Don't Use Proxies When Exporting")); - dont_use_proxies_when_exporting->setToolTip(tr("Use originals instead of proxies when exporting")); - AddBoolPair(dont_use_proxies_when_exporting, &olive::config.dont_use_proxies_on_export); - misc_general->addWidget(dont_use_proxies_when_exporting); - - // 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())); - misc_general->addWidget(default_sequence_settings); - - general_layout->addLayout(misc_general, row, 0, 1, 5); - - row++; - - tabWidget->addTab(general_tab, tr("General")); - - // Behavior - QWidget* behavior_tab = new QWidget(this); - tabWidget->addTab(behavior_tab, tr("Behavior")); - - ColumnedGridLayout* behavior_tab_layout = new ColumnedGridLayout(behavior_tab, 2); - - QCheckBox* add_default_effects_to_clips = new QCheckBox(tr("Add Default Effects to New Clips")); - AddBoolPair(add_default_effects_to_clips, &olive::config.add_default_effects_to_clips); - behavior_tab_layout->Add(add_default_effects_to_clips); - - QCheckBox* auto_seek_to_beginning = new QCheckBox(tr("Automatically Seek to the Beginning When Playing at the End of a Sequence")); - AddBoolPair(auto_seek_to_beginning, &olive::config.auto_seek_to_beginning); - behavior_tab_layout->Add(auto_seek_to_beginning); - - QCheckBox* selecting_also_seeks = new QCheckBox(tr("Selecting Also Seeks")); - AddBoolPair(selecting_also_seeks, &olive::config.select_also_seeks); - behavior_tab_layout->Add(selecting_also_seeks); - - QCheckBox* edit_tool_also_seeks = new QCheckBox(tr("Edit Tool Also Seeks")); - AddBoolPair(edit_tool_also_seeks, &olive::config.edit_tool_also_seeks); - behavior_tab_layout->Add(edit_tool_also_seeks); - - QCheckBox* edit_tool_selects_links = new QCheckBox(tr("Edit Tool Selects Links")); - AddBoolPair(edit_tool_selects_links, &olive::config.edit_tool_selects_links); - behavior_tab_layout->Add(edit_tool_selects_links); - - QCheckBox* seek_also_selects = new QCheckBox(tr("Seek Also Selects")); - AddBoolPair(seek_also_selects, &olive::config.seek_also_selects); - behavior_tab_layout->Add(seek_also_selects); - - QCheckBox* seek_to_end_of_pastes = new QCheckBox(tr("Seek to the End of Pastes")); - AddBoolPair(seek_to_end_of_pastes, &olive::config.paste_seeks); - behavior_tab_layout->Add(seek_to_end_of_pastes); - - QCheckBox* scroll_wheel_zooms = new QCheckBox(tr("Scroll Wheel Zooms")); - scroll_wheel_zooms->setToolTip(tr("Hold CTRL to toggle this setting")); - AddBoolPair(scroll_wheel_zooms, &olive::config.scroll_zooms); - behavior_tab_layout->Add(scroll_wheel_zooms); - - QCheckBox* invert_timeline_scroll_axes = new QCheckBox(tr("Invert Timeline Scroll Axes")); - AddBoolPair(invert_timeline_scroll_axes, &olive::config.invert_timeline_scroll_axes); - behavior_tab_layout->Add(invert_timeline_scroll_axes); - - QCheckBox* enable_drag_files_to_timeline = new QCheckBox(tr("Enable Drag Files to Timeline")); - AddBoolPair(enable_drag_files_to_timeline, &olive::config.enable_drag_files_to_timeline); - behavior_tab_layout->Add(enable_drag_files_to_timeline); - - QCheckBox* autoscale_by_default = new QCheckBox(tr("Auto-Scale By Default")); - AddBoolPair(autoscale_by_default, &olive::config.autoscale_by_default); - behavior_tab_layout->Add(autoscale_by_default); - - QCheckBox* enable_seek_to_import = new QCheckBox(tr("Auto-Seek to Imported Clips")); - AddBoolPair(enable_seek_to_import, &olive::config.enable_seek_to_import); - behavior_tab_layout->Add(enable_seek_to_import); - - QCheckBox* enable_audio_scrubbing = new QCheckBox(tr("Audio Scrubbing")); - AddBoolPair(enable_audio_scrubbing, &olive::config.enable_audio_scrubbing); - behavior_tab_layout->Add(enable_audio_scrubbing); - - QCheckBox* enable_drop_on_media_to_replace = new QCheckBox(tr("Drop Files on Media to Replace")); - AddBoolPair(enable_drop_on_media_to_replace, &olive::config.drop_on_media_to_replace); - behavior_tab_layout->Add(enable_drop_on_media_to_replace); - - QCheckBox* enable_hover_focus = new QCheckBox(tr("Enable Hover Focus")); - AddBoolPair(enable_hover_focus, &olive::config.hover_focus); - behavior_tab_layout->Add(enable_hover_focus); - - QCheckBox* set_name_and_marker = new QCheckBox(tr("Ask For Name When Setting Marker")); - AddBoolPair(set_name_and_marker, &olive::config.set_name_with_marker); - behavior_tab_layout->Add(set_name_and_marker); - - // Appearance - QWidget* appearance_tab = new QWidget(this); - tabWidget->addTab(appearance_tab, tr("Appearance")); - - row = 0; - - QGridLayout* appearance_layout = new QGridLayout(appearance_tab); - - // Appearance -> Theme - appearance_layout->addWidget(new QLabel(tr("Theme")), row, 0); - - ui_style = new QComboBox(); - ui_style->addItem(tr("Olive Dark (Default)"), olive::styling::kOliveDefaultDark); - ui_style->addItem(tr("Olive Light"), olive::styling::kOliveDefaultLight); - ui_style->addItem(tr("Native"), olive::styling::kNativeDarkIcons); - ui_style->addItem(tr("Native (Light Icons)"), olive::styling::kNativeLightIcons); - ui_style->setCurrentIndex(olive::config.style); - appearance_layout->addWidget(ui_style, row, 1, 1, 2); - - row++; - -#ifdef Q_OS_WIN - // 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::config.use_native_menu_styling, true); - appearance_layout->addWidget(native_menus, row, 0, 1, 3); - - row++; -#endif - - // Appearance -> Custom CSS - appearance_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0); - - custom_css_fn = new QLineEdit(general_tab); - custom_css_fn->setText(olive::config.css_path); - appearance_layout->addWidget(custom_css_fn, row, 1); - - QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); - connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file())); - appearance_layout->addWidget(custom_css_browse, row, 2); - - row++; - - // Appearance -> Effect Textbox Lines - appearance_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0); - - effect_textbox_lines_field = new QSpinBox(general_tab); - effect_textbox_lines_field->setMinimum(1); - effect_textbox_lines_field->setValue(olive::config.effect_textbox_lines); - appearance_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 2); - - row++; - - // Playback - QWidget* playback_tab = new QWidget(this); - QVBoxLayout* playback_tab_layout = new QVBoxLayout(playback_tab); - - // Playback -> Memory Usage - QGroupBox* memory_usage_group = new QGroupBox(playback_tab); - memory_usage_group->setTitle(tr("Memory Usage")); - QGridLayout* memory_usage_layout = new QGridLayout(memory_usage_group); - memory_usage_layout->addWidget(new QLabel(tr("Upcoming Frame Queue:"), playback_tab), 0, 0); - upcoming_queue_spinbox = new QDoubleSpinBox(playback_tab); - upcoming_queue_spinbox->setValue(olive::config.upcoming_queue_size); - memory_usage_layout->addWidget(upcoming_queue_spinbox, 0, 1); - upcoming_queue_type = new QComboBox(playback_tab); - upcoming_queue_type->addItem(tr("frames")); - upcoming_queue_type->addItem(tr("seconds")); - upcoming_queue_type->setCurrentIndex(olive::config.upcoming_queue_type); - memory_usage_layout->addWidget(upcoming_queue_type, 0, 2); - memory_usage_layout->addWidget(new QLabel(tr("Previous Frame Queue:"), playback_tab), 1, 0); - previous_queue_spinbox = new QDoubleSpinBox(playback_tab); - previous_queue_spinbox->setValue(olive::config.previous_queue_size); - memory_usage_layout->addWidget(previous_queue_spinbox, 1, 1); - previous_queue_type = new QComboBox(playback_tab); - previous_queue_type->addItem(tr("frames")); - previous_queue_type->addItem(tr("seconds")); - previous_queue_type->setCurrentIndex(olive::config.previous_queue_type); - memory_usage_layout->addWidget(previous_queue_type, 1, 2); - playback_tab_layout->addWidget(memory_usage_group); - - tabWidget->addTab(playback_tab, tr("Playback")); - - // Audio - QWidget* audio_tab = new QWidget(this); - - QGridLayout* audio_tab_layout = new QGridLayout(audio_tab); - - row = 0; - - // Audio -> Output Device - - audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0); - - audio_output_devices = new QComboBox(); - audio_output_devices->addItem(tr("Default"), ""); - - // list all available audio output devices - QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); - bool found_preferred_device = false; - for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); - if (!found_preferred_device - && devs.at(i).deviceName() == olive::config.preferred_audio_output) { - audio_output_devices->setCurrentIndex(audio_output_devices->count()-1); - found_preferred_device = true; - } - } - - audio_tab_layout->addWidget(audio_output_devices, row, 1); - - row++; - - // Audio -> Input Device - - audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0); - - audio_input_devices = new QComboBox(); - audio_input_devices->addItem(tr("Default"), ""); - - // list all available audio input devices - devs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); - found_preferred_device = false; - for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); - if (!found_preferred_device - && devs.at(i).deviceName() == olive::config.preferred_audio_input) { - audio_input_devices->setCurrentIndex(audio_input_devices->count()-1); - found_preferred_device = true; - } - } - - audio_tab_layout->addWidget(audio_input_devices, row, 1); - - row++; - - // Audio -> Sample Rate - - audio_tab_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); - - audio_sample_rate = new QComboBox(); - combobox_audio_sample_rates(audio_sample_rate); - for (int i=0;icount();i++) { - if (audio_sample_rate->itemData(i).toInt() == olive::config.audio_rate) { - audio_sample_rate->setCurrentIndex(i); - break; - } - } - - audio_tab_layout->addWidget(audio_sample_rate, row, 1); - - row++; - - // Audio -> Audio Recording - audio_tab_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0); - - recordingComboBox = new QComboBox(general_tab); - recordingComboBox->addItem(tr("Mono")); - recordingComboBox->addItem(tr("Stereo")); - recordingComboBox->setCurrentIndex(olive::config.recording_mode - 1); - audio_tab_layout->addWidget(recordingComboBox, row, 1); - - row++; - - tabWidget->addTab(audio_tab, tr("Audio")); - - // - // COLOR MANAGEMENT - // - - QWidget* color_management_tab = new QWidget(); - - QGridLayout* color_management_layout = new QGridLayout(color_management_tab); - - row = 0; - - // COLOR MANAGEMENT -> Enable Color Management - enable_color_management = new QCheckBox(tr("Enable Color Management")); - enable_color_management->setChecked(olive::config.enable_color_management); - color_management_layout->addWidget(enable_color_management, row, 0); - - row++; - - QGroupBox* opencolorio_groupbox = new QGroupBox(); - QGridLayout* opencolorio_groupbox_layout = new QGridLayout(opencolorio_groupbox); - - // COLOR MANAGEMENT -> OpenColorIO Config File - opencolorio_groupbox_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), 0, 0); - - ocio_config_file = new QLineEdit(); - ocio_config_file->setText(olive::config.ocio_config_path); - connect(ocio_config_file, SIGNAL(textChanged(const QString &)), this, SLOT(update_ocio_config(const QString&))); - opencolorio_groupbox_layout->addWidget(ocio_config_file, 0, 1, 1, 4); - - QPushButton* ocio_config_browse_btn = new QPushButton(tr("Browse")); - connect(ocio_config_browse_btn, SIGNAL(clicked(bool)), this, SLOT(browse_ocio_config())); - opencolorio_groupbox_layout->addWidget(ocio_config_browse_btn, 0, 5); - - // COLOR MANAGEMENT -> Default Input Color Space - ocio_default_input = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Default Input Color Space:")), 1, 0); - opencolorio_groupbox_layout->addWidget(ocio_default_input, 1, 1, 1, 5); - - // COLOR MANAGEMENT -> Display - ocio_display = new QComboBox(); - connect(ocio_display, SIGNAL(currentIndexChanged(int)), this, SLOT(update_ocio_view_menu())); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Display:")), 2, 0); - opencolorio_groupbox_layout->addWidget(ocio_display, 2, 1); - - // COLOR MANAGEMENT -> View - ocio_view = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("View:")), 2, 2); - opencolorio_groupbox_layout->addWidget(ocio_view, 2, 3); - - // COLOR MANAGEMENT -> Look - ocio_look = new QComboBox(); - opencolorio_groupbox_layout->addWidget(new QLabel(tr("Look:")), 2, 4); - opencolorio_groupbox_layout->addWidget(ocio_look, 2, 5); - - color_management_layout->addWidget(opencolorio_groupbox, row, 0); - - row++; - - // COLOR MANAGEMENT -> Bit Depth - QGroupBox* bit_depth_groupbox = new QGroupBox(tr("Bit Depth")); - QGridLayout* bit_depth_groupbox_layout = new QGridLayout(bit_depth_groupbox); - - // COLOR MANAGEMENT -> Bit Depth -> Playback - playback_bit_depth = new QComboBox(); - for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); - } - playback_bit_depth->setCurrentIndex(olive::config.playback_bit_depth); - bit_depth_groupbox_layout->addWidget(new QLabel(tr("Playback (Offline):")), 0, 0); - bit_depth_groupbox_layout->addWidget(playback_bit_depth, 0, 1); - - // COLOR MANAGEMENT -> Bit Depth -> Export - export_bit_depth = new QComboBox(); - for (int i=0;iaddItem(olive::pixel_formats.at(i).name, i); - } - export_bit_depth->setCurrentIndex(olive::config.export_bit_depth); - bit_depth_groupbox_layout->addWidget(new QLabel(tr("Export (Online):")), 0, 2); - bit_depth_groupbox_layout->addWidget(export_bit_depth, 0, 3); - - color_management_layout->addWidget(bit_depth_groupbox, row, 0); - - - - //row++; - - populate_ocio_menus(OCIO::GetCurrentConfig()); - - tabWidget->addTab(color_management_tab, tr("Color Management")); - - // Shortcuts - QWidget* shortcut_tab = new QWidget(this); - - QVBoxLayout* shortcut_layout = new QVBoxLayout(shortcut_tab); - - QLineEdit* key_search_line = new QLineEdit(shortcut_tab); - key_search_line->setPlaceholderText(tr("Search for action or shortcut")); - connect(key_search_line, SIGNAL(textChanged(const QString &)), this, SLOT(refine_shortcut_list(const QString &))); - - shortcut_layout->addWidget(key_search_line); - - keyboard_tree = new QTreeWidget(shortcut_tab); - QTreeWidgetItem* tree_header = keyboard_tree->headerItem(); - tree_header->setText(0, tr("Action")); - tree_header->setText(1, tr("Shortcut")); - shortcut_layout->addWidget(keyboard_tree); - - QHBoxLayout* reset_shortcut_layout = new QHBoxLayout(shortcut_tab); - - QPushButton* import_shortcut_button = new QPushButton(tr("Import"), shortcut_tab); - reset_shortcut_layout->addWidget(import_shortcut_button); - connect(import_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(load_shortcut_file())); - - QPushButton* export_shortcut_button = new QPushButton(tr("Export"), shortcut_tab); - reset_shortcut_layout->addWidget(export_shortcut_button); - connect(export_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(save_shortcut_file())); - - reset_shortcut_layout->addStretch(); - - QPushButton* reset_selected_shortcut_button = new QPushButton(tr("Reset Selected"), shortcut_tab); - reset_shortcut_layout->addWidget(reset_selected_shortcut_button); - connect(reset_selected_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_default_shortcut())); - - QPushButton* reset_all_shortcut_button = new QPushButton(tr("Reset All"), shortcut_tab); - reset_shortcut_layout->addWidget(reset_all_shortcut_button); - connect(reset_all_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_all_shortcuts())); - - shortcut_layout->addLayout(reset_shortcut_layout); - - tabWidget->addTab(shortcut_tab, tr("Keyboard")); - - verticalLayout->addWidget(tabWidget); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(this); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - - verticalLayout->addWidget(buttonBox); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); -} diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h deleted file mode 100644 index 721a2b505..000000000 --- a/dialogs/preferencesdialog.h +++ /dev/null @@ -1,432 +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 PREFERENCESDIALOG_H -#define PREFERENCESDIALOG_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -#include "timeline/sequence.h" - -class KeySequenceEditor; - -/** - * @brief The PreferencesDialog class - * - * A dialog for the global application settings. Mostly an interface for Config. Can be loaded from any part of the - * application. - */ -class PreferencesDialog : public QDialog -{ - Q_OBJECT - -public: - /** - * @brief PreferencesDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow. - */ - explicit PreferencesDialog(QWidget *parent = nullptr); - -private slots: - /** - * @brief Override of accept to save preferences to Config. - */ - virtual void accept() override; - - /** - * @brief Reset all selected shortcuts in keyboard_tree to their defaults - */ - void reset_default_shortcut(); - - /** - * @brief Reset all shortcuts indiscriminately to their defaults - * - * This is safe to call directly as it'll ask the user if they wish to do so before it resets. - */ - void reset_all_shortcuts(); - - /** - * @brief Shows/hides shortcut entries according to a shortcut query. - * - * This function can be directly connected to QLineEdit::textChanged() for simplicity. - * - * @param s - * - * The search query to compare shortcut names to. - * - * @param parent - * - * This is used as the function calls itself recursively to traverse the menu item hierarchy. This should be left as - * nullptr when called externally. - * - * @return - * - * Value used as function calls itself recursively to determine if a menu parent has any children that are not hidden. - * If so, TRUE is returned so the parent is shown too (even if it doesn't match the search query). If not, FALSE is - * returned so the parent is hidden. - */ - bool refine_shortcut_list(const QString &s, QTreeWidgetItem* parent = nullptr); - - /** - * @brief Show a file dialog to load an external shortcut preset from file - */ - void load_shortcut_file(); - - /** - * @brief Show a file dialog to save an external shortcut preset from file - */ - void save_shortcut_file(); - - /** - * @brief Delete all previews (waveform and thumbnail cache) - */ - void delete_all_previews(); - - // Browse for file functionns - /** - * @brief Show a file dialog to browse for an external CSS file to load for styling the application. - */ - void browse_css_file(); - void browse_ocio_config(); - - // OCIO function - void update_ocio_view_menu(); - void update_ocio_view_menu(OCIO::ConstConfigRcPtr config); - void update_ocio_config(const QString&); - - /** - * @brief Shows a NewSequenceDialog attached to default_sequence - */ - void edit_default_sequence_settings(); - -private: - - /** - * @brief Create and arrange all UI widgets - */ - void setup_ui(); - - /** - * @brief Populate keyboard shortcut panel with keyboard shortcuts from the menu bar - * - * @param menu - * - * A reference to the main application's menu bar. Usually MainWindow::menuBar(). - */ - void setup_kbd_shortcuts(QMenuBar* menu); - - /** - * @brief Internal function called by setup_kbd_shortcuts() to traverse down the menu bar's hierarchy and populate the - * shortcut panel. - * - * This function will call itself recursively as it finds submenus belong to the menu provided. It will also create - * QTreeWidgetItems as children of the parent item provided, either using them as parents themselves for submenus - * or attaching a KeySequenceEditor to them for shortcut editing. - * - * @param menu - * - * The current menu to traverse down. - * - * @param parent - * - * The parent item to add QTreeWidgetItems to. - */ - void setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent); - - enum PreviewDeleteTypes { - DELETE_NONE, - DELETE_THUMBNAILS, - DELETE_WAVEFORMS, - DELETE_BOTH - }; - - // used to delete previews - // type can be: 't' for thumbnails, 'w' for waveforms, or 1 for all - /** - * @brief Delete disk cached preview files (thumbnails, waveforms, etc.) - * - * @param type - * - * The types of previews to delete. - */ - void delete_previews(PreviewDeleteTypes type); - - void populate_ocio_menus(OCIO::ConstConfigRcPtr config); - - /** - * @brief UI widget for editing the CSS filename - */ - QLineEdit* custom_css_fn; - - /** - * @brief UI widget for editing the list of extensions to detect image sequences from - */ - QLineEdit* imgSeqFormatEdit; - - /** - * @brief UI widget for editing the recording channels - */ - QComboBox* recordingComboBox; - - - /** - * @brief UI widget for editing keyboard shortcuts - */ - QTreeWidget* keyboard_tree; - - /** - * @brief UI widget for editing the upcoming queue size - */ - QDoubleSpinBox* upcoming_queue_spinbox; - - /** - * @brief UI widget for editing the upcoming queue type - */ - QComboBox* upcoming_queue_type; - - /** - * @brief UI widget for editing the previous queue size - */ - QDoubleSpinBox* previous_queue_spinbox; - - /** - * @brief UI widget for editing the previous queue type - */ - QComboBox* previous_queue_type; - - /** - * @brief UI widget for editing the size of textboxes in the EffectControls panel - */ - QSpinBox* effect_textbox_lines_field; - - /** - * @brief UI widget for selecting the output audio device - */ - QComboBox* audio_output_devices; - - /** - * @brief UI widget for selecting the input audio device - */ - QComboBox* audio_input_devices; - - /** - * @brief UI widget for selecting the audio sampling rates - */ - QComboBox* audio_sample_rate; - - /** - * @brief UI widget for selecting the UI language - */ - QComboBox* language_combobox; - - /** - * @brief UI widget for selecting the resolution of the thumbnails to generate - */ - QSpinBox* thumbnail_res_spinbox; - - /** - * @brief UI widget for selecting the resolution of the waveforms to generate - */ - QSpinBox* waveform_res_spinbox; - - QCheckBox* enable_color_management; - QLineEdit* ocio_config_file; - QComboBox* ocio_default_input; - QComboBox* ocio_display; - QComboBox* ocio_view; - QComboBox* ocio_look; - QComboBox* playback_bit_depth; - QComboBox* export_bit_depth; - - /** - * @brief UI widget for selecting the current UI style - */ - QComboBox* ui_style; - - /** - * @brief Stored default Sequence object - * - * Default Sequence settings are loaded into an actual Sequence object that can be loaded into NewSequenceDialog - * for the sake of familiarity with the user. - */ - Sequence default_sequence; - - /** - * @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and - * key_shortcut_fields) - */ - QVector 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 Tests an OpenColorIO configuration file to determine whether it's valid and throws a messagebox if not - * - * @param url - * - * URL to the OpenColorIO configuration file. - * - * @return - * - * A OCIO::ConstConfigRcPtr config pointer if the configuration file is valid, nullptr if not. - */ - OCIO::ConstConfigRcPtr TestOCIOConfig(const QString& url); - - /** - * @brief Add an automated QCheckBox+boolean value pair - * - * Many preferences are simple true/false (or on/off) options. Rather than adding a QCheckBox for each one and - * manually setting its checked value to the configuration setting (and vice versa when saving), this convenience - * function will add it to an automated set of checkboxes, automatically setting the checked state to the current - * setting, and then saving the new checked state back to the setting when the user accepts the changes (clicks OK). - * - * @param ui - * - * A valid QCheckBox item. This function does not take ownership of the QWidget or place it in a layout anywhere. - * - * @param value - * - * A pointer to the Boolean value this QCheckBox should be shared with. The QCheckBox widget's checked state will be - * set to the value of this pointer. - * - * @param restart_required - * - * Defaults to FALSE, set this to TRUE if changing this setting should prompt the user for a restart of Olive before - * the setting change takes effect. - */ - void AddBoolPair(QCheckBox* ui, bool* value, bool restart_required = false); - - /** - * @brief Internal array managed by AddBoolPair(). Do not access this directly. - */ - QVector bool_ui; - - /** - * @brief Internal array managed by AddBoolPair(). Do not access this directly. - */ - QVector bool_value; - - /** - * @brief Internal array managed by AddBoolPair(). Do not access this directly. - */ - QVector bool_restart_required; -}; - -/** - * @brief The KeySequenceEditor class - * - * Simple derived class of QKeySequenceEdit that attaches to a QAction and provides functions for transferring - * keyboard shortcuts to and from it. - */ -class KeySequenceEditor : public QKeySequenceEdit { - Q_OBJECT -public: - /** - * @brief KeySequenceEditor Constructor - * - * @param parent - * - * QWidget parent. - * - * @param a - * - * The QAction to link to. This cannot be changed throughout the lifetime of a KeySequenceEditor. - */ - KeySequenceEditor(QWidget *parent, QAction* a); - - /** - * @brief Sets the attached QAction's shortcut to the shortcut entered in this field. - * - * This is not done automatically in case the user cancels out of the Preferences dialog, in which case the - * expectation is that the changes made will not be saved. Therefore, this needs to be triggered manually when - * PreferencesDialog saves. - */ - void set_action_shortcut(); - - /** - * @brief Set this shortcut back to the QAction's default shortcut - * - * Each QAction contains the default shortcut in its `property("default")` and can be used to restore the default - * "hard-coded" shortcut with this function. - * - * This function does not save the default shortcut back into the QAction, it simply loads the default shortcut from - * the QAction into this edit field. To save it into the QAction, it's necessary to call set_action_shortcut() after - * calling this function. - */ - void reset_to_default(); - - /** - * @brief Return attached QAction's unique ID - * - * Each of Olive's menu actions has a unique string ID (that, unlike the text, is not translated) for matching with - * an external shortcut configuration file. The ID is stored in the QAction's `property("id")`. This function returns - * that ID. - * - * @return - * - * The QAction's unique ID. - */ - QString action_name(); - - /** - * @brief Serialize this shortcut entry into a string that can be saved to a file - * - * @return - * - * A string serialization of this shortcut. The format is "[ID]\t[SEQUENCE]" where [ID] is the attached QAction's - * unique identifier and [SEQUENCE] is the current keyboard shortcut in the field (NOT necessarily the shortcut in - * the QAction). If the entered shortcut is the same as the QAction's default shortcut, the return value is empty - * because a default shortcut does not need to be saved to a file. - */ - QString export_shortcut(); -private: - /** - * @brief Internal reference to the linked QAction - */ - QAction* action; -}; - -#endif // PREFERENCESDIALOG_H diff --git a/dialogs/proxydialog.cpp b/dialogs/proxydialog.cpp deleted file mode 100644 index 21534ca9f..000000000 --- a/dialogs/proxydialog.cpp +++ /dev/null @@ -1,184 +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 "proxydialog.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "project/proxygenerator.h" -#include "project/footage.h" -#include "ui/mainwindow.h" -#include "global/global.h" - -ProxyDialog::ProxyDialog(QWidget *parent, const QVector &media) : - QDialog(parent), - selected_media(media) -{ - // set dialog title - setWindowTitle(tr("Create Proxy")); - - // set proxy folder name to "Proxy", depending on the user's language - proxy_folder_name = tr("Proxy"); - - // set up dialog's layout - QGridLayout* layout = new QGridLayout(this); - - // set the video dimensions of the proxy - layout->addWidget(new QLabel(tr("Dimensions:"), this), 0, 0); - - size_combobox = new QComboBox(this); - size_combobox->addItem(tr("Same Size as Source"), 1.0); - size_combobox->addItem(tr("Half Resolution (1/2)"), 0.5); - size_combobox->addItem(tr("Quarter Resolution (1/4)"), 0.25); - size_combobox->addItem(tr("Eighth Resolution (1/8)"), 0.125); - size_combobox->addItem(tr("Sixteenth Resolution (1/16)"), 0.0625); - layout->addWidget(size_combobox, 0, 1); - - // set the desired format of the proxy to create - layout->addWidget(new QLabel(tr("Format:"), this), 1, 0); - - format_combobox = new QComboBox(this); - format_combobox->addItem(tr("ProRes HQ")); - // format_combobox->addItem(tr("ProRes SQ")); - // format_combobox->addItem(tr("ProRes LT")); - // format_combobox->addItem(tr("DNxHD")); - // format_combobox->addItem(tr("H.264")); - layout->addWidget(format_combobox, 1, 1); - - // set the location to place the proxies - layout->addWidget(new QLabel(tr("Location:"), this), 2, 0); - - location_combobox = new QComboBox(this); - location_combobox->addItem(tr("Same as Source (in \"%1\" folder)").arg(proxy_folder_name)); - location_combobox->addItem(""); - connect(location_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(location_changed(int))); - layout->addWidget(location_combobox, 2, 1); - - // location_changed will set the default "location" items - location_changed(0); - - // set up dialog buttons - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - buttons->setCenterButtons(true); - layout->addWidget(buttons, 3, 0, 1, 2); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); -} - -void ProxyDialog::accept() { - QVector info_list; - - // set to TRUE if any existing proxies exist and the user chooses to overwrite all of them - bool overwrite_all_existing = false; - - for (int i=0;icurrentData().toDouble(); - - Footage* footage = selected_media.at(i)->to_footage(); - - QString base_footage_fn = QFileInfo(footage->url).baseName(); - - // TEMPORARILY hardcoded proxy format - base_footage_fn.append(".mov"); - - // determine path from input - if (custom_location.isEmpty()) { - // use same as source (proxy subfolder) - - // generate full path from footage path and proxy_folder_name's translated "Proxy" - info.path = QDir(QFileInfo(footage->url).dir().filePath(proxy_folder_name)).filePath(base_footage_fn); - } else { - // use existing location - info.path = QDir(custom_location).filePath(base_footage_fn); - } - - // if the proposed proxy file already exists & user didn't select YesToAll box - if (QFileInfo::exists(info.path) && !overwrite_all_existing){ - int rtn = QMessageBox::warning( this, - tr("Proxy file exists"), - tr("The file \"%1\" already exists. Do you wish to replace it?").arg(info.path), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No); - - switch (rtn){ - case QMessageBox::Yes: - // continue as normal, proxy generator will automatically overwrite this file - break; - case QMessageBox::YesToAll: - // continue as normal, also set variable so that above messagebox is not shown again - overwrite_all_existing = true; - break; - case QMessageBox::No: - // return to dialog without closing or starting any proxy generation - return; - } - } - - // send to proxy generator thread - info_list.append(info); - } - - // all proxy info checks out, queue it with the proxy generator - for (int i=0;ito_footage(); - footage->proxy = true; - footage->proxy_path.clear(); - - olive::proxy_generator.queue(info_list.at(i)); - } - - olive::Global->set_modified(true); - - QDialog::accept(); -} - -void ProxyDialog::location_changed(int i) { - // clear any custom location - either the user picked a new one or chose not a custom location - custom_location.clear(); - - if (i == 1) { - // if the user picked a custom location, ask which directory - QString s = QFileDialog::getExistingDirectory(this); - - if (s.isEmpty()) { - // if the user didn't input anything, set the combobox back to default - location_combobox->setCurrentIndex(0); - } else { - // if the user chose a custom location, set the combobox text to it and custom_location for future usage - location_combobox->setItemText(1, s); - custom_location = s; - } - } else { - // if the user doesn't picks something other than custom location, set this string back to default for clearer UX - location_combobox->setItemText(1, tr("Custom Location")); - } -} diff --git a/dialogs/proxydialog.h b/dialogs/proxydialog.h deleted file mode 100644 index 45933e485..000000000 --- a/dialogs/proxydialog.h +++ /dev/null @@ -1,107 +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 PROXYDIALOG_H -#define PROXYDIALOG_H - -#include -#include -#include - -#include "project/media.h" - -/** - * @brief The ProxyDialog class - * - * Dialog to set up proxy generation of footage. This dialog can be called from anywhere provided it's given a valid - * array of Media and will start all proxy generation. - */ -class ProxyDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief ProxyDialog Constructor - * @param parent - * - * Parent widget to become modal to. - * - * @param footage - * - * List of Footage items to process. - */ - ProxyDialog(QWidget* parent, const QVector &media); -public slots: - /** - * @brief Accept changes - * - * Called when the user clicks OK on the dialog. Verifies all proxies, asking the user whether they want to overwrite - * existing proxies if necessary, and if everything is valid, queues the footage with ProxyGenerator. - */ - virtual void accept() override; -private: - /** - * @brief User's desired dimensions - * - * Always a fraction of the original video size (e.g. 1/2, 1/4, 1/8, etc.) - */ - QComboBox* size_combobox; - - /** - * @brief User's desired proxy format - * - * e.g. ProRes, DNxHD, etc. - */ - QComboBox* format_combobox; - - /** - * @brief Allows users to set the directory to store proxies in - */ - QComboBox* location_combobox; - - /** - * @brief Stores the custom location to store proxies if the user sets a custom location - */ - QString custom_location; - - /** - * @brief Stores the default subdirectory to be made next to the source (dependent on the user's language) - * - * "Proxy" in en-US. - */ - QString proxy_folder_name; - - /** - * @brief Stored list of footage to make proxies for - */ - QVector selected_media; -private slots: - /** - * @brief Slot when the user changes the location - * - * Triggered when the user changes the index in the location combobox. - * - * @param i - * - * location_combobox's new selected index - */ - void location_changed(int i); -}; - -#endif // PROXYDIALOG_H diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp deleted file mode 100644 index 7fc237901..000000000 --- a/dialogs/replaceclipmediadialog.cpp +++ /dev/null @@ -1,130 +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 "replaceclipmediadialog.h" - -#include -#include -#include -#include - -#include "panels/panels.h" -#include "undo/undostack.h" -#include "rendering/cacher.h" -#include "undo/undo.h" - -ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media) : - QDialog(parent), - media(old_media) -{ - setWindowTitle(tr("Replace clips using \"%1\"").arg(old_media->get_name())); - - resize(300, 400); - - QVBoxLayout* layout = new QVBoxLayout(this); - - layout->addWidget(new QLabel(tr("Select which media you want to replace this media's clips with:"), this)); - - tree = new QTreeView(this); - - layout->addWidget(tree); - - use_same_media_in_points = new QCheckBox(tr("Keep the same media in-points"), this); - use_same_media_in_points->setChecked(true); - layout->addWidget(use_same_media_in_points); - - QHBoxLayout* buttons = new QHBoxLayout(); - - buttons->addStretch(); - - QPushButton* replace_button = new QPushButton(tr("Replace"), this); - connect(replace_button, SIGNAL(clicked(bool)), this, SLOT(accept())); - buttons->addWidget(replace_button); - - QPushButton* cancel_button = new QPushButton(tr("Cancel"), this); - connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject())); - buttons->addWidget(cancel_button); - - buttons->addStretch(); - - layout->addLayout(buttons); - - tree->setModel(&olive::project_model); -} - -void ReplaceClipMediaDialog::accept() { - QModelIndexList selected_items = tree->selectionModel()->selectedRows(); - if (selected_items.size() != 1) { - QMessageBox::critical( - this, - tr("No media selected"), - tr("Please select a media to replace with or click 'Cancel'."), - QMessageBox::Ok - ); - } else { - Media* new_item = static_cast(selected_items.at(0).internalPointer()); - if (media == new_item) { - QMessageBox::critical( - this, - tr("Same media selected"), - tr("You selected the same media that you're replacing. Please select a different one or click 'Cancel'."), - QMessageBox::Ok - ); - } else if (new_item->get_type() == MEDIA_TYPE_FOLDER) { - QMessageBox::critical( - this, - tr("Folder selected"), - tr("You cannot replace footage with a folder."), - QMessageBox::Ok - ); - } else { - - SequencePtr top_sequence = Timeline::GetTopSequence(); - - if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && top_sequence == new_item->to_sequence()) { - QMessageBox::critical( - this, - tr("Active sequence selected"), - tr("You cannot insert a sequence into itself."), - QMessageBox::Ok - ); - } else { - ReplaceClipMediaCommand* rcmc = new ReplaceClipMediaCommand( - media, - new_item, - use_same_media_in_points->isChecked() - ); - - QVector all_clips = top_sequence->GetAllClips(); - for (int i=0;imedia() == media) { - rcmc->clips.append(c); - } - } - - olive::undo_stack.push(rcmc); - - QDialog::accept(); - } - - } - } -} diff --git a/dialogs/replaceclipmediadialog.h b/dialogs/replaceclipmediadialog.h deleted file mode 100644 index ec93f46c4..000000000 --- a/dialogs/replaceclipmediadialog.h +++ /dev/null @@ -1,82 +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 REPLACECLIPMEDIADIALOG_H -#define REPLACECLIPMEDIADIALOG_H - -#include -#include -#include - -#include "ui/sourcetable.h" -#include "project/projectelements.h" - -/** - * @brief The ReplaceClipMediaDialog class - * - * A dialog to replace all Clips using a certain Media with a different Media. This dialog can be run from anywhere - * provided it's given a valid Media object. - */ -class ReplaceClipMediaDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief ReplaceClipMediaDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow or Project panel. - * - * @param old_media - * - * A valid Media object which will be used to scan the currently active Sequence for Clips using it. - */ - ReplaceClipMediaDialog(QWidget* parent, Media* old_media); -private slots: - /** - * @brief Overridden accept for when the user clicks "Replace" - * - * Checks whether the requested replace is valid using the following criteria: - * * Any Media is selected - * * The selected Media is not the same Media that the user is trying to replace - * * The Media is not a folder - * * The Media is not the currently active Sequence - */ - virtual void accept() override; -private: - /** - * @brief Internal pointer to the Media we're replacing - */ - Media* media; - - /** - * @brief Tree widget to show Project's media - */ - QTreeView* tree; - - /** - * @brief CheckBox for using the same media in points - * - * When the starting point of a Clip is trimmed (i.e. the Clip no longer starts at 0), - */ - QCheckBox* use_same_media_in_points; -}; - -#endif // REPLACECLIPMEDIADIALOG_H diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp deleted file mode 100644 index 302ba23e0..000000000 --- a/dialogs/speeddialog.cpp +++ /dev/null @@ -1,461 +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 "speeddialog.h" - -#include -#include -#include -#include -#include - -#include "timeline/sequence.h" -#include "project/footage.h" -#include "rendering/renderfunctions.h" -#include "panels/panels.h" -#include "panels/timeline.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "nodes/oldeffectnode.h" -#include "project/media.h" - -SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent) { - setWindowTitle(tr("Speed/Duration")); - - clips_ = clips; - - QVBoxLayout* main_layout = new QVBoxLayout(this); - - QGridLayout* grid = new QGridLayout(); - grid->setSpacing(6); - - grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0); - percent = new LabelSlider(this); - percent->SetDecimalPlaces(2); - percent->SetDisplayType(LabelSlider::Percent); - percent->SetDefault(1); - grid->addWidget(percent, 0, 1); - - grid->addWidget(new QLabel(tr("Frame Rate:"), this), 1, 0); - frame_rate = new LabelSlider(this); - frame_rate->SetDecimalPlaces(3); - grid->addWidget(frame_rate, 1, 1); - - grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0); - duration = new LabelSlider(this); - duration->SetDisplayType(LabelSlider::FrameNumber); - duration->SetFrameRate(clips_.first()->track()->sequence()->frame_rate()); - grid->addWidget(duration, 2, 1); - - main_layout->addLayout(grid); - - reverse = new QCheckBox(tr("Reverse"), this); - maintain_pitch = new QCheckBox(tr("Maintain Audio Pitch"), this); - ripple = new QCheckBox(tr("Ripple Changes"), this); - - main_layout->addWidget(reverse); - main_layout->addWidget(maintain_pitch); - main_layout->addWidget(ripple); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - buttonBox->setCenterButtons(true); - main_layout->addWidget(buttonBox); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - - connect(percent, SIGNAL(valueChanged(double)), this, SLOT(percent_update())); - connect(frame_rate, SIGNAL(valueChanged(double)), this, SLOT(frame_rate_update())); - connect(duration, SIGNAL(valueChanged(double)), this, SLOT(duration_update())); -} - -int SpeedDialog::exec() { - bool enable_frame_rate = false; - bool multiple_audio = false; - maintain_pitch->setEnabled(false); - - double default_frame_rate = qSNaN(); - double current_frame_rate = qSNaN(); - double current_percent = qSNaN(); - long default_length = -1; - long current_length = -1; - - for (int i=0;ispeed().value; - if (c->type() == olive::kTypeVideo) { - bool process_video = true; - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - FootageStream* ms = c->media_stream(); - if (ms != nullptr && ms->infinite_length) { - process_video = false; - } - } - - if (process_video) { - double media_frame_rate = c->media_frame_rate(); - - // get "default" frame rate" - if (enable_frame_rate) { - // check if frame rate is equal to default - if (!qIsNaN(default_frame_rate) && !qFuzzyCompare(media_frame_rate, default_frame_rate)) { - default_frame_rate = qSNaN(); - } - if (!qIsNaN(current_frame_rate) && !qFuzzyCompare(media_frame_rate*c->speed().value, current_frame_rate)) { - current_frame_rate = qSNaN(); - } - } else { - default_frame_rate = media_frame_rate; - current_frame_rate = media_frame_rate*c->speed().value; - } - - enable_frame_rate = true; - } - } else if (c->type() == olive::kTypeAudio) { - maintain_pitch->setEnabled(true); - - if (!multiple_audio) { - maintain_pitch->setChecked(c->speed().maintain_audio_pitch); - multiple_audio = true; - } else if (!maintain_pitch->isTristate() && maintain_pitch->isChecked() != c->speed().maintain_audio_pitch) { - maintain_pitch->setCheckState(Qt::PartiallyChecked); - maintain_pitch->setTristate(true); - } - } - - if (i == 0) { - reverse->setChecked(c->reversed()); - } else if (c->reversed() != reverse->isChecked()) { - reverse->setTristate(true); - reverse->setCheckState(Qt::PartiallyChecked); - } - - // get default length - long clip_default_length = qRound(c->length() * clip_percent); - if (i == 0) { - current_length = c->length(); - default_length = clip_default_length; - current_percent = clip_percent; - } else { - if (current_length != -1 && c->length() != current_length) { - current_length = -1; - } - if (default_length != -1 && clip_default_length != default_length) { - default_length = -1; - } - if (!qIsNaN(current_percent) && !qFuzzyCompare(clip_percent, current_percent)) { - current_percent = qSNaN(); - } - } - } - - frame_rate->SetMinimum(1); - percent->SetMinimum(0.0001); - duration->SetMinimum(1); - - frame_rate->setEnabled(enable_frame_rate); - frame_rate->SetDefault(default_frame_rate); - frame_rate->SetValue(current_frame_rate); - percent->SetValue(current_percent); - duration->SetDefault(default_length); - duration->SetValue((current_length == -1) ? qSNaN() : current_length); - - return QDialog::exec(); -} - -void SpeedDialog::percent_update() { - bool got_fr = false; - double fr_val = qSNaN(); - long len_val = -1; - - for (int i=0;iisEnabled() && c->type() == olive::kTypeVideo) { - double clip_fr = c->media_frame_rate() * percent->value(); - if (got_fr) { - if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) { - fr_val = qSNaN(); - } - } else { - fr_val = clip_fr; - got_fr = true; - } - } - - // get duration - long clip_default_length = qRound(c->length() * c->speed().value); - long new_clip_length = qRound(clip_default_length / percent->value()); - if (i == 0) { - len_val = new_clip_length; - } else if (len_val > -1 && len_val != new_clip_length) { - len_val = -1; - } - } - - frame_rate->SetValue(fr_val); - duration->SetValue((len_val == -1) ? qSNaN() : len_val); -} - -void SpeedDialog::duration_update() { - double pc_val = qSNaN(); - bool got_fr = false; - double fr_val = qSNaN(); - - for (int i=0;ilength() * c->speed().value); - double clip_pc = clip_default_length / duration->value(); - if (i == 0) { - pc_val = clip_pc; - } else if (!qIsNaN(pc_val) && !qFuzzyCompare(clip_pc, pc_val)) { - pc_val = qSNaN(); - } - - // get frame rate - if (frame_rate->isEnabled() && c->type() == olive::kTypeVideo) { - double clip_fr = c->media_frame_rate() * clip_pc; - if (got_fr) { - if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) { - fr_val = qSNaN(); - } - } else { - fr_val = clip_fr; - got_fr = true; - } - } - } - - frame_rate->SetValue(fr_val); - percent->SetValue(pc_val); -} - -void SpeedDialog::frame_rate_update() { - /*double fr = (frame_rate->value()); - double pc = (fr / default_frame_rate); - percent->set_value(pc, false); - duration->set_value(default_length / pc, false);*/ - - double old_pc_val = qSNaN(); - bool got_pc_val = false; - double pc_val = qSNaN(); - bool got_len_val = false; - long len_val = -1; - - // analyze video clips - for (int i=0;ispeed().value; - } else if (!qIsNaN(old_pc_val) && !qFuzzyCompare(c->speed().value, old_pc_val)) { - old_pc_val = qSNaN(); - } - - if (c->type() == olive::kTypeVideo) { - // what would the new speed be based on this frame rate - double new_clip_speed = frame_rate->value() / c->media_frame_rate(); - if (!got_pc_val) { - pc_val = new_clip_speed; - got_pc_val = true; - } else if (!qIsNaN(pc_val) && !qFuzzyCompare(pc_val, new_clip_speed)) { - pc_val = qSNaN(); - } - - // what would be the new length based on this speed - long new_clip_len = (c->length() * c->speed().value) / new_clip_speed; - if (!got_len_val) { - len_val = new_clip_len; - got_len_val = true; - } else if (len_val > -1 && new_clip_len != len_val) { - len_val = -1; - } - } - } - - // analyze audio clips - for (int i=0;itype() == olive::kTypeAudio) { - - long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? - c->length() : qRound((c->length() * c->speed().value) / pc_val); - - if (len_val > -1 && new_clip_len != len_val) { - len_val = -1; - break; - } - } - } - - percent->SetValue(pc_val); - duration->SetValue((len_val == -1) ? qSNaN() : len_val); -} - -void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, long& lr) { - c->track()->DeselectArea(c->timeline_in(), c->timeline_out()); - - long proposed_out = c->timeline_out(); - double multiplier = (c->speed().value / speed); - proposed_out = qRound(c->timeline_in() + (c->length() * multiplier)); - ca->append(new SetSpeedAction(c, speed)); - if (!ripple && proposed_out > c->timeline_out()) { - QVector all_clips = c->track()->sequence()->GetAllClips(); - - for (int i=0;itrack() == c->track() - && compare->timeline_in() >= c->timeline_out() && compare->timeline_in() < proposed_out) { - proposed_out = compare->timeline_in(); - } - } - } - ep = qMin(ep, c->timeline_out()); - lr = qMax(lr, proposed_out - c->timeline_out()); - c->track()->sequence()->MoveClip(c, - ca, - c->timeline_in(), - proposed_out, - qRound(c->clip_in() * multiplier), - c->track()); - - c->refactor_frame_rate(ca, multiplier, false); - - c->track()->SelectArea(c->timeline_in(), proposed_out); -} - -void SpeedDialog::accept() { - ComboAction* ca = new ComboAction(); - - // undoable action for setting "maintain audio pitch" - SetClipProperty* audio_pitch_action = new SetClipProperty(kSetClipPropertyMaintainAudioPitch); - - // undoable action for setting "reversed" - SetClipProperty* reversed_action = new SetClipProperty(kSetClipPropertyReversed); - - // undoable action for restoring clip selections - Sequence* sequence = clips_.first()->track()->sequence(); - QVector old_selections = sequence->Selections(); - - // variables used to calculate ripples - long earliest_point = LONG_MAX; - long longest_ripple = LONG_MIN; - - for (int i=0;iIsOpen()) { - c->Close(true); - } - - // set maintain audio pitch if the user made a selection - if (c->type() == olive::kTypeAudio - && maintain_pitch->checkState() != Qt::PartiallyChecked - && c->speed().maintain_audio_pitch != maintain_pitch->isChecked()) { - audio_pitch_action->AddSetting(c, maintain_pitch->isChecked()); - } - - // set reverse setting if the user made a selection - if (reverse->checkState() != Qt::PartiallyChecked && c->reversed() != reverse->isChecked()) { - long new_clip_in = (c->media_length() - (c->length() + c->clip_in())); - c->track()->sequence()->MoveClip(c, - ca, - c->timeline_in(), - c->timeline_out(), - new_clip_in, - c->track()); - c->set_clip_in(new_clip_in); - reversed_action->AddSetting(c, reverse->isChecked()); - } - } - - // setting the actual speed - if (!qIsNaN(percent->value())) { - - // if we have a percentage value, use that on all the clips - for (int i=0;ivalue(), ripple->isChecked(), earliest_point, longest_ripple); - } - - } else if (!qIsNaN(frame_rate->value())) { - - // if the user changed the speed by changing the frame rate, - bool can_change_all = true; - double cached_speed = clips_.first()->speed().value; - double cached_fr = qSNaN(); - - // see if we can use the frame rate to change all the speeds - for (int i=0;i 0 && !qFuzzyCompare(cached_speed, c->speed().value)) { - can_change_all = false; - } - if (c->type() == olive::kTypeVideo) { - if (qIsNaN(cached_fr)) { - cached_fr = c->media_frame_rate(); - } else if (!qFuzzyCompare(cached_fr, c->media_frame_rate())) { - can_change_all = false; - break; - } - } - } - - // make changes - for (int i=0;itype() == olive::kTypeVideo) { - set_speed(ca, c, frame_rate->value() / c->media_frame_rate(), ripple->isChecked(), earliest_point, longest_ripple); - } else if (can_change_all) { - set_speed(ca, c, frame_rate->value() / cached_fr, ripple->isChecked(), earliest_point, longest_ripple); - } - } - } else if (!qIsNaN(duration->value())) { - // simply set duration - for (int i=0;ilength() * c->speed().value) / duration->value(), ripple->isChecked(), earliest_point, longest_ripple); - } - } - - if (ripple->isChecked()) { - sequence->Ripple(ca, earliest_point, longest_ripple); - } - - ca->append(new SetSelectionsCommand(sequence, old_selections, sequence->Selections())); - - ca->append(reversed_action); - ca->append(audio_pitch_action); - - olive::undo_stack.push(ca); - - update_ui(true); - QDialog::accept(); -} diff --git a/dialogs/speeddialog.h b/dialogs/speeddialog.h deleted file mode 100644 index 27d3765bb..000000000 --- a/dialogs/speeddialog.h +++ /dev/null @@ -1,132 +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 SPEEDDIALOG_H -#define SPEEDDIALOG_H - -#include -#include - -#include "timeline/clip.h" -#include "ui/labelslider.h" - -/** - * @brief The SpeedDialog class - * - * A dialog for setting the speed of one or more Clips. This can be run from anywhere provided it's given a valid - * array of Clips. - * - * It's preferable to - */ -class SpeedDialog : public QDialog -{ - Q_OBJECT -public: - /** - * @brief SpeedDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow or Timeline panel. - * - * @param clips - * - * A valid array of Clips to change the speed of. - */ - SpeedDialog(QWidget* parent, QVector clips); -public slots: - /** - * @brief Override of exec() to set up current Clip speed data just before opening - * - * @return - * - * The result of QDialog::exec(), a DialogCode result. - */ - virtual int exec() override; -private slots: - /** - * @brief Override of accept() to perform the selected changes on the Clips - */ - virtual void accept() override; - - /** - * @brief Slot when the speed percentage field is changed by the user - * - * The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the - * Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the - * same speed multipler. - */ - void percent_update(); - - /** - * @brief Slot when the duration field is changed by the user - * - * The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the - * Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the - * same speed multipler. - */ - void duration_update(); - - /** - * @brief Slot when the frame rate field is changed by the user - * - * The three fields (percent, duration, and frame rate) all work in tandem to create a speed multipler for the - * Clip. Each has a slot for when one of the fields changes to update the others appropriately so they all have the - * same speed multipler. - */ - void frame_rate_update(); -private: - /** - * @brief Internal array of Clip objects - */ - QVector clips_; - - /** - * @brief Speed percentage field - */ - LabelSlider* percent; - - /** - * @brief Duration field - */ - LabelSlider* duration; - - /** - * @brief Frame rate field - */ - LabelSlider* frame_rate; - - /** - * @brief UI widget for setting the Clip's reverse value - */ - QCheckBox* reverse; - - /** - * @brief UI widget for setting the Clip's maintain pitch value - */ - QCheckBox* maintain_pitch; - - /** - * @brief UI widget for setting whether to ripple Clips around these changes or not - */ - QCheckBox* ripple; -}; - -#endif // SPEEDDIALOG_H diff --git a/dialogs/texteditdialog.cpp b/dialogs/texteditdialog.cpp deleted file mode 100644 index 281688a32..000000000 --- a/dialogs/texteditdialog.cpp +++ /dev/null @@ -1,213 +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 "texteditdialog.h" - -#include -#include -#include -#include -#include - -#include "ui/icons.h" - -TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text) : - QDialog(parent), - rich_text_(rich_text) -{ - setWindowTitle(tr("Edit Text")); - - QVBoxLayout* layout = new QVBoxLayout(this); - - // Create central text editor object - textEdit = new QTextEdit(this); - textEdit->setUndoRedoEnabled(true); - - // Upper toolbar - if (rich_text) { - QHBoxLayout* toolbar = new QHBoxLayout(); - - // Italic Button - italic_button = new QPushButton(); - italic_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/italic.svg", false)); - italic_button->setCheckable(true); - connect(italic_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontItalic(bool))); - toolbar->addWidget(italic_button); - - // Underline Button - underline_button = new QPushButton(); - underline_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/underline.svg", false)); - underline_button->setCheckable(true); - connect(underline_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontUnderline(bool))); - toolbar->addWidget(underline_button); - - // Font Name - font_list = new QFontComboBox(); - connect(font_list, SIGNAL(currentIndexChanged(const QString&)), textEdit, SLOT(setFontFamily(const QString&))); - toolbar->addWidget(font_list); - - // Font Weight - font_weight = new QComboBox(); - font_weight->addItem(tr("Thin"), QFont::Thin); - font_weight->addItem(tr("Extra Light"), QFont::ExtraLight); - font_weight->addItem(tr("Light"), QFont::Light); - font_weight->addItem(tr("Normal"), QFont::Normal); - font_weight->addItem(tr("Medium"), QFont::Medium); - font_weight->addItem(tr("Demi Bold"), QFont::DemiBold); - font_weight->addItem(tr("Bold"), QFont::Bold); - font_weight->addItem(tr("Extra Bold"), QFont::ExtraBold); - font_weight->addItem(tr("Black"), QFont::Black); - connect(font_weight, SIGNAL(currentIndexChanged(int)), this, SLOT(SetFontWeight(int))); - toolbar->addWidget(font_weight); - - // Font Size - font_size = new LabelSlider(); - connect(font_size, SIGNAL(valueChanged(double)), textEdit, SLOT(setFontPointSize(qreal))); - toolbar->addWidget(font_size); - - // Font Color - font_color = new ColorButton(); - connect(font_color, SIGNAL(color_changed(const QColor&)), textEdit, SLOT(setTextColor(const QColor &))); - toolbar->addWidget(font_color); - - toolbar->addStretch(); - - // Left Align - left_align_button = new QPushButton(); - left_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-left.svg", false)); - left_align_button->setCheckable(true); - left_align_button->setProperty("a", Qt::AlignLeft); - connect(left_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); - toolbar->addWidget(left_align_button); - - // Center Align - center_align_button = new QPushButton(); - center_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-center.svg", false)); - center_align_button->setCheckable(true); - center_align_button->setProperty("a", Qt::AlignCenter); - connect(center_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); - toolbar->addWidget(center_align_button); - - // Right Align - right_align_button = new QPushButton(); - right_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/align-right.svg", false)); - right_align_button->setCheckable(true); - right_align_button->setProperty("a", Qt::AlignRight); - connect(right_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); - toolbar->addWidget(right_align_button); - - // Justify Align - justify_align_button = new QPushButton(); - justify_align_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/justify-center.svg", false)); - justify_align_button->setCheckable(true); - justify_align_button->setProperty("a", Qt::AlignJustify); - connect(justify_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); - toolbar->addWidget(justify_align_button); - - layout->addLayout(toolbar); - } - - layout->addWidget(textEdit); - - // Lower toolbar - /* - if (rich_text) { - QHBoxLayout* lower_toolbar = new QHBoxLayout(); - - lower_toolbar->addWidget(new QLabel(tr("Letter Spacing:"))); - - letter_spacing = new LabelSlider(); - connect(letter_spacing, SIGNAL(valueChanged(double)), this, SLOT(SetLetterSpacing(qreal))); - lower_toolbar->addWidget(letter_spacing); - - lower_toolbar->addStretch(); - - layout->addLayout(lower_toolbar); - } - */ - - // Create dialog buttons at the bottom - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - buttons->setCenterButtons(true); - layout->addWidget(buttons); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); - - // Connect the cursor position changing to the rich text toolbar buttons updating (so for example, when italic text - // is selected, the italic button will be pressed) - connect(textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(UpdateUIFromTextCursor())); - - // Set the widget's text based on the rich text mode - if (rich_text_) { - textEdit->setHtml(s); - } else { - textEdit->setPlainText(s); - } - - // Helps ensure the UI elements update correctly at the beginning - when the cursor is at the start, the UI elements - // show up blank. Setting it to the end is probably more expected behavior anyway. - textEdit->moveCursor(QTextCursor::End); -} - -const QString& TextEditDialog::get_string() { - return result_str; -} - -void TextEditDialog::accept() { - result_str = rich_text_ ? textEdit->toHtml() : textEdit->toPlainText(); - QDialog::accept(); -} - -void TextEditDialog::SetFontWeight(int i) -{ - textEdit->setFontWeight(font_weight->itemData(i).toInt()); -} - -void TextEditDialog::SetAlignmentFromProperty() -{ - textEdit->setAlignment(static_cast(sender()->property("a").toInt())); - UpdateUIFromTextCursor(); -} - -void TextEditDialog::UpdateUIFromTextCursor() -{ - if (rich_text_) { - italic_button->setChecked(textEdit->fontItalic()); - underline_button->setChecked(textEdit->fontUnderline()); - font_list->setCurrentText(textEdit->fontFamily()); - font_size->SetValue(textEdit->fontPointSize()); - font_color->set_color(textEdit->textColor()); - - for (int i=0;icount();i++) { - if (font_weight->itemData(i).toInt() == textEdit->fontWeight()) { - font_weight->blockSignals(true); - font_weight->setCurrentIndex(i); - font_weight->blockSignals(false); - break; - } - } - - Qt::Alignment align = textEdit->alignment(); - left_align_button->setChecked(align == Qt::AlignLeft); - center_align_button->setChecked(align == Qt::AlignCenter); - right_align_button->setChecked(align == Qt::AlignRight); - justify_align_button->setChecked(align == Qt::AlignJustify); - } -} diff --git a/dialogs/texteditdialog.h b/dialogs/texteditdialog.h deleted file mode 100644 index 6f6e2de07..000000000 --- a/dialogs/texteditdialog.h +++ /dev/null @@ -1,179 +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 TEXTEDITDIALOG_H -#define TEXTEDITDIALOG_H - -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/colorbutton.h" - -/** - * @brief The TextEditDialog class - * - * A separate window for editing text. This window can be resized arbitrarily and also provides a toolbar for rich text - * editing (if rich text is enabled). This dialog can be run from anywhere. Once the dialog has closed (i.e. returned - * from exec() ), the text entered into it can be retrieved using get_string(). - * - * TODO: Add a live signal for updating the calling function. - */ -class TextEditDialog : public QDialog { - Q_OBJECT -public: - /** - * @brief TextEditDialog Constructor - * - * @param parent - * - * QWidget parent. Usually MainWindow. - * - * @param s - * - * The starting string when the dialog opens. It'll be read as rich text HTML or plain text based on the `rich_text` - * parameter (which defaults to rich text HTML). It can also be left empty to start blank. - * - * @param rich_text - * - * Set the editing mode of the editor. If TRUE, the dialog will interpret the string in `s` as rich text HTML and also - * return rich text HTML through get_string(). It'll also show a toolbar with rich text options (i.e. font, italic, - * underline, size, etc.) If FALSE, the dialog will run in plain text mode interpreting the string in `s` as plain - * text and returning plain text through get_string(). It also will not show the rich text editing toolbar. - */ - TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr, bool rich_text = true); - - /** - * @brief Retrieve the current text in the dialog - * - * This function can be called after the user has accepted the dialog (i.e. made changes and clicked OK). - * This will return either plain text or rich text (HTML) depending on the mode it's running in (rich/plain text mode - * is set in the constructor). The value this returns only gets updated when the user clicks OK so it cannot be - * used to retrieve live text updates from the dialog. - * - * @return - * - * The text entered once the user accepted this dialog. - */ - const QString& get_string(); -private slots: - /** - * @brief Override of accept() to store the entered text string so it can be retrieved by get_string(). - */ - virtual void accept() override; - - /** - * @brief Slot for the font_weight combobox to set the font weight based on its data value - * - * @param i - * - * Index of the font_weight to retrieve the desired font weight from - */ - void SetFontWeight(int i); - - /** - * @brief Slot for text alignment buttons to set alignment based on their properties - * - * Intended slot for left_align_button, center_align_button, right_align_button, and justify_align_button. Pulls - * from their property("a") value which should be a member of the Qt::Alignment enum. - */ - void SetAlignmentFromProperty(); - - /** - * @brief Slot for when the text edit widget's cursor moves so the rich text toolbar can stay up to date - * - * In rich text mode, different parts of a text document can be formatted in different ways. As the user moves - * around the text, the UI buttons should be consistent with whatever text is currently selected. This slot should - * therefore be connected to QTextEdit::cursorPositionChanged() and will change the "checked" state of the formatting - * buttons and current index of the comboboxes to match the currently selected text. - */ - void UpdateUIFromTextCursor(); -private: - - /** - * @brief Internal rich text mode value - * - * This is set in the constructor and cannot be changed during the lifetime of this dialog. - */ - bool rich_text_; - - /** - * @brief Internal storage of text entered, saved when the user clicks OK - */ - QString result_str; - - /** - * @brief Main text editing widget - */ - QTextEdit* textEdit; - - /** - * @brief Toggle button for setting the italic state of the currently selected text - */ - QPushButton* italic_button; - - /** - * @brief Toggle button for setting the underlined state of the currently selected text - */ - QPushButton* underline_button; - - /** - * @brief ComboBox for the list of font families that the selected text can be set to - */ - QFontComboBox* font_list; - - /** - * @brief ComboBox for the list of font weights that the selected text can be set to - */ - QComboBox* font_weight; - - /** - * @brief A slider to set the current font size - */ - LabelSlider* font_size; - - /** - * @brief A color selector for setting the current text color - */ - ColorButton* font_color; - - /** - * @brief Button for setting the current text row(s) to left alignment - */ - QPushButton* left_align_button; - - /** - * @brief Button for setting the current text row(s) to center alignment - */ - QPushButton* center_align_button; - - /** - * @brief Button for setting the current text row(s) to right alignment - */ - QPushButton* right_align_button; - - /** - * @brief Button for setting the current text row(s) to justified alignment - */ - QPushButton* justify_align_button; -}; - -#endif // TEXTEDITDIALOG_H diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp deleted file mode 100644 index 10db09797..000000000 --- a/effects/effectfield.cpp +++ /dev/null @@ -1,344 +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 "effectfield.h" - -#include -#include -#include - -#include "rendering/renderfunctions.h" -#include "global/config.h" -#include "global/timing.h" -#include "nodes/nodeio.h" -#include "nodes/oldeffectnode.h" -#include "undo/undo.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "global/math.h" -#include "global/debug.h" - -EffectField::EffectField(NodeIO* parent, EffectFieldType t) : - QObject(parent), - type_(t), - enabled_(true) -{ - // EffectField MUST be created with a parent. - Q_ASSERT(parent != nullptr); - - // Set a very base default value - SetValueAt(0, 0); - - // Connect this field to the effect's changed function - connect(this, SIGNAL(Changed()), parent->ParentNode(), SLOT(FieldChanged())); -} - -NodeIO *EffectField::GetParentRow() -{ - return static_cast(parent()); -} - -QVariant EffectField::ConvertStringToValue(const QString &s) -{ - return s; -} - -QString EffectField::ConvertValueToString(const QVariant &v) -{ - return v.toString(); -} - -void EffectField::UpdateWidgetValue(QWidget *, double) {} - -QVariant EffectField::GetValueAt(double timecode) -{ - if (HasKeyframes()) { - int before_keyframe; - int after_keyframe; - double progress; - GetKeyframeData(timecode, before_keyframe, after_keyframe, progress); - - const QVariant& before_data = keyframes.at(before_keyframe).data; - switch (type_) { - case EFFECT_FIELD_DOUBLE: - { - double value; - if (before_keyframe == after_keyframe) { - value = keyframes.at(before_keyframe).data.toDouble(); - } else { - const EffectKeyframe& before_key = keyframes.at(before_keyframe); - const EffectKeyframe& after_key = keyframes.at(after_keyframe); - - double before_dbl = before_key.data.toDouble(); - double after_dbl = after_key.data.toDouble(); - - if (before_key.type == EFFECT_KEYFRAME_HOLD) { - - // Hold keyframes will always return the previous keyframe with no interpolation - value = before_dbl; - - } else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) { - - // bezier interpolation - if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { - - // cubic bezier - double t = cubic_t_from_x(timecode, - before_key.time, - before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), - after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), - after_key.time); - - value = cubic_from_t(before_dbl, - before_dbl+before_key.post_handle.y(), - after_dbl+after_key.pre_handle.y(), - after_dbl, - t); - - } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier - - // last keyframe is the bezier one - double t = quad_t_from_x(timecode, - before_key.time, - before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), - after_key.time); - - value = quad_from_t(before_dbl, - before_dbl+before_key.post_handle.y(), - after_dbl, - t); - - } else { - // this keyframe is the bezier one - double t = quad_t_from_x(timecode, - before_key.time, - after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), - after_key.time); - - value = quad_from_t(before_dbl, - after_dbl+after_key.pre_handle.y(), - after_dbl, - t); - } - } else { - - // Linear interpolation (default) - value = double_lerp(before_dbl, after_dbl, progress); - - } - } - persistent_data_ = value; - break; - } - case EFFECT_FIELD_COLOR: - { - QColor value; - if (before_keyframe == after_keyframe) { - value = keyframes.at(before_keyframe).data.value(); - } else { - QColor before_data = keyframes.at(before_keyframe).data.value(); - QColor after_data = keyframes.at(after_keyframe).data.value(); - value = QColor(lerp(before_data.red(), after_data.red(), progress), - lerp(before_data.green(), after_data.green(), progress), - lerp(before_data.blue(), after_data.blue(), progress)); - } - persistent_data_ = value; - break; - } - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_BOOL: - case EFFECT_FIELD_COMBO: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - persistent_data_ = before_data; - break; - default: - break; - } - } - - return persistent_data_; -} - -void EffectField::SetValueAt(double time, const QVariant &value) -{ - if (HasKeyframes()) { - - // Create keyframe here - - // Check array if a keyframe at this time already exists - int keyframe_index = -1; - for (int i=0;iParentNode()->Time(); - key.data = persistent_data_; - key.type = EFFECT_KEYFRAME_LINEAR; - - keyframes.append(key); - - ca->append(new KeyframeAdd(this, keyframes.size()-1)); - - } else { - - // Convert keyframes to one "perpetual" keyframe - - // Set first keyframe to whatever the data is now - ca->append(new SetQVariant(&persistent_data_, persistent_data_, GetValueAt(GetParentRow()->ParentNode()->Time()))); - - // Delete all keyframes - for (int i=0;iappend(new KeyframeDelete(this, 0)); - } - - } -} - -const EffectField::EffectFieldType &EffectField::type() -{ - return type_; -} - -double EffectField::GetValidKeyframeHandlePosition(int key, bool post) { - int comp_key = -1; - - // find keyframe before or after this one - for (int i=0;i keyframes.at(key).time) == post) - && (comp_key == -1 - || ((keyframes.at(i).time < keyframes.at(comp_key).time) == post))) { - // compare with next keyframe for post or previous frame for pre - comp_key = i; - } - } - - double adjusted_key = post ? keyframes.at(key).post_handle.x() : keyframes.at(key).pre_handle.x(); - - // if this is the earliest/latest keyframe, no validation is required - if (comp_key == -1) { - return adjusted_key; - } - - double comp = keyframes.at(comp_key).time - keyframes.at(key).time; - - // if comp keyframe is bezier, validate with its accompanying handle - if (keyframes.at(comp_key).type == EFFECT_KEYFRAME_BEZIER) { - double relative_comp_handle = comp + (post ? keyframes.at(comp_key).pre_handle.x() : keyframes.at(comp_key).post_handle.x()); - // return an average - if ((post && keyframes.at(key).post_handle.x() > relative_comp_handle) - || (!post && keyframes.at(key).pre_handle.x() < relative_comp_handle)) { - adjusted_key = (adjusted_key + relative_comp_handle)*0.5; - } - } - - // don't let handle go beyond the compare keyframe's time - if (post == (adjusted_key > comp)) { - return comp; - } - - if (post == (adjusted_key < 0)) { - return 0; - } - - // original value is valid - return adjusted_key; -} - -void EffectField::GetKeyframeData(double timecode, int &before, int &after, double &progress) { - int before_keyframe_index = -1; - int after_keyframe_index = -1; - double before_keyframe_time = DBL_MIN; - double after_keyframe_time = DBL_MAX; - - for (int i=0;i before_keyframe_time) { - before_keyframe_index = i; - before_keyframe_time = eval_keyframe_time; - } else if (eval_keyframe_time > timecode && eval_keyframe_time < after_keyframe_time) { - after_keyframe_index = i; - after_keyframe_time = eval_keyframe_time; - } - } - - if ((type_ == EFFECT_FIELD_DOUBLE || type_ == EFFECT_FIELD_COLOR) - && (before_keyframe_index > -1 && after_keyframe_index > -1)) { - // interpolate - before = before_keyframe_index; - after = after_keyframe_index; - progress = (timecode-before_keyframe_time)/(after_keyframe_time-before_keyframe_time); - } else if (before_keyframe_index > -1) { - before = before_keyframe_index; - after = before_keyframe_index; - } else { - before = after_keyframe_index; - after = after_keyframe_index; - } -} - -bool EffectField::HasKeyframes() { - return (GetParentRow()->IsKeyframing() && !keyframes.isEmpty()); -} - -bool EffectField::IsEnabled() { - return enabled_; -} - -void EffectField::SetEnabled(bool e) { - enabled_ = e; - emit EnabledChanged(enabled_); -} diff --git a/effects/effectfield.h b/effects/effectfield.h deleted file mode 100644 index 543dafc47..000000000 --- a/effects/effectfield.h +++ /dev/null @@ -1,420 +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 EFFECTFIELD_H -#define EFFECTFIELD_H - -#include -#include -#include - -#include "effects/keyframe.h" -#include "undo/undostack.h" -#include "nodes/nodedatatypes.h" - -class NodeIO; -class ComboAction; - -/** - * @brief The EffectField class - * - * Any user-interactive element of an Effect. Usually a parameter that modifies the effect output, but sometimes just - * a UI object that performs some other function (e.g. LabelField and ButtonField). - * - * EffectField provides a largely abstract interface for Effect classes to pull information from. The class itself - * handles keyframing between linear, bezier, and hold interpolation accessible through GetValueAt(). This class - * is abstract, and therefore never intended to be used on its own. Instead you should always use a derived class. - * - * EffectField objects are *not* UI objects on their own. Instead, they're largely a system of values that can change - * over time. For a widget that the user can use to edit/modify these values, use CreateWidget(). - * - * Derived classes are expected to override at least CreateWidget() to create a visual interactive widget corresponding - * to the field. If this - * field is a value used in the Effect (as most will be), UpdateWidgetValue() should also be overridden to display the - * correct value for this field as the user moves around the Timeline. - * - * If the field is intended to be saved and loaded from Olive project files (as most will be), ConvertStringToValue() - * and ConvertValueToString() may also have to be overridden depending on how the derived class's data works. - */ -class EffectField : public QObject { - Q_OBJECT -public: - - /** - * @brief The EffectFieldType enum - * - * Predetermined types of fields. Used throughout Olive to identify what kind of data to expect from GetValueAt(). - * - * This enum is also currently used to match an external XML effect's fields with the correct derived class (e.g. - * EFFECT_FIELD_DOUBLE matches to DoubleField). - */ - enum EffectFieldType { - /** Values are doubles. Also corresponds to DoubleField. */ - EFFECT_FIELD_DOUBLE, - - /** Values are colors. Also corresponds to ColorField. */ - EFFECT_FIELD_COLOR, - - /** Values are strings. Also corresponds to StringField. */ - EFFECT_FIELD_STRING, - - /** Values are booleans. Also corresponds to BoolField. */ - EFFECT_FIELD_BOOL, - - /** Values are arbitrary data. Also corresponds to ComboField. */ - EFFECT_FIELD_COMBO, - - /** Values are font family names (in string). Also corresponds to FontField. */ - EFFECT_FIELD_FONT, - - /** Values are filenames (in string). Also corresponds to FileField. */ - EFFECT_FIELD_FILE, - - /** Values is a UI object with no data. Corresponds to nothing. */ - EFFECT_FIELD_UI - }; - - /** - * @brief EffectField Constructor - * - * Creates a new EffectField object. - * - * @param parent - * - * The EffectRow to add this field to. This must be a valid EffectRow. The EffectRow takes ownership of the field - * using the QObject parent/child system to automate memory management. EffectFields are never expected - * to change parent during their lifetime. - * - * @param t - * - * The type of data contained within this field. This is expected to be filled by a derived class. - */ - EffectField(NodeIO* parent, EffectFieldType t); - - /** - * @brief Get the EffectRow that this field is a member of. - * - * Equivalent to `static_cast(EffectField::parent())` - * - * @return - * - * The EffectRow that this field is a member of. - */ - NodeIO* GetParentRow(); - - /** - * @brief Get the type of data to expect from this field - * - * @return - * - * A member of the EffectFieldType enum. - */ - const EffectFieldType& type(); - - /** - * @brief Get the value of this field at a given timecode - * - * EffectFields are designed to be keyframable, meaning the user can make the values change over the course of the - * Sequence. This is the main function used through Olive to retrieve what value this field will be at a given time. - * - * A common use case for this function would be EffectField::GetValueAt(EffectField::Now()), which will automatically - * retrieve the timecode at the current playhead. - * - * If the parent EffectRow is NOT keyframing, this function will simply return persistent_data_. If it IS keyframing, - * this will use the values in `keyframes` to determine what value should be specifically at this time. - * (bezier or linear interpolating it between values if necessary). Therefore this function should almost always be - * used to retrieve data from this field as the value will always be correct for the given time. - * - * @param timecode - * - * The time to retrieve the value in clip/media seconds (e.g. 0.0 is the very start of the media, 1.0 is one second - * into the media). - * - * @return - * - * A QVariant representation of the value at the given timecode. - */ - QVariant GetValueAt(double timecode); - - /** - * @brief Set the value of this field at a given timecode - * - * EffectFields are designed to be keyframable, meaning the user can make the values change over the course of the - * Sequence. This is the main function used through Olive to set what value this field will be at a given time. - * - * If the parent EffectRow is keyframing, this function will determine whether a keyframe exists at this time already. - * If it does, it will change the value at that keyframe to `value`. Otherwise, it'll create a new keyframe at the - * specified `time` with the specified `value`. - * - * If the parent EffectRow is not keyframing, the data is simply stored in `persistent_data_`. - * - * When constructing an Effect - * - * @param time - * - * The time to retrieve the value at in clip/media seconds (e.g. 0.0 is the very start of the media, 1.0 is one - * second into the media). - * - * @param value - * - * The QVariant value to set at this time. - */ - void SetValueAt(double time, const QVariant& value); - - /** - * @brief Set up keyframing on this field - * - * This should always be called if the user is enabling/disabling keyframing on the parent row. This function will - * move data between persistent_data_ and keyframes depending on whether keyframing is being enabled or disabled. - * - * If keyframing is getting ENABLED, this function will create the first keyframe automatically at the current time - * using the current value in persistent_data_. - * - * If keyframing is getting DISABLED, persistent_data_ is set to the current value at this time (GetValueAt(Now())) - * and delete all current keyframes. - * - * @param enabled - * - * TRUE if keyframing is getting enabled. - * - * @param ca - * - * A valid ComboAction object. It's expected that this function will be part of a larger action to enable/disable - * keyframing on the parent EffectRow, so this function will add commands to this ComboAction. - */ - void PrepareDataForKeyframing(bool enabled, ComboAction* ca); - - /** - * @brief Convert a value from this field to a string - * - * When saving effect data to a project file, the data needs to be converted to a string format for saving in XML. - * The needs of this string representation may differ depending on the needs of the derived class, therefore you - * derived classes may need to override it. - * - * Default behavior is a simple QVariant <-> QString conversion, which should suffice in most cases. - * - * @param v - * - * The QVariant data (retrieved from this field) to convert to string - * - * @return - * - * A string representation of the QVariant data provided. - */ - virtual QString ConvertValueToString(const QVariant& v); - - /** - * @brief Convert a string to a value appropriate for this field - * - * This function is the inverse of ConvertValueToString(), converting a string back to field data. - * - * @param s - * - * The string to convert to data. - * - * @return - * - * QVariant data converted from the provided string. - */ - virtual QVariant ConvertStringToValue(const QString& s); - - - /** - * @brief Create a widget for the user to interact with this field - * - * EffectField objects are *not* UI objects on their own. Instead, they're largely a system of values that can change - * over time. This function creates a QWidget object that can be placed somewhere in the UI so the user can - * interact with and change the data in this field. - * - * This function must be overridden by derived classes in order to create a widget that appropriate for that field's - * data. The derived class is also responsible for - * connecting signals like EnabledChanged(), Clicked(), and any other data that needs to be transferred between the - * widget and the field (setting up the signals and slots to do so). The field does NOT retain ownership (or any - * reference for that matter) to widgets it creates, - * so keeping the widget and field up to date with each other relies solely on setting up signals and slots. - * Infinite widgets can be created from a single field and used throughout Olive this way. - * - * Ownership is passed to the caller, and therefore the caller is responsible for freeing it. - * - * @param existing - * - * Olive allows multiple effects to attach to one UI layout. Pass a QWidget to this parameter (instead of nullptr) - * to attach this field additionally to the widget's signals/slots without creating a new one. The QWidget must be a - * widget previously created from the same derived class type or the result is undefined. - * - * @return - * - * A new QWidget object for this EffectField, or the same QWidget passed to `existing` if one was specified. - */ - virtual QWidget* CreateWidget(QWidget* existing = nullptr) = 0; - - /** - * @brief Update a widget created by CreateWidget() using the value at a given time - * - * Use this function to update a QWidget (obtained from CreateWidget()) with the correct value from the field at a - * given time. - * - * Since only the derived classes know what type of QWidget it created in CreateWidget() and how to work with them, - * derived classes are also expected to override this function if the field is an active value used in the Effect - * that should visually update as the user moves around the Timeline. However if the field does NOT need to update - * live (e.g. the field is just a UI wrapper like LabelField or ButtonField), this function does not need to be - * overridden as the default behavior (to do nothing) will suffice in those cases. - * - * @param widget - * - * The QWidget to set the value of (must be a QWidget obtained from CreateWidget() or the behavior is undefined). - * - * @param timecode - * - * The time in clip/media seconds to retrieve data from. - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode); - - /** - * @brief Get the correct X position/time value of a bezier keyframe's handles - * - * Retrieves the X value (time value) of a bezier keyframe's handles. Internally, the handles' X values are allowed - * to be arbitrary values. This however can lead to inadvertently creating impossible bezier curves (ones that, for - * example, mathematically loop over each other, but obviously a field can't have two values at the same time). - * - * This function returns the keyframe handles' X values adjusted to prevent this from happening. All calculations - * are consistent (i.e. the post handle of one keyframe will be adjusted the same way as the pre handle of the - * keyframe before it). It's recommended to always use this function to retrieve keyframe handle X values. - * - * @param key - * - * Index of the keyframe (in `keyframes`) to retrieve the handle position from. - * - * @param post - * - * FALSE to retrieve the "pre" handle (handle to the left of the keyframe), TRUE to retrieve the "post" handle - * (handle to the right of the keyframe). - * - * @return - * - * The adjusted X value of that keyframe handle. - */ - double GetValidKeyframeHandlePosition(int key, bool post); - - /** - * @brief Return whether this field is enabled or not - * - * @return - * - * TRUE if this field is enabled. - */ - bool IsEnabled(); - - /** - * @brief Set the enabled state of this field - * @param e - * - * TRUE to enable this field, FALSE to disable it. - */ - void SetEnabled(bool e); - - /** - * @brief Persistent data object - * - * If the parent EffectRow is not keyframing, all field data is stored and retrieved here. If the row IS keyframing, - * this variable goes basically unused unless `keyframes` is empty. - * - * NOTE: It is NOT recommended to access this variable directly. Use GetValueAt() instead. - */ - QVariant persistent_data_; - - /** - * @brief Keyframe array - * - * Contains all data about this field's keyframes, from the keyframe times, to their data, to their type (linear, - * bezier, or hold), to the bezier handles (if using bezier). If the row is not keyframing, this array is never used - * (`persistent_data_` is used instead). If it is, this array will always be used unless the array is empty, in which - * case `persistent_data_` will be used again. - */ - QVector keyframes; - -signals: - /** - * @brief Changed signal - * - * Emitted whenever SetValueAt() is called in order to trigger a UI update and Viewer repaint. Note this is NOT - * triggered as the value changes from keyframing. Only when the user themselves triggers a change. - */ - void Changed(); - - /** - * @brief Clicked signal - * - * Emitted when the user clicks on a QWidget attached to this field. Derived classes should connect this to the - * clicked signal of any QWidget's created (or attached) in CreateWidget(). - */ - void Clicked(); - - /** - * @brief Enable change state signal - * - * Emitted when the field's enabled state is changed through SetEnabled(). Derived classes should connect this to the - * setEnabled() slot of any QWidget's created (or attached) in CreateWidget(). - */ - void EnabledChanged(bool); - -private: - /** - * @brief Internal type variable set in the constructor. Access with type(). - */ - EffectFieldType type_; - - /** - * @brief Used by GetValueAt() to determine whether to use keyframe data or persistent data - * @return - * - * TRUE if this keyframe data should be retrieved, FALSE if persistent data should be retrieved - */ - bool HasKeyframes(); - - /** - * @brief Internal function for determining where we are between the available keyframes - * - * @param timecode - * - * Timecode to get keyframe data at - * - * @param before - * - * The index (in the keyframes array) in the keyframe prior to this timecode. - * - * @param after - * - * The index (in the keyframes array) in the keyframe after this timecode. - * - * @param d - * - * The progress between the `before` keyframe and `after` keyframe from 0.0 to 1.0. - */ - void GetKeyframeData(double timecode, int& before, int& after, double& d); - - /** - * @brief Internal enabled value - */ - bool enabled_; - -}; - -#endif // EFFECTFIELD_H diff --git a/effects/effectfields.h b/effects/effectfields.h deleted file mode 100644 index 82644bfd6..000000000 --- a/effects/effectfields.h +++ /dev/null @@ -1,40 +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 EFFECTFIELDS_H -#define EFFECTFIELDS_H - -/** - - A simple convenience header for including all the available EffectField derivations. - - */ - -#include "fields/boolfield.h" -#include "fields/buttonfield.h" -#include "fields/colorfield.h" -#include "fields/combofield.h" -#include "fields/doublefield.h" -#include "fields/filefield.h" -#include "fields/fontfield.h" -#include "fields/labelfield.h" -#include "fields/stringfield.h" - -#endif // EFFECTFIELDS_H diff --git a/effects/effectgizmo.cpp b/effects/effectgizmo.cpp deleted file mode 100644 index b74e93175..000000000 --- a/effects/effectgizmo.cpp +++ /dev/null @@ -1,63 +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 "effectgizmo.h" - -#include "ui/labelslider.h" -#include "effects/fields/doublefield.h" -#include "nodes/oldeffectnode.h" - -EffectGizmo::EffectGizmo(OldEffectNode *parent, int type) : - QObject(parent), - x_field1(nullptr), - x_field_multi1(1.0), - y_field1(nullptr), - y_field_multi1(1.0), - x_field2(nullptr), - x_field_multi2(1.0), - y_field2(nullptr), - y_field_multi2(1.0), - type(type), - cursor(-1) -{ - Q_ASSERT(parent != nullptr); - - int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1; - world_pos.resize(point_count); - screen_pos.resize(point_count); - - color = Qt::white; -} - -int EffectGizmo::get_point_count() { - return world_pos.size(); -} - -int EffectGizmo::get_type() { - return type; -} - -int EffectGizmo::get_cursor() { - return cursor; -} - -void EffectGizmo::set_cursor(int c) { - cursor = c; -} diff --git a/effects/effectgizmo.h b/effects/effectgizmo.h deleted file mode 100644 index 25ad8ae70..000000000 --- a/effects/effectgizmo.h +++ /dev/null @@ -1,73 +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 EFFECTGIZMO_H -#define EFFECTGIZMO_H - -enum GizmoType { - GIZMO_TYPE_DOT, - GIZMO_TYPE_POLY, - GIZMO_TYPE_TARGET -}; - -#define GIZMO_DOT_SIZE 2.5f -#define GIZMO_TARGET_SIZE 5.0f - -#include -#include -#include -#include -#include -#include -#include - -class DoubleField; -class OldEffectNode; - -class EffectGizmo : public QObject { - Q_OBJECT -public: - EffectGizmo(OldEffectNode* parent, int type); - - QVector world_pos; - QVector screen_pos; - - DoubleField* x_field1; - double x_field_multi1; - DoubleField* y_field1; - double y_field_multi1; - DoubleField* x_field2; - double x_field_multi2; - DoubleField* y_field2; - double y_field_multi2; - - QColor color; - int get_point_count(); - - int get_type(); - - int get_cursor(); - void set_cursor(int c); -private: - int type; - int cursor; -}; - -#endif // EFFECTGIZMO_H diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp deleted file mode 100644 index 984f90000..000000000 --- a/effects/effectloaders.cpp +++ /dev/null @@ -1,170 +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 "effectloaders.h" - -#include -#include -#include - -#include "nodes/oldeffectnode.h" -#include "effects/transition.h" -#include "global/path.h" -#include "panels/panels.h" -#include "panels/effectcontrols.h" -#include "global/config.h" - -#include "effects/internal/transformeffect.h" -#include "effects/internal/texteffect.h" -#include "effects/internal/timecodeeffect.h" -#include "effects/internal/solideffect.h" -#include "effects/internal/audionoiseeffect.h" -#include "effects/internal/toneeffect.h" -#include "effects/internal/volumeeffect.h" -#include "effects/internal/paneffect.h" -#include "effects/internal/shakeeffect.h" -#include "effects/internal/cornerpineffect.h" -#include "effects/internal/vsthost.h" -#include "effects/internal/fillleftrighteffect.h" -#include "effects/internal/richtexteffect.h" - -#include "effects/internal/crossdissolvetransition.h" -#include "effects/internal/linearfadetransition.h" -#include "effects/internal/logarithmicfadetransition.h" -#include "effects/internal/exponentialfadetransition.h" - -#include "nodes/nodes/nodemedia.h" -#include "nodes/nodes/nodetexturepassthru.h" -#include "nodes/nodes/nodeshader.h" - -QMutex olive::effects_loaded; - -void load_internal_effects() { - if (!olive::runtime_config.shaders_are_enabled) { - qWarning() << "Shaders are disabled, some effects may be nonfunctional"; - } - - olive::node_library.resize(kInvalidNode); - olive::node_library.fill(nullptr); - - olive::node_library[kTransformEffect] = std::make_shared(nullptr); - olive::node_library[kTextInput] = std::make_shared(nullptr); - olive::node_library[kSolidInput] = std::make_shared(nullptr); - olive::node_library[kNoiseInput] = std::make_shared(nullptr); - olive::node_library[kVolumeEffect] = std::make_shared(nullptr); - olive::node_library[kPanEffect] = std::make_shared(nullptr); - olive::node_library[kToneInput] = std::make_shared(nullptr); - olive::node_library[kShakeEffect] = std::make_shared(nullptr); - olive::node_library[kTimecodeEffect] = std::make_shared(nullptr); - olive::node_library[kFillLeftRightEffect] = std::make_shared(nullptr); - olive::node_library[kVstEffect] = std::make_shared(nullptr); - olive::node_library[kCornerPinEffect] = std::make_shared(nullptr); - olive::node_library[kRichTextInput] = std::make_shared(nullptr); - //olive::node_library[kMediaInput] = std::make_shared(nullptr); - //olive::node_library[kImageOutput] = std::make_shared(nullptr); - olive::node_library[kCrossDissolveTransition] = std::make_shared(nullptr); - olive::node_library[kLinearFadeTransition] = std::make_shared(nullptr); - olive::node_library[kExponentialFadeTransition] = std::make_shared(nullptr); - olive::node_library[kLogarithmicFadeTransition] = std::make_shared(nullptr); -} - -void load_shader_effects_worker(const QString& effects_path) { - QDir effects_dir(effects_path); - if (effects_dir.exists()) { - - QList entries = effects_dir.entryList({"*.xml"}, - QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); - - for (int i=0;i(nullptr, - effect_name, - effect_id, - effect_cat, - file_url)); - } else { - qCritical() << "Invalid effect found in" << entries.at(i); - } - break; - } - reader.readNext(); - } - - file.close(); - } - } - } -} - -void load_shader_effects() { - QList effects_paths = get_effects_paths(); - - for (int h=0;hstart(); -} - -EffectInit::EffectInit() { - olive::effects_loaded.lock(); -} - -void EffectInit::run() { - qInfo() << "Initializing effects..."; - load_internal_effects(); - load_shader_effects(); - olive::effects_loaded.unlock(); - qInfo() << "Finished initializing effects"; -} diff --git a/effects/effectloaders.h b/effects/effectloaders.h deleted file mode 100644 index dd137ac52..000000000 --- a/effects/effectloaders.h +++ /dev/null @@ -1,55 +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 EFFECTLOADERS_H -#define EFFECTLOADERS_H - -#include -#include -#include - -namespace olive { - extern QMutex effects_loaded; -} - -/** - * @brief The EffectInit class - * - * A separate thread for loading effects in the background while the rest of the program's initiation takes place. - * The program can even run before the effects have finished loading, but any point the software needs to access - * effects, it will have to wait for this thread to finish before it can. Fortunately this thread is usually very - * quick and is over before the MainWindow shows. - */ -class EffectInit : public QThread { -public: - EffectInit(); - - /** - * @brief A static convenience function to set up the EffectInit thread, start it, and free itself when complete. - */ - static void StartLoading(); -protected: - /** - * @brief Function that runs in the other thread. - */ - void run(); -}; - -#endif // EFFECTLOADERS_H diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp deleted file mode 100644 index fbd2b2ea0..000000000 --- a/effects/fields/boolfield.cpp +++ /dev/null @@ -1,99 +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 "boolfield.h" - -#include - -#include "nodes/node.h" -#include "undo/undo.h" - -BoolField::BoolField(NodeIO *parent) : - EffectField(parent, EffectField::EFFECT_FIELD_BOOL) -{} - -bool BoolField::GetBoolAt(double timecode) -{ - return GetValueAt(timecode).toBool(); -} - -QWidget *BoolField::CreateWidget(QWidget *existing) -{ - QCheckBox* cb; - - if (existing == nullptr) { - - cb = new QCheckBox(); - cb->setEnabled(IsEnabled()); - - } else { - - cb = static_cast(existing); - - } - - connect(cb, SIGNAL(toggled(bool)), this, SLOT(UpdateFromWidget(bool))); - connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); - connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(Toggled(bool))); - - return cb; -} - -void BoolField::UpdateWidgetValue(QWidget *widget, double timecode) -{ - QCheckBox* cb = static_cast(widget); - - // Setting the checked state on the checkbox below normally triggers a change() signal that will then trickle back - // to setting a value on this field. Therefore we block its signals while we're setting this. - - cb->blockSignals(true); - - if (qIsNaN(timecode)) { - cb->setTristate(true); - cb->setCheckState(Qt::PartiallyChecked); - } else { - cb->setTristate(false); - cb->setChecked(GetBoolAt(timecode)); - } - - cb->blockSignals(false); - - emit Toggled(cb->isChecked()); -} - -QVariant BoolField::ConvertStringToValue(const QString &s) -{ - return (s == "1"); -} - -QString BoolField::ConvertValueToString(const QVariant &v) -{ - return QString::number(v.toBool()); -} - -void BoolField::UpdateFromWidget(bool b) -{ - KeyframeDataChange* kdc = new KeyframeDataChange(this); - - SetValueAt(GetParentRow()->ParentNode()->Time(), b); - - kdc->SetNewKeyframes(); - olive::undo_stack.push(kdc); -} diff --git a/effects/fields/boolfield.h b/effects/fields/boolfield.h deleted file mode 100644 index 7595aab73..000000000 --- a/effects/fields/boolfield.h +++ /dev/null @@ -1,101 +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 BOOLFIELD_H -#define BOOLFIELD_H - -#include "../effectfield.h" - -/** - * @brief The BoolField class - * - * An EffectField derivative the produces boolean values (true or false) and uses a checkbox as its visual representation. - */ -class BoolField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - BoolField(NodeIO* parent); - - /** - * @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 Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a QCheckBox. - */ - virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; - - /** - * @brief Reimplementation of EffectField::ConvertStringToValue() - */ - virtual QVariant ConvertStringToValue(const QString& s) override; - - /** - * @brief Reimplementation of 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); -}; - -#endif // BOOLFIELD_H diff --git a/effects/fields/buttonfield.cpp b/effects/fields/buttonfield.cpp deleted file mode 100644 index 0e1e7c7f5..000000000 --- a/effects/fields/buttonfield.cpp +++ /dev/null @@ -1,66 +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 "buttonfield.h" - -#include - -ButtonField::ButtonField(NodeIO *parent, const QString &string) : - EffectField(parent, EffectField::EFFECT_FIELD_UI), - button_text_(string) -{} - -void ButtonField::SetCheckable(bool c) -{ - checkable_ = c; -} - -void ButtonField::SetChecked(bool c) -{ - checked_ = c; - emit CheckedChanged(c); -} - -QWidget *ButtonField::CreateWidget(QWidget *existing) -{ - QPushButton* button; - - if (existing == nullptr) { - - button = new QPushButton(); - - button->setCheckable(checkable_); - button->setEnabled(IsEnabled()); - button->setText(button_text_); - - } else { - - button = static_cast(existing); - - } - - connect(this, SIGNAL(CheckedChanged(bool)), button, SLOT(setChecked(bool))); - connect(this, SIGNAL(EnabledChanged(bool)), button, SLOT(setEnabled(bool))); - connect(button, SIGNAL(clicked(bool)), this, SIGNAL(Clicked())); - connect(button, SIGNAL(toggled(bool)), this, SLOT(SetChecked(bool))); - connect(button, SIGNAL(toggled(bool)), this, SIGNAL(Toggled(bool))); - - return button; -} diff --git a/effects/fields/buttonfield.h b/effects/fields/buttonfield.h deleted file mode 100644 index ac1ca842f..000000000 --- a/effects/fields/buttonfield.h +++ /dev/null @@ -1,111 +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 BUTTONFIELD_H -#define BUTTONFIELD_H - -#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 Reimplementation of EffectField::EffectField(). - */ - ButtonField(NodeIO* 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 Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a QPushButton. - */ - 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_; -}; - -#endif // BUTTONFIELD_H diff --git a/effects/fields/colorfield.cpp b/effects/fields/colorfield.cpp deleted file mode 100644 index 2a52c879a..000000000 --- a/effects/fields/colorfield.cpp +++ /dev/null @@ -1,73 +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 "colorfield.h" - -#include - -#include "ui/colorbutton.h" -#include "nodes/node.h" -#include "undo/undo.h" - -ColorField::ColorField(NodeIO* parent) : - EffectField(parent, EffectField::EFFECT_FIELD_COLOR) -{} - -QColor ColorField::GetColorAt(double timecode) -{ - return GetValueAt(timecode).value(); -} - -QWidget *ColorField::CreateWidget(QWidget *existing) -{ - ColorButton* cb = (existing != nullptr) ? static_cast(existing) : new ColorButton(); - - connect(cb, SIGNAL(color_changed(const QColor &)), this, SLOT(UpdateFromWidget(const QColor &))); - connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); - - return cb; -} - -void ColorField::UpdateWidgetValue(QWidget *widget, double timecode) -{ - ColorButton* cb = static_cast(widget); - - cb->set_color(GetColorAt(timecode)); -} - -QVariant ColorField::ConvertStringToValue(const QString &s) -{ - return QColor(s); -} - -QString ColorField::ConvertValueToString(const QVariant &v) -{ - return v.value().name(); -} - -void ColorField::UpdateFromWidget(const QColor& c) -{ - KeyframeDataChange* kdc = new KeyframeDataChange(this); - - SetValueAt(GetParentRow()->ParentNode()->Time(), c); - - kdc->SetNewKeyframes(); - olive::undo_stack.push(kdc); -} diff --git a/effects/fields/colorfield.h b/effects/fields/colorfield.h deleted file mode 100644 index 0744a25e6..000000000 --- a/effects/fields/colorfield.h +++ /dev/null @@ -1,88 +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 COLORFIELD_H -#define COLORFIELD_H - -#include "../effectfield.h" - -/** - * @brief The ColorField class - * - * An EffectField derivative that produces color values and uses a ColorButton as its UI representative. - */ -class ColorField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - ColorField(NodeIO* parent); - - /** - * @brief Get the color value at a given timecode - * - * A convenience function, equivalent to GetValueAt(timecode).value(). - * - * @param timecode - * - * The timecode to retrieve the color at - * - * @return - * - * The color value at this timecode - */ - QColor GetColorAt(double timecode); - - /** - * @brief CreateWidget - * - * Creates and connects to a ColorButton. - */ - virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; - - /** - * @brief Reimplementation of EffectField::ConvertStringToValue() - */ - virtual QVariant ConvertStringToValue(const QString& s) override; - - /** - * @brief Reimplementation of EffectField::ConvertValueToString() - */ - virtual QString ConvertValueToString(const QVariant& v) override; -private slots: - /** - * @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input - * - * @param b - * - * The current color selected by the QWidget (ColorButton in this case). Automatically triggered when this slot is - * connected to the ColorButton::color_changed() signal. - */ - void UpdateFromWidget(const QColor &c); -}; - -#endif // COLORFIELD_H diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp deleted file mode 100644 index 5779b00e8..000000000 --- a/effects/fields/combofield.cpp +++ /dev/null @@ -1,93 +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 "combofield.h" - -#include - -#include "nodes/node.h" -#include "ui/comboboxex.h" -#include "undo/undo.h" - -ComboField::ComboField(NodeIO* parent) : - EffectField(parent, EffectField::EFFECT_FIELD_COMBO) -{} - -void ComboField::AddItem(const QString &text, const QVariant &data) -{ - ComboFieldItem item; - - item.name = text; - item.data = data; - - items_.append(item); -} - -QWidget *ComboField::CreateWidget(QWidget *existing) -{ - ComboBoxEx* cb; - - if (existing == nullptr) { - cb = new ComboBoxEx(); - - cb->setScrollingEnabled(false); - - for (int i=0;iaddItem(items_.at(i).name); - } - } else { - cb = static_cast(existing); - } - - connect(cb, SIGNAL(activated(int)), this, SLOT(UpdateFromWidget(int))); - connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); - - return cb; -} - -void ComboField::UpdateWidgetValue(QWidget *widget, double timecode) -{ - QVariant data = GetValueAt(timecode); - - ComboBoxEx* cb = static_cast(widget); - - for (int i=0;iblockSignals(true); - cb->setCurrentIndex(i); - cb->blockSignals(false); - - emit DataChanged(data); - return; - } - } - - qWarning() << "Failed to set ComboField value from data"; -} - -void ComboField::UpdateFromWidget(int index) -{ - KeyframeDataChange* kdc = new KeyframeDataChange(this); - - SetValueAt(GetParentRow()->ParentNode()->Time(), items_.at(index).data); - - kdc->SetNewKeyframes(); - olive::undo_stack.push(kdc); -} diff --git a/effects/fields/combofield.h b/effects/fields/combofield.h deleted file mode 100644 index 76c199e1e..000000000 --- a/effects/fields/combofield.h +++ /dev/null @@ -1,113 +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 COMBOFIELD_H -#define COMBOFIELD_H - -#include "../effectfield.h" - -/** - * @brief The ComboFieldItem struct - * - * An internal string+value pair used to represent a combobox item. name is used for the UI - * representation of the choices and the data is what can be retrieved by code. - * - * \see ComboField::AddItem. - */ -struct ComboFieldItem { - QString name; - QVariant data; -}; - -/** - * @brief The ComboField class - * - * An EffectField derivative to produce arbitrary data based on a fixed selection of items. - */ -class ComboField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - ComboField(NodeIO* parent); - - /** - * @brief Add an item to this ComboField - * - * Adds a choice that the user can choose from this ComboField. All choices need text (for the on-screen - * choice) and data, which gets read on the backend. The selected data is what gets saved and loaded from - * project files, and therefore the data should be unique to this item. In case more items get added to - * this ComboField later, old project files will still open correctly. This is also why simple selected - * indices are not available. The text is only shown on the UI so it can be safely translated during runtime. - * - * @param text - * - * The text to show at this index. - * - * @param data - * - * The data to be retrieved at this index. - */ - void AddItem(const QString& text, const QVariant& data); - - /** - * @brief Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a QComboBox with the set of items added in AddItem(). - */ - virtual QWidget *CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; - -signals: - /** - * @brief Signal emitted whenever a connected widget's data gets changed - * - * Useful for UI events that need to occur with the change of this ComboField's value. - */ - void DataChanged(const QVariant&); - -private: - /** - * @brief Internal array of string+value pair items. - * - * \see ComboFieldItem - */ - QVector items_; - -private slots: - /** - * @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input - * - * @param b - * - * The current index of the QWidget (QComboBox in this case). Automatically set when this slot is connected - * to the QComboBox::currentIndexChanged() signal. This is the only time ComboFields deal with indices since the - * QComboBox's indices will match precisely to the items_ array. Outside of this function, QVariant data is preferred. - */ - void UpdateFromWidget(int index); -}; - -#endif // COMBOFIELD_H diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp deleted file mode 100644 index 5b8033249..000000000 --- a/effects/fields/doublefield.cpp +++ /dev/null @@ -1,151 +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 "doublefield.h" - -#include "nodes/node.h" -#include "undo/undo.h" - -DoubleField::DoubleField(NodeIO* parent) : - EffectField(parent, EffectField::EFFECT_FIELD_DOUBLE), - min_(qSNaN()), - max_(qSNaN()), - default_(0), - display_type_(LabelSlider::Normal), - frame_rate_(30), - value_set_(false), - kdc_(nullptr) -{ - connect(this, SIGNAL(Changed()), this, SLOT(ValueHasBeenSet()), Qt::DirectConnection); -} - -double DoubleField::GetDoubleAt(double timecode) -{ - return GetValueAt(timecode).toDouble(); -} - -void DoubleField::SetMinimum(double minimum) -{ - min_ = minimum; - emit MinimumChanged(min_); -} - -void DoubleField::SetMaximum(double maximum) -{ - max_ = maximum; - emit MaximumChanged(max_); -} - -void DoubleField::SetDefault(double d) -{ - default_ = d; - - if (!value_set_) { - SetValueAt(0, d); - } -} - -void DoubleField::SetDisplayType(LabelSlider::DisplayType type) -{ - display_type_ = type; -} - -void DoubleField::SetFrameRate(const double &rate) -{ - frame_rate_ = rate; -} - -QVariant DoubleField::ConvertStringToValue(const QString &s) -{ - return s.toDouble(); -} - -QString DoubleField::ConvertValueToString(const QVariant &v) -{ - return QString::number(v.toDouble()); -} - -QWidget *DoubleField::CreateWidget(QWidget *existing) -{ - LabelSlider* ls; - - if (existing == nullptr) { - - ls = new LabelSlider(); - - if (!qIsNaN(min_)) { - ls->SetMinimum(min_); - } - ls->SetDefault(default_); - if (!qIsNaN(max_)) { - ls->SetMaximum(max_); - } - ls->SetDisplayType(display_type_); - ls->SetFrameRate(frame_rate_); - - ls->setEnabled(IsEnabled()); - - } else { - - ls = static_cast(existing); - - } - - connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double))); - connect(ls, SIGNAL(clicked()), this, SIGNAL(Clicked())); - connect(this, SIGNAL(EnabledChanged(bool)), ls, SLOT(setEnabled(bool))); - connect(this, SIGNAL(MaximumChanged(double)), ls, SLOT(SetMaximum(double))); - connect(this, SIGNAL(MinimumChanged(double)), ls, SLOT(SetMinimum(double))); - - return ls; -} - -void DoubleField::UpdateWidgetValue(QWidget *widget, double timecode) -{ - if (qIsNaN(timecode)) { - static_cast(widget)->SetValue(qSNaN()); - } else { - static_cast(widget)->SetValue(GetDoubleAt(timecode)); - } -} - -void DoubleField::ValueHasBeenSet() -{ - value_set_ = true; -} - -void DoubleField::UpdateFromWidget(double d) -{ - LabelSlider* ls = static_cast(sender()); - - if (ls->IsDragging() && kdc_ == nullptr) { - kdc_ = new KeyframeDataChange(this); - } - - SetValueAt(GetParentRow()->ParentNode()->Time(), d); - - if (!ls->IsDragging() && kdc_ != nullptr) { - kdc_->SetNewKeyframes(); - - olive::undo_stack.push(kdc_); - - kdc_ = nullptr; - } -} diff --git a/effects/fields/doublefield.h b/effects/fields/doublefield.h deleted file mode 100644 index 33a91d434..000000000 --- a/effects/fields/doublefield.h +++ /dev/null @@ -1,210 +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 DOUBLEFIELD_H -#define DOUBLEFIELD_H - -#include "../effectfield.h" -#include "ui/labelslider.h" - -class KeyframeDataChange; - -/** - * @brief The DoubleField class - * - * An EffectField derivative the produces number values (integer or floating-point) and uses a LabelSlider as its - * visual representation. - */ -class DoubleField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - DoubleField(NodeIO* parent); - - /** - * @brief Get double value at timecode - * - * Convenience function. Equivalent to GetValueAt().toDouble() - * - * @param timecode - * - * Timecode to retrieve value at - * - * @return - * - * Double value at the set timecode - */ - double GetDoubleAt(double timecode); - - /** - * @brief Sets the minimum allowed number for the user to set to `minimum`. - */ - void SetMinimum(double minimum); - - /** - * @brief Sets the maximum allowed number for the user to set to `maximum`. - */ - void SetMaximum(double maximum); - - /** - * @brief Sets the default number for this field to `d`. - */ - void SetDefault(double d); - - /** - * @brief Sets the UI display type to a member of LabelSlider::DisplayType. - */ - void SetDisplayType(LabelSlider::DisplayType type); - - /** - * @brief For a timecode-based display type, sets the frame rate to be used for the displayed timecode - * - * \see SetDisplayType() and LabelSlider::SetFrameRate(). - */ - void SetFrameRate(const double& rate); - - /** - * @brief Reimplementation of EffectField::ConvertStringToValue() - */ - virtual QVariant ConvertStringToValue(const QString& s) override; - - /** - * @brief Reimplementation of EffectField::ConvertValueToString() - */ - virtual QString ConvertValueToString(const QVariant& v) override; - - /** - * @brief Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a LabelSlider. - */ - virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; -signals: - /** - * @brief Signal emitted when the field's maximum value has changed - * - * This signal gets connected to any LabelSlider created from CreateWidget() so the maximum value is - * always synchronized between them. - * - * Note: A connection is not made both ways as you should never manipulate a UI object created from - * an EffectField directly. Always access data through the EffectField itself. - * - * \see SetMaximum() - * - * @param maximum - * - * The new maximum value. - */ - void MaximumChanged(double maximum); - - /** - * @brief Signal emitted when the field's minimum value has changed - * - * This signal gets connected to any LabelSlider created from CreateWidget() so the minimum value is - * always synchronized between them. - * - * Note: A connection is not made both ways as you should never manipulate a UI object created from - * an EffectField directly. Always access data through the EffectField itself. - * - * \see SetMinimum() - * - * @param minimum - * - * The new minimum value. - */ - void MinimumChanged(double minimum); -private: - /** - * @brief Internal minimum value - * - * \see SetMinimum(). - */ - double min_; - - /** - * @brief Internal maximum value - * - * \see SetMaximum(). - */ - double max_; - - /** - * @brief Internal default value - * - * \see SetDefault(). - */ - double default_; - - /** - * @brief Internal display type value - * - * \see SetDisplayType(). - */ - LabelSlider::DisplayType display_type_; - - /** - * @brief Internal frame rate value - * - * \see SetFrameRate(). - */ - double frame_rate_; - - /** - * @brief Internal value used to allow SetDefault() to set the value as well if none has been set - * - * Initialized to FALSE, then set to TRUE indefinitely whenever the value gets set on this field. - */ - bool value_set_; - - /** - * @brief An internal KeyframeDataChange undoable command - * - * This is stored to allow for the value to be changed by dragging without every single "step" being pushed to - * the undo stack. Instead an undo command can be created at the start of a drag, and then pushed at the end - * to make it one single undoable action. - */ - KeyframeDataChange* kdc_; -private slots: - /** - * @brief Connected to EffectField::Changed() to ensure value_set_ gets set to TRUE whenever a value is set on this - * field. - */ - void ValueHasBeenSet(); - - /** - * @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input - * - * @param b - * - * The current number value of the QWidget (LabelSlider in this case). Automatically set when this slot is connected - * to the LabelSlider::valueChanged() signal. - */ - void UpdateFromWidget(double d); -}; - -#endif // DOUBLEFIELD_H diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp deleted file mode 100644 index 4258227ed..000000000 --- a/effects/fields/filefield.cpp +++ /dev/null @@ -1,68 +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 "filefield.h" - -#include - -#include "ui/embeddedfilechooser.h" -#include "nodes/node.h" -#include "undo/undo.h" - -FileField::FileField(NodeIO* parent) : - EffectField(parent, EffectField::EFFECT_FIELD_FILE) -{ - // Set default value to an empty string - SetValueAt(0, ""); -} - -QString FileField::GetFileAt(double timecode) -{ - return GetValueAt(timecode).toString(); -} - -QWidget *FileField::CreateWidget(QWidget *existing) -{ - EmbeddedFileChooser* efc = (existing != nullptr) ? static_cast(existing) : new EmbeddedFileChooser(); - - connect(efc, SIGNAL(changed(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); - connect(this, SIGNAL(EnabledChanged(bool)), efc, SLOT(setEnabled(bool))); - - 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); - - SetValueAt(GetParentRow()->ParentNode()->Time(), s); - - kdc->SetNewKeyframes(); - olive::undo_stack.push(kdc); -} diff --git a/effects/fields/filefield.h b/effects/fields/filefield.h deleted file mode 100644 index 032ef93ee..000000000 --- a/effects/fields/filefield.h +++ /dev/null @@ -1,79 +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 FILEFIELD_H -#define FILEFIELD_H - -#include "../effectfield.h" - -/** - * @brief The FileInput class - * - * An EffectField derivative that produces filenames in string and uses an EmbeddedFileChooser - * as its visual representation. - */ -class FileField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - FileField(NodeIO* parent); - - /** - * @brief Get the filename at the given timecode - * - * A convenience function, equivalent to GetValueAt(timecode).toString() - * - * @param timecode - * - * The timecode to retrieve the filename at - * - * @return - * - * The filename at this timecode - */ - QString GetFileAt(double timecode); - - /** - * @brief Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a EmbeddedFileChooser. - */ - virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget *widget, double timecode) override; -private slots: - /** - * @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input - * - * @param b - * - * The current string of the QWidget (TextEditEx in this case). Automatically set when this slot - * is connected to the TextEditEx::textModified() signal. - */ - void UpdateFromWidget(const QString &s); -}; - -#endif // FILEFIELD_H diff --git a/effects/fields/fontfield.cpp b/effects/fields/fontfield.cpp deleted file mode 100644 index 282becff5..000000000 --- a/effects/fields/fontfield.cpp +++ /dev/null @@ -1,95 +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 "fontfield.h" - -#include -#include - -#include "ui/comboboxex.h" -#include "nodes/node.h" -#include "undo/undo.h" - -// NOTE/TODO: This shares a lot of similarity with ComboInput, and could probably be a derived class of it - -FontField::FontField(NodeIO* parent) : - EffectField(parent, EffectField::EFFECT_FIELD_FONT) -{ - font_list = QFontDatabase().families(); - - SetValueAt(0, font_list.first()); -} - -QString FontField::GetFontAt(double timecode) -{ - return GetValueAt(timecode).toString(); -} - -QWidget *FontField::CreateWidget(QWidget *existing) -{ - ComboBoxEx* fcb = new ComboBoxEx(); - - if (existing == nullptr) { - - fcb = new ComboBoxEx(); - - fcb->setScrollingEnabled(false); - - fcb->addItems(font_list); - - } else { - - fcb = static_cast(existing); - - } - - connect(fcb, SIGNAL(currentTextChanged(const QString &)), this, SLOT(UpdateFromWidget(const QString &))); - connect(this, SIGNAL(EnabledChanged(bool)), fcb, SLOT(setEnabled(bool))); - - return fcb; -} - -void FontField::UpdateWidgetValue(QWidget *widget, double timecode) -{ - QVariant data = GetValueAt(timecode); - - ComboBoxEx* cb = static_cast(widget); - - for (int i=0;iblockSignals(true); - cb->setCurrentIndex(i); - cb->blockSignals(false); - return; - } - } - - qWarning() << "Failed to set FontField value from data"; -} - -void FontField::UpdateFromWidget(const QString& s) -{ - KeyframeDataChange* kdc = new KeyframeDataChange(this); - - SetValueAt(GetParentRow()->ParentNode()->Time(), s); - - kdc->SetNewKeyframes(); - olive::undo_stack.push(kdc); -} diff --git a/effects/fields/fontfield.h b/effects/fields/fontfield.h deleted file mode 100644 index 50ef9a509..000000000 --- a/effects/fields/fontfield.h +++ /dev/null @@ -1,88 +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 FONTFIELD_H -#define FONTFIELD_H - -#include "combofield.h" - -/** - * @brief The FontField class - * - * An EffectField derivative the produces font family names in string and uses a QComboBox - * as its visual representation. - * - * TODO Upgrade to QFontComboBox. - */ -class FontField : public EffectField { - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - FontField(NodeIO* parent); - - /** - * @brief Get the font family name at the given timecode - * - * A convenience function, equivalent to GetValueAt(timecode).toString() - * - * @param timecode - * - * The timecode to retrieve the font family name at - * - * @return - * - * The font family name at this timecode - */ - QString GetFontAt(double timecode); - - /** - * @brief Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a QComboBox. - */ - virtual QWidget *CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; - -private: - /** - * @brief Internal list of fonts to add to a QComboBox when creating one in CreateWidget(). - * - * NOTE: Deprecated. Once QComboBox is replaced by QFontComboBox this will be completely unnecessary. - */ - QStringList font_list; -private slots: - /** - * @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input - * - * @param b - * - * The current font name specified by the QWidget (QComboBox in this case). Automatically set when this slot - * is connected to the QComboBox::currentTextChanged() signal. - */ - void UpdateFromWidget(const QString& index); -}; - -#endif // FONTFIELD_H diff --git a/effects/fields/labelfield.cpp b/effects/fields/labelfield.cpp deleted file mode 100644 index ee6ecbfd5..000000000 --- a/effects/fields/labelfield.cpp +++ /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 . - -***/ - -#include "labelfield.h" - -#include - -LabelField::LabelField(NodeIO *parent, const QString &string) : - EffectField(parent, EffectField::EFFECT_FIELD_UI), - label_text_(string) -{} - -QWidget *LabelField::CreateWidget(QWidget *existing) -{ - QLabel* label; - - if (existing == nullptr) { - - label = new QLabel(label_text_); - - label->setEnabled(IsEnabled()); - - } else { - - label = static_cast(existing); - - } - - connect(this, SIGNAL(EnabledChanged(bool)), label, SLOT(setEnabled(bool))); - - return label; -} diff --git a/effects/fields/labelfield.h b/effects/fields/labelfield.h deleted file mode 100644 index a2cb05d23..000000000 --- a/effects/fields/labelfield.h +++ /dev/null @@ -1,55 +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 LABELFIELD_H -#define LABELFIELD_H - -#include "../effectfield.h" - -/** - * @brief The LabelField class - * - * A UI-type EffectField. This field is largely an EffectField wrapper around a QLabel and provides no data that's - * usable in the Effect. It's primarily useful for showing UI information. This field is not exposed to the external - * shader API as it requires raw C++ code to connect it to other elements. - */ -class LabelField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - */ - LabelField(NodeIO* parent, const QString& string); - - /** - * @brief Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a QLabel. - */ - virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; -private: - /** - * @brief Internal text string - */ - QString label_text_; -}; - -#endif // LABELFIELD_H diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp deleted file mode 100644 index 4f1d1470e..000000000 --- a/effects/fields/stringfield.cpp +++ /dev/null @@ -1,101 +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 "stringfield.h" - -#include -#include - -#include "nodes/node.h" -#include "ui/texteditex.h" -#include "global/config.h" -#include "undo/undo.h" - -StringField::StringField(NodeIO* parent, bool rich_text) : - EffectField(parent, EffectField::EFFECT_FIELD_STRING), - rich_text_(rich_text) -{ - // Set default value to an empty string - SetValueAt(0, ""); -} - -QString StringField::GetStringAt(double timecode) -{ - return GetValueAt(timecode).toString(); -} - -QWidget *StringField::CreateWidget(QWidget *existing) -{ - TextEditEx* text_edit; - - if (existing == nullptr) { - - text_edit = new TextEditEx(nullptr, rich_text_); - - text_edit->setEnabled(IsEnabled()); - text_edit->setUndoRedoEnabled(true); - - // the "2" is because the height needs one extra pixel of padding on the top and the bottom - text_edit->setTextHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::config.effect_textbox_lines - + text_edit->document()->documentMargin() - + text_edit->document()->documentMargin() + 2)); - - } else { - - text_edit = static_cast(existing); - - } - - connect(text_edit, SIGNAL(textModified(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); - connect(this, SIGNAL(EnabledChanged(bool)), text_edit, SLOT(setEnabled(bool))); - - return text_edit; -} - -void StringField::UpdateWidgetValue(QWidget *widget, double timecode) -{ - TextEditEx* text = static_cast(widget); - - text->blockSignals(true); - - int pos = text->textCursor().position(); - - if (rich_text_) { - text->setHtml(GetValueAt(timecode).toString()); - } else { - text->setPlainText(GetValueAt(timecode).toString()); - } - - QTextCursor new_cursor(text->document()); - new_cursor.setPosition(pos); - text->setTextCursor(new_cursor); - - text->blockSignals(false); -} - -void StringField::UpdateFromWidget(const QString &s) -{ - KeyframeDataChange* kdc = new KeyframeDataChange(this); - - SetValueAt(GetParentRow()->ParentNode()->Time(), s); - - kdc->SetNewKeyframes(); - olive::undo_stack.push(kdc); -} diff --git a/effects/fields/stringfield.h b/effects/fields/stringfield.h deleted file mode 100644 index d18cd84ed..000000000 --- a/effects/fields/stringfield.h +++ /dev/null @@ -1,87 +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 STRINGFIELD_H -#define STRINGFIELD_H - -#include "../effectfield.h" - -/** - * @brief The StringField class - * - * An EffectField derivative that produces arbitrary strings entered by the user and uses a TextEditEx as its - * visual representation. - */ -class StringField : public EffectField -{ - Q_OBJECT -public: - /** - * @brief Reimplementation of EffectField::EffectField(). - * - * Provides a setting for whether this StringField - and its attached TextEditEx objects - should operate in rich - * text or plain text mode, defaulting to rich text mode. - */ - StringField(NodeIO* parent, bool rich_text = true); - - /** - * @brief Get the string at the given timecode - * - * A convenience function, equivalent to GetValueAt(timecode).toString() - * - * @param timecode - * - * The timecode to retrieve the string at - * - * @return - * - * The string at this timecode - */ - QString GetStringAt(double timecode); - - /** - * @brief Reimplementation of EffectField::CreateWidget() - * - * Creates and connects to a TextEditEx. - */ - virtual QWidget *CreateWidget(QWidget *existing = nullptr) override; - - /** - * @brief Reimplementation of EffectField::UpdateWidgetValue() - */ - virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; -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 (EmbeddedFileChooser in this case). Automatically set when this slot - * is connected to the EmbeddedFileChooser::changed() signal. - */ - void UpdateFromWidget(const QString& b); -private: - /** - * @brief Internal value for whether this field is in rich text or plain text mode - */ - bool rich_text_; -}; - -#endif // STRINGFIELD_H diff --git a/effects/internal/audionoiseeffect.cpp b/effects/internal/audionoiseeffect.cpp deleted file mode 100644 index 839f6b2e9..000000000 --- a/effects/internal/audionoiseeffect.cpp +++ /dev/null @@ -1,94 +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 "audionoiseeffect.h" - -#include -#include - -AudioNoiseEffect::AudioNoiseEffect(Clip* c) : OldEffectNode(c) { - amount_val = new DoubleInput(this, "amount", tr("Amount")); - amount_val->SetMinimum(0); - amount_val->SetDefault(20); - amount_val->SetMaximum(100); - - mix_val = new BoolInput(this, "mix", tr("Mix")); - mix_val->SetValueAt(0, true); -} - -QString AudioNoiseEffect::name() -{ - return tr("Noise"); -} - -QString AudioNoiseEffect::id() -{ - return "org.olivevideoeditor.Olive.noise"; -} - -QString AudioNoiseEffect::description() -{ - return tr("Generate audio noise that can be mixed with this clip."); -} - -EffectType AudioNoiseEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType AudioNoiseEffect::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr AudioNoiseEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void AudioNoiseEffect::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - - Q_UNUSED(type) - - double interval = (timecode_end - timecode_start)/nb_samples; - for (int i=0;iGetDoubleAt(timecode)*0.01 ); - - for (int j=0;jrandomFloat() * vol; - - // mix with source audio - if (mix_val->GetBoolAt(timecode)) { - samples[j][i] += noise_sample; - } else { - samples[j][i] = noise_sample; - } - } - } -} diff --git a/effects/internal/audionoiseeffect.h b/effects/internal/audionoiseeffect.h deleted file mode 100644 index cebbf07b4..000000000 --- a/effects/internal/audionoiseeffect.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 AUDIONOISEEFFECT_H -#define AUDIONOISEEFFECT_H - -#include "nodes/oldeffectnode.h" - -class AudioNoiseEffect : public OldEffectNode { - Q_OBJECT -public: - AudioNoiseEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; - - DoubleInput* amount_val; - BoolInput* mix_val; -}; - -#endif // AUDIONOISEEFFECT_H diff --git a/effects/internal/common.vert b/effects/internal/common.vert deleted file mode 100644 index d698c628e..000000000 --- a/effects/internal/common.vert +++ /dev/null @@ -1,8 +0,0 @@ -#version 110 - -varying vec2 vTexCoord; - -void main() { - vTexCoord = gl_MultiTexCoord0.xy; - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; -} \ No newline at end of file diff --git a/effects/internal/cornerpin.frag b/effects/internal/cornerpin.frag deleted file mode 100644 index 1eba35cc1..000000000 --- a/effects/internal/cornerpin.frag +++ /dev/null @@ -1,46 +0,0 @@ -#version 130 - -uniform sampler2D tex; -uniform bool perspective; - -varying vec2 q; -varying vec2 b1; -varying vec2 b2; -varying vec2 b3; -varying vec2 vTexCoord; - -float Wedge2D(vec2 v, vec2 w) { - return (v.x*w.y) - (v.y*w.x); -} - -void main(void) { - if (perspective) { - gl_FragColor = texture2D(tex, vTexCoord); - } else { - float A = Wedge2D(b2, b3); - float B = Wedge2D(b3, q) - Wedge2D(b1, b2); - float C = Wedge2D(b1, q); - - vec2 uv; - - // solve for v - if (abs(A) < 0.001) { - uv.y = -C/B; - } else { - float discrim = B*B - 4.0*A*C; - uv.y = 0.5 * (-B + sqrt(discrim)) / A; - } - - // solve for u - vec2 denom = b1 + uv.y * b3; - if (abs(denom.x) > abs(denom.y)) { - uv.x = (q.x - b2.x * uv.y) / denom.x; - } else { - uv.x = (q.y - b2.y * uv.y) / denom.y; - } - - uv.y = 1.0 - uv.y; - - gl_FragColor = texture2D(tex, uv); - } -} \ No newline at end of file diff --git a/effects/internal/cornerpin.vert b/effects/internal/cornerpin.vert deleted file mode 100644 index ee96216a0..000000000 --- a/effects/internal/cornerpin.vert +++ /dev/null @@ -1,66 +0,0 @@ -#version 130 - -uniform bool perspective; -uniform vec2 p0; -uniform vec2 p1; -uniform vec2 p2; -uniform vec2 p3; - -varying vec2 q; -varying vec2 b1; -varying vec2 b2; -varying vec2 b3; -varying vec2 vTexCoord; - -void main() { - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - - if (perspective) { - float m1 = (p3.y - p0.y)/(p3.x - p0.x); - float c1 = p0.y - m1 * p0.x; - float m2 = (p1.y - p2.y)/(p1.x - p2.x); - float c2 = p2.y - m2 * p2.x; - float mid_x = (c2 - c1) / (m1 - m2); - float mid_y = m1 * mid_x + c1; - - float d0 = length(vec2(mid_x - p0.x, mid_y - p0.y)); - float d1 = length(vec2(p1.x - mid_x, mid_y - p1.y)); - float d2 = length(vec2(p3.x - mid_x, p3.y - mid_y)); - float d3 = length(vec2(mid_x - p2.x, p2.y - mid_y)); - - float q; - - if (gl_VertexID == 0) { - q = (d1+d3)/d3; - } else if (gl_VertexID == 1) { - q = (d0+d2)/d2; - } else if (gl_VertexID == 2) { - q = (d3+d1)/d1; - } else { - q = (d2+d0)/d0; - } - - gl_Position[0] *= q; - gl_Position[1] *= q; - gl_Position[3] = q; - - vTexCoord = gl_MultiTexCoord0.xy; - } else { - vec2 pos; - - if (gl_VertexID == 0) { // top left - pos = p2; - } else if (gl_VertexID == 1) { // top right - pos = p3; - } else if (gl_VertexID == 2) { // bottom right - pos = p1; - } else if (gl_VertexID == 3) { // bottom left - pos = p0; - } - - q = pos - p0; - b1 = p1 - p0; - b2 = p2 - p0; - b3 = p0 - p1 - p2 + p3; - } -} \ No newline at end of file diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp deleted file mode 100644 index 7b7c4b9a6..000000000 --- a/effects/internal/cornerpineffect.cpp +++ /dev/null @@ -1,116 +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 "cornerpineffect.h" - -#include "global/path.h" -#include "timeline/clip.h" -#include "global/debug.h" - -CornerPinEffect::CornerPinEffect(Clip* c) : OldEffectNode(c) { - SetFlags(OldEffectNode::CoordsFlag | OldEffectNode::ShaderFlag); - - top_left = new Vec2Input(this, "topleft", tr("Top Left")); - - top_right = new Vec2Input(this, "topright", tr("Top Right")); - - bottom_left = new Vec2Input(this, "bottomleft", tr("Bottom Left")); - - bottom_right = new Vec2Input(this, "bottomright", tr("Bottom Right")); - - perspective = new BoolInput(this, "perspective", tr("Perspective")); - perspective->SetValueAt(0, true); - - top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_left_gizmo->x_field1 = static_cast(top_left->Field(0)); - top_left_gizmo->y_field1 = static_cast(top_left->Field(1)); - - top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->x_field1 = static_cast(top_right->Field(0)); - top_right_gizmo->y_field1 = static_cast(top_right->Field(1)); - - bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->x_field1 = static_cast(bottom_left->Field(0)); - bottom_left_gizmo->y_field1 = static_cast(bottom_left->Field(1)); - - bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->x_field1 = static_cast(bottom_right->Field(0)); - bottom_right_gizmo->y_field1 = static_cast(bottom_right->Field(1)); - - shader_vert_path_ = "cornerpin.vert"; - shader_frag_path_ = "cornerpin.frag"; -} - -QString CornerPinEffect::name() -{ - return tr("Corner Pin"); -} - -QString CornerPinEffect::id() -{ - return "org.olivevideoeditor.Olive.cornerpin"; -} - -QString CornerPinEffect::category() -{ - return tr("Distort"); -} - -QString CornerPinEffect::description() -{ - return tr("Distort/warp this clip by pinning each of its four corners."); -} - -EffectType CornerPinEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType CornerPinEffect::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr CornerPinEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) { - coords.vertex_top_left += top_left->GetVector2DAt(timecode); - coords.vertex_top_right += top_right->GetVector2DAt(timecode); - coords.vertex_bottom_left += bottom_left->GetVector2DAt(timecode); - coords.vertex_bottom_right += bottom_right->GetVector2DAt(timecode); -} - -void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords, int) { - shader_program_->setUniformValue("p0", coords.vertex_bottom_left.x(), coords.vertex_bottom_left.y()); - shader_program_->setUniformValue("p1", coords.vertex_bottom_right.x(), coords.vertex_bottom_right.y()); - shader_program_->setUniformValue("p2", coords.vertex_top_left.x(), coords.vertex_top_left.y()); - shader_program_->setUniformValue("p3", coords.vertex_top_right.x(), coords.vertex_top_right.y()); - shader_program_->setUniformValue("perspective", perspective->GetBoolAt(timecode)); -} - -void CornerPinEffect::gizmo_draw(double, GLTextureCoords &coords) { - top_left_gizmo->world_pos[0] = coords.vertex_top_left; - top_right_gizmo->world_pos[0] = coords.vertex_top_right; - bottom_right_gizmo->world_pos[0] = coords.vertex_bottom_right; - bottom_left_gizmo->world_pos[0] = coords.vertex_bottom_left; -} diff --git a/effects/internal/cornerpineffect.h b/effects/internal/cornerpineffect.h deleted file mode 100644 index a9ecbb2ad..000000000 --- a/effects/internal/cornerpineffect.h +++ /dev/null @@ -1,56 +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 CORNERPINEFFECT_H -#define CORNERPINEFFECT_H - -#include "nodes/oldeffectnode.h" - -class CornerPinEffect : public OldEffectNode { - Q_OBJECT -public: - CornerPinEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - void process_coords(double timecode, GLTextureCoords& coords, int data); - void process_shader(double timecode, GLTextureCoords& coords, int iterations); - void gizmo_draw(double timecode, GLTextureCoords& coords); -private: - Vec2Input* top_left; - Vec2Input* top_right; - Vec2Input* bottom_left; - Vec2Input* bottom_right; - - BoolInput* perspective; - - EffectGizmo* top_left_gizmo; - EffectGizmo* top_right_gizmo; - EffectGizmo* bottom_left_gizmo; - EffectGizmo* bottom_right_gizmo; -}; - -#endif // CORNERPINEFFECT_H diff --git a/effects/internal/crossdissolvetransition.cpp b/effects/internal/crossdissolvetransition.cpp deleted file mode 100644 index d98869018..000000000 --- a/effects/internal/crossdissolvetransition.cpp +++ /dev/null @@ -1,70 +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 "crossdissolvetransition.h" - -#include - -CrossDissolveTransition::CrossDissolveTransition(Clip* c) : Transition(c) { - SetFlags(OldEffectNode::CoordsFlag); -} - -QString CrossDissolveTransition::name() -{ - return tr("Cross Dissolve"); -} - -QString CrossDissolveTransition::id() -{ - return "org.olivevideoeditor.Olive.crossdissolve"; -} - -QString CrossDissolveTransition::category() -{ - return tr("Dissolves"); -} - -QString CrossDissolveTransition::description() -{ - return tr("Dissolve clips evenly."); -} - -EffectType CrossDissolveTransition::type() -{ - return EFFECT_TYPE_TRANSITION; -} - -olive::TrackType CrossDissolveTransition::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr CrossDissolveTransition::Create(Clip *c) -{ - return std::make_shared(c); -} - -void CrossDissolveTransition::process_coords(double progress, GLTextureCoords& coords, int data) { - if (data == kTransitionClosing) { - coords.opacity *= (1.0 - progress); - } else { - coords.opacity *= progress; - } -} diff --git a/effects/internal/crossdissolvetransition.h b/effects/internal/crossdissolvetransition.h deleted file mode 100644 index 13d33f5d5..000000000 --- a/effects/internal/crossdissolvetransition.h +++ /dev/null @@ -1,41 +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 CROSSDISSOLVETRANSITION_H -#define CROSSDISSOLVETRANSITION_H - -#include "effects/transition.h" - -class CrossDissolveTransition : public Transition { -public: - CrossDissolveTransition(Clip *c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_coords(double timecode, GLTextureCoords &, int data) override; -}; - -#endif // CROSSDISSOLVETRANSITION_H diff --git a/effects/internal/cubetransition.h b/effects/internal/cubetransition.h deleted file mode 100644 index f6c5910d3..000000000 --- a/effects/internal/cubetransition.h +++ /dev/null @@ -1,32 +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 CUBETRANSITION_H -#define CUBETRANSITION_H - -#include "effects/transition.h" - -class CubeTransition : public Transition { -public: - CubeTransition(Clip* c, Clip* s); - void process_coords(double timecode, GLTextureCoords &, int data); -}; - -#endif // CUBETRANSITION_H diff --git a/effects/internal/dropshadow.frag b/effects/internal/dropshadow.frag deleted file mode 100644 index 402c4c547..000000000 --- a/effects/internal/dropshadow.frag +++ /dev/null @@ -1,46 +0,0 @@ -#version 110 - -uniform sampler2D image; - -uniform vec2 resolution; - -uniform int shadow; -uniform vec3 shadowcolor; -uniform float shadowsoftness; -uniform float shadowopacity; -uniform float shadowdistance; - -varying vec2 vTexCoord; - -void main(void) { - /* - vec4 master_px = texture2D(image, vTexCoord); - if (shadow == 1) { - vec2 shadow_dist = vec2(shadowdistance)/resolution; - - float shadow_opacity = 0.01*shadowopacity; - - vec4 shadowed_px = vec4(shadowcolor.r, shadowcolor.g, shadowcolor.b, shadow_opacity*texture2D(image, vTexCoord-shadow_dist).a); - - float rad = floor(shadowsoftness); - if (rad > 0.0) { - shadowed_px.a = 0.0; - float divider = (1.0 / pow(rad, 2.0))*shadow_opacity; - for (float x=-rad+0.5;x<=rad;x+=2.0) { - for (float y=-rad+0.5;y<=rad;y+=2.0) { - shadowed_px.a += shadow_opacity*texture2D(image, vTexCoord-shadow_dist+(vec2(x, y)/resolution)).a*divider; - } - } - } - - vec4 shadow_blend = (shadowed_px*(1.0-master_px.a)); - - vec4 composition = mix(shadow_blend, master_px, master_px.a); - - gl_FragColor = composition; - } else { - gl_FragColor = master_px; - } - */ - gl_FragColor = texture2D(image, vTexCoord); -} \ No newline at end of file diff --git a/effects/internal/dropshadoweffect.cpp b/effects/internal/dropshadoweffect.cpp deleted file mode 100644 index 3d2a178ef..000000000 --- a/effects/internal/dropshadoweffect.cpp +++ /dev/null @@ -1,25 +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 "dropshadoweffect.h" - -DropShadowEffect::DropShadowEffect() { - -} diff --git a/effects/internal/dropshadoweffect.h b/effects/internal/dropshadoweffect.h deleted file mode 100644 index e6bcdbc81..000000000 --- a/effects/internal/dropshadoweffect.h +++ /dev/null @@ -1,31 +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 DROPSHADOWEFFECT_H -#define DROPSHADOWEFFECT_H - - -class DropShadowEffect -{ -public: - DropShadowEffect(); -}; - -#endif // DROPSHADOWEFFECT_H diff --git a/effects/internal/exponentialfadetransition.cpp b/effects/internal/exponentialfadetransition.cpp deleted file mode 100644 index 095e149f5..000000000 --- a/effects/internal/exponentialfadetransition.cpp +++ /dev/null @@ -1,83 +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 "exponentialfadetransition.h" - -#include - -ExponentialFadeTransition::ExponentialFadeTransition(Clip* c) : - Transition(c) -{ -} - -QString ExponentialFadeTransition::name() -{ - return tr("Exponential Fade"); -} - -QString ExponentialFadeTransition::id() -{ - return "org.olivevideoeditor.Olive.exponentialfade"; -} - -QString ExponentialFadeTransition::description() -{ - return tr("An exponential audio fade that starts slow and ends fast."); -} - -EffectType ExponentialFadeTransition::type() -{ - return EFFECT_TYPE_TRANSITION; -} - -olive::TrackType ExponentialFadeTransition::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr ExponentialFadeTransition::Create(Clip *c) -{ - return std::make_shared(c); -} - -void ExponentialFadeTransition::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - double interval = (timecode_end-timecode_start)/nb_samples; - - for (int i=0;i. - -***/ - -#ifndef EXPONENTIALFADETRANSITION_H -#define EXPONENTIALFADETRANSITION_H - -#include "effects/transition.h" - -class ExponentialFadeTransition : public Transition { -public: - ExponentialFadeTransition(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; -}; - -#endif // LINEARFADETRANSITION_H diff --git a/effects/internal/fillleftrighteffect.cpp b/effects/internal/fillleftrighteffect.cpp deleted file mode 100644 index 64d15fe03..000000000 --- a/effects/internal/fillleftrighteffect.cpp +++ /dev/null @@ -1,84 +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 "fillleftrighteffect.h" - -enum FillType { - FILL_TYPE_LEFT, - FILL_TYPE_RIGHT -}; - -FillLeftRightEffect::FillLeftRightEffect(Clip* c) : OldEffectNode(c) { - fill_type = new ComboInput(this, "type", tr("Type")); - fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT); - fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT); -} - -QString FillLeftRightEffect::name() -{ - return tr("Fill Left/Right"); -} - -QString FillLeftRightEffect::id() -{ - return "org.olivevideoeditor.Olive.fillleftright"; -} - -QString FillLeftRightEffect::description() -{ - return tr("Replaces either the left or right channel with the other"); -} - -EffectType FillLeftRightEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType FillLeftRightEffect::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr FillLeftRightEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void FillLeftRightEffect::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - - Q_UNUSED(type) - - double interval = (timecode_end-timecode_start)/nb_samples; - - if (channel_count == 2) { - for (int i=0;iGetValueAt(timecode_start+(interval*i)) == FILL_TYPE_LEFT) { - samples[0][i] = samples[1][i]; - } else { - samples[1][i] = samples[0][i]; - } - } - } -} diff --git a/effects/internal/fillleftrighteffect.h b/effects/internal/fillleftrighteffect.h deleted file mode 100644 index 58e0e3006..000000000 --- a/effects/internal/fillleftrighteffect.h +++ /dev/null @@ -1,48 +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 FILLLEFTRIGHTEFFECT_H -#define FILLLEFTRIGHTEFFECT_H - -#include "nodes/oldeffectnode.h" - -class FillLeftRightEffect : public OldEffectNode { - Q_OBJECT -public: - FillLeftRightEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; -private: - ComboInput* fill_type; -}; - -#endif // FILLLEFTRIGHTEFFECT_H diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp deleted file mode 100644 index 9508dd243..000000000 --- a/effects/internal/frei0reffect.cpp +++ /dev/null @@ -1,196 +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 "frei0reffect.h" - -#ifndef NOFREI0R - -#include -#include - -#include "timeline/clip.h" - -typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int height); -typedef int (*f0rInitFunc) (); -typedef void (*f0rDeinitFunc) (); -typedef void (*f0rUpdateFunc) (f0r_instance_t instance, - double time, const uint32_t* inframe, uint32_t* outframe); -typedef void (*f0rDestructFunc)(f0r_instance_t instance); -typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info); -typedef void (*f0rSetParamValue) (f0r_instance_t instance, - f0r_param_t param, int param_index); - -Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : - Effect(c, em), - open(false) -{ - SetFlags(ImageFlag); - - // Windows DLL loading routine - QString dll_fn = QDir(em->path).filePath(em->filename); - - handle.setFileName(dll_fn); - - - if (!handle.load()) { - 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; - } - - f0rInitFunc init = reinterpret_cast(handle.resolve("f0r_init")); - init(); - - construct_module(); - - f0r_plugin_info_t 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(handle.resolve("f0r_get_param_info")); - for (int i=0;i= 0 && param_info.type <= F0R_PARAM_STRING) { - EffectRow* row = new EffectRow(this, param_info.name); - switch (param_info.type) { - case F0R_PARAM_BOOL: - new BoolField(row, QString::number(i)); - break; - case F0R_PARAM_DOUBLE: - { - DoubleField* f = new DoubleField(row, QString::number(i)); - f->SetMinimum(0); - f->SetMaximum(100); - } - break; - case F0R_PARAM_COLOR: - new ColorField(row, QString::number(i)); - break; - case F0R_PARAM_POSITION: - { - DoubleField* fx = new DoubleField(row, QString("%1X").arg(QString::number(i))); - fx->SetMinimum(0); - fx->SetMaximum(100); - DoubleField* fy = new DoubleField(row, QString("%1Y").arg(QString::number(i))); - fy->SetMinimum(0); - fy->SetMaximum(100); - } - break; - case F0R_PARAM_STRING: - new StringField(row, QString::number(i), false); - break; - } - } - } -} - -Frei0rEffect::~Frei0rEffect() { - if (handle.isLoaded()) { - f0rDeinitFunc deinit = reinterpret_cast(handle.resolve("f0r_deinit")); - deinit(); - - handle.unload(); - } -} - -void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int) { - f0rUpdateFunc update_func = reinterpret_cast(handle.resolve("f0r_update")); - - for (int i=0;i(handle.resolve("f0r_set_param_value")); - switch (param_info.type) { - case F0R_PARAM_BOOL: - { - double b = param_row->Field(0)->GetValueAt(timecode).toBool(); - set_param(instance, &b, i); - } - break; - case F0R_PARAM_DOUBLE: - { - double d = param_row->Field(0)->GetValueAt(timecode).toDouble()*0.01; - set_param(instance, &d, i); - } - break; - case F0R_PARAM_COLOR: - { - QColor qcolor = param_row->Field(0)->GetValueAt(timecode).value(); - - f0r_param_color fcolor; - fcolor.r = float(qcolor.redF()); - fcolor.g = float(qcolor.greenF()); - fcolor.b = float(qcolor.blueF()); - - set_param(instance, &fcolor, i); - } - break; - case F0R_PARAM_POSITION: - { - f0r_param_position pos; - pos.x = param_row->Field(0)->GetValueAt(timecode).toDouble(); - pos.y = param_row->Field(1)->GetValueAt(timecode).toDouble(); - set_param(instance, &pos, i); - } - break; - case F0R_PARAM_STRING: - { - QByteArray bytes = param_row->Field(0)->GetValueAt(timecode).toString().toUtf8(); - char* byte_data = bytes.data(); - set_param(instance, &byte_data, i); - } - break; - } - } - - update_func(instance, timecode, reinterpret_cast(input), reinterpret_cast(output)); -} - -void Frei0rEffect::refresh() { - destruct_module(); - construct_module(); -} - -void Frei0rEffect::destruct_module() { - if (open) { - f0rDestructFunc destruct = reinterpret_cast(handle.resolve("f0r_destruct")); - destruct(instance); - - open = false; - } -} - -void Frei0rEffect::construct_module() { - f0rConstructFunc construct = reinterpret_cast(handle.resolve("f0r_construct")); - instance = construct(parent_clip->media_width(), parent_clip->media_height()); - - open = true; -} - -#endif diff --git a/effects/internal/frei0reffect.h b/effects/internal/frei0reffect.h deleted file mode 100644 index 693c9df5c..000000000 --- a/effects/internal/frei0reffect.h +++ /dev/null @@ -1,55 +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 FREI0REFFECT_H -#define FREI0REFFECT_H - -#ifndef NOFREI0R - -#include -#include - -#include "effects/effect.h" - -typedef void (*f0rGetParamInfo)(f0r_param_info_t * info, - int param_index ); - -class Frei0rEffect : public Effect { - Q_OBJECT -public: - Frei0rEffect(Clip* c, const EffectMeta* em); - ~Frei0rEffect(); - - virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size); - - virtual void refresh(); -private: - QLibrary handle; - f0r_instance_t instance; - int param_count; - f0rGetParamInfo get_param_info; - void destruct_module(); - void construct_module(); - bool open; -}; - -#endif - -#endif // FREI0REFFECT_H diff --git a/effects/internal/internalshaders.qrc b/effects/internal/internalshaders.qrc deleted file mode 100644 index a6239c9e1..000000000 --- a/effects/internal/internalshaders.qrc +++ /dev/null @@ -1,9 +0,0 @@ - - - common.vert - cornerpin.frag - cornerpin.vert - premultiply.frag - dropshadow.frag - - diff --git a/effects/internal/linearfadetransition.cpp b/effects/internal/linearfadetransition.cpp deleted file mode 100644 index f25eff752..000000000 --- a/effects/internal/linearfadetransition.cpp +++ /dev/null @@ -1,79 +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 "linearfadetransition.h" - -LinearFadeTransition::LinearFadeTransition(Clip* c) : Transition(c) {} - -QString LinearFadeTransition::name() -{ - return tr("Linear Fade"); -} - -QString LinearFadeTransition::id() -{ - return "org.olivevideoeditor.Olive.linearfade"; -} - -QString LinearFadeTransition::description() -{ - return tr("An linear audio fade that fades evenly at a constant rate."); -} - -EffectType LinearFadeTransition::type() -{ - return EFFECT_TYPE_TRANSITION; -} - -olive::TrackType LinearFadeTransition::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr LinearFadeTransition::Create(Clip *c) -{ - return std::make_shared(c); -} - -void LinearFadeTransition::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - double interval = (timecode_end-timecode_start)/nb_samples; - - for (int i=0;i. - -***/ - -#ifndef LINEARFADETRANSITION_H -#define LINEARFADETRANSITION_H - -#include "effects/transition.h" - -class LinearFadeTransition : public Transition { -public: - LinearFadeTransition(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; -}; - -#endif // LINEARFADETRANSITION_H diff --git a/effects/internal/logarithmicfadetransition.cpp b/effects/internal/logarithmicfadetransition.cpp deleted file mode 100644 index 6208a1e4e..000000000 --- a/effects/internal/logarithmicfadetransition.cpp +++ /dev/null @@ -1,83 +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 "logarithmicfadetransition.h" - -#include - -LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c) : - Transition(c) -{ -} - -QString LogarithmicFadeTransition::name() -{ - return tr("Logarithmic Fade"); -} - -QString LogarithmicFadeTransition::id() -{ - return "org.olivevideoeditor.Olive.logarithmicfade"; -} - -QString LogarithmicFadeTransition::description() -{ - return tr("An logarithmic audio fade that starts fast and ends slow."); -} - -EffectType LogarithmicFadeTransition::type() -{ - return EFFECT_TYPE_TRANSITION; -} - -olive::TrackType LogarithmicFadeTransition::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr LogarithmicFadeTransition::Create(Clip *c) -{ - return std::make_shared(c); -} - -void LogarithmicFadeTransition::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - double interval = (timecode_end-timecode_start)/nb_samples; - - for (int i=0;i. - -***/ - -#ifndef LOGARITHMICFADETRANSITION_H -#define LOGARITHMICFADETRANSITION_H - -#include "effects/transition.h" - -class LogarithmicFadeTransition : public Transition { -public: - LogarithmicFadeTransition(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip* c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; -}; - -#endif // LOGARITHMICFADETRANSITION_H diff --git a/effects/internal/ocio.frag b/effects/internal/ocio.frag deleted file mode 100644 index 479c63a67..000000000 --- a/effects/internal/ocio.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 110 - -uniform sampler2D tex1; -uniform sampler3D tex2; - -void main() -{ - vec4 col = texture2D(tex1, gl_TexCoord[0].st); - gl_FragColor = OCIODisplay(col, tex2); -} \ No newline at end of file diff --git a/effects/internal/paneffect.cpp b/effects/internal/paneffect.cpp deleted file mode 100644 index 2d713f884..000000000 --- a/effects/internal/paneffect.cpp +++ /dev/null @@ -1,96 +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 "paneffect.h" - -#include -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/collapsiblewidget.h" - -PanEffect::PanEffect(Clip* c) : OldEffectNode(c) { - pan_val = new DoubleInput(this, "pan", tr("Pan")); - pan_val->SetMinimum(-100); - pan_val->SetDefault(0); - pan_val->SetMaximum(100); -} - -QString PanEffect::name() -{ - return tr("Pan"); -} - -QString PanEffect::id() -{ - return "org.olivevideoeditor.Olive.pan"; -} - -QString PanEffect::description() -{ - return tr("Modifying the panning on a stereo audio clip."); -} - -EffectType PanEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType PanEffect::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr PanEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void PanEffect::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - - Q_UNUSED(type) - - // This has no effect on mono sources - if (channel_count < 2) { - return; - } - - double interval = (timecode_end - timecode_start)/nb_samples; - - for (int i=0;iGetDoubleAt(timecode_start+(interval*i)); - double pval = log_volume(qAbs(pan_field_val)*0.01); - - if (pan_field_val < 0) { - // affect right channel - samples[1][i] *= (1.0-pval); - } else { - // affect left channel - samples[0][i] *= (1.0-pval); - } - } -} diff --git a/effects/internal/paneffect.h b/effects/internal/paneffect.h deleted file mode 100644 index 130d8fe50..000000000 --- a/effects/internal/paneffect.h +++ /dev/null @@ -1,48 +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 PANEFFECT_H -#define PANEFFECT_H - -#include "nodes/oldeffectnode.h" - -class PanEffect : public OldEffectNode { - Q_OBJECT -public: - PanEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; - - DoubleInput* pan_val; -}; - -#endif // PANEFFECT_H diff --git a/effects/internal/premultiply.frag b/effects/internal/premultiply.frag deleted file mode 100644 index 64381fb27..000000000 --- a/effects/internal/premultiply.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 110 - -uniform sampler2D tex; -varying vec2 vTexCoord; - -void main(void) { - vec4 c = texture2D(tex, vTexCoord); - c.rgb *= c.a; - gl_FragColor = c; -} \ No newline at end of file diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp deleted file mode 100644 index 09e5c7efd..000000000 --- a/effects/internal/richtexteffect.cpp +++ /dev/null @@ -1,225 +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 "richtexteffect.h" - -#include -#include - -#include "timeline/clip.h" -#include "ui/blur.h" - -enum AutoscrollDirection { - SCROLL_OFF, - SCROLL_UP, - SCROLL_DOWN, - SCROLL_LEFT, - SCROLL_RIGHT, -}; - -RichTextEffect::RichTextEffect(Clip *c) : - OldEffectNode(c) -{ - SetFlags(OldEffectNode::SuperimposeFlag); - - text_val = new StringInput(this, "text", tr("Text")); - - padding_field = new DoubleInput(this, "padding", tr("Padding")); - - position = new Vec2Input(this, "pos", tr("Position")); - - vertical_align = new ComboInput(this, "valign", tr("Vertical Align:")); - vertical_align->AddItem(tr("Top"), Qt::AlignTop); - vertical_align->AddItem(tr("Center"), Qt::AlignCenter); - vertical_align->AddItem(tr("Bottom"), Qt::AlignBottom); - vertical_align->SetValueAt(0, Qt::AlignCenter); - - autoscroll = new ComboInput(this, "autoscroll", tr("Auto-Scroll")); - autoscroll->AddItem(tr("Off"), SCROLL_OFF); - autoscroll->AddItem(tr("Up"), SCROLL_UP); - autoscroll->AddItem(tr("Down"), SCROLL_DOWN); - autoscroll->AddItem(tr("Left"), SCROLL_LEFT); - autoscroll->AddItem(tr("Right"), SCROLL_RIGHT); - - shadow_bool = new BoolInput(this, "shadow", tr("Shadow")); - - shadow_color = new ColorInput(this, "shadowcolor", tr("Shadow Color")); - - shadow_angle = new DoubleInput(this, "shadowangle", tr("Shadow Angle")); - - shadow_distance = new DoubleInput(this, "shadowdistance", tr("Shadow Distance")); - shadow_distance->SetMinimum(0); - - shadow_softness = new DoubleInput(this, "shadowsoftness", tr("Shadow Softness")); - shadow_softness->SetMinimum(0); - - shadow_opacity = new DoubleInput(this, "shadowopacity", tr("Shadow Opacity")); - shadow_opacity->SetMinimum(0); - shadow_opacity->SetMaximum(100); - - // Create default text - text_val->SetValueAt(0, "" - "" - "
Sample Text
" - "" - ""); -} - -QString RichTextEffect::name() -{ - return tr("Rich Text"); -} - -QString RichTextEffect::id() -{ - return "org.olivevideoeditor.Olive.richtext"; -} - -QString RichTextEffect::category() -{ - return tr("Render"); -} - -QString RichTextEffect::description() -{ - return tr("Render formatted rich text over a clip."); -} - -EffectType RichTextEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType RichTextEffect::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr RichTextEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void RichTextEffect::redraw(double timecode) -{ - QPainter p(&img); - p.setRenderHint(QPainter::Antialiasing); - int width = img.width(); - int height = img.height(); - - int padding = qRound(padding_field->GetDoubleAt(timecode)); - - width -= 2 * padding; - height -= 2 * padding; - - QTextDocument td; - td.setHtml(text_val->GetStringAt(timecode)); - td.setTextWidth(width); - - QPoint translation = position->GetVector2DAt(timecode).toPoint(); - translation += {padding, padding}; - - int doc_height = qRound(td.size().height()); - - AutoscrollDirection auto_scroll_dir = static_cast(autoscroll->GetValueAt(timecode).toInt()); - - double scroll_progress = 0; - - if (auto_scroll_dir != SCROLL_OFF) { - double clip_length_secs = double(parent_clip->length()) / parent_clip->media_frame_rate(); - scroll_progress = (timecode - double(parent_clip->clip_in()) / parent_clip->media_frame_rate()) / clip_length_secs; - } - - if (auto_scroll_dir == SCROLL_OFF || auto_scroll_dir == SCROLL_LEFT || auto_scroll_dir == SCROLL_RIGHT) { - - // If we're not auto-scrolling the vertical direction, respect the vertical alignment - if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) { - translation.setY(translation.y() + height / 2 - doc_height / 2); - } else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) { - translation.setY(translation.y() + height - doc_height); - } - - // Check if we are autoscrolling - if (auto_scroll_dir != SCROLL_OFF) { - - if (auto_scroll_dir == SCROLL_LEFT) { - scroll_progress = 1.0 - scroll_progress; - } - - int doc_width = qRound(td.size().width()); - translation.setX(translation.x() + qRound(-doc_width + (img.width() + doc_width) * scroll_progress)); - } - - } else if (auto_scroll_dir == SCROLL_UP || auto_scroll_dir == SCROLL_DOWN) { - - // Auto-scroll bottom to top or top to bottom - - if (auto_scroll_dir == SCROLL_UP) { - scroll_progress = 1.0 - scroll_progress; - } - - translation.setY(translation.y() + qRound(-doc_height + (img.height() + doc_height)*scroll_progress)); - - } - - QRect clip_rect = img.rect(); - clip_rect.translate(-translation); - p.translate(translation); - - img.fill(Qt::transparent); - - // draw software shadow - if (shadow_bool->GetBoolAt(timecode)) { - - // calculate offset using distance and angle - double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0; - double distance = qFloor(shadow_distance->GetDoubleAt(timecode)); - int shadow_x_offset = qRound(qCos(angle) * distance); - int shadow_y_offset = qRound(qSin(angle) * distance); - - p.translate(shadow_x_offset, shadow_y_offset); - clip_rect.translate(-shadow_x_offset, -shadow_y_offset); - - td.drawContents(&p, clip_rect); - - int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode)); - if (blurSoftness > 0) { - olive::ui::blur(img, img.rect(), blurSoftness, true); - } - - p.setCompositionMode(QPainter::CompositionMode_SourceIn); - - p.fillRect(clip_rect, shadow_color->GetColorAt(timecode)); - - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - - p.translate(-shadow_x_offset, -shadow_y_offset); - clip_rect.translate(shadow_x_offset, shadow_y_offset); - } - - td.drawContents(&p, clip_rect); - - p.end(); -} - -bool RichTextEffect::AlwaysUpdate() -{ - return autoscroll->GetValueAt(Now()).toInt() != SCROLL_OFF; -} diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h deleted file mode 100644 index 28a477c01..000000000 --- a/effects/internal/richtexteffect.h +++ /dev/null @@ -1,58 +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 RICHTEXTEFFECT_H -#define RICHTEXTEFFECT_H - -#include "nodes/oldeffectnode.h" - -class RichTextEffect : public OldEffectNode { - Q_OBJECT -public: - RichTextEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void redraw(double timecode) override; - -protected: - virtual bool AlwaysUpdate() override; -private: - StringInput* text_val; - DoubleInput* padding_field; - Vec2Input* position; - ComboInput* vertical_align; - ComboInput* autoscroll; - - BoolInput* shadow_bool; - DoubleInput* shadow_angle; - DoubleInput* shadow_distance; - ColorInput* shadow_color; - DoubleInput* shadow_softness; - DoubleInput* shadow_opacity; -}; - -#endif // RICHTEXTEFFECT_H diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp deleted file mode 100644 index f8816c1ec..000000000 --- a/effects/internal/shakeeffect.cpp +++ /dev/null @@ -1,116 +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 "shakeeffect.h" - -#include -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/collapsiblewidget.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "panels/timeline.h" -#include "global/debug.h" - -ShakeEffect::ShakeEffect(Clip* c) : OldEffectNode(c) { - SetFlags(OldEffectNode::CoordsFlag); - - intensity_val = new DoubleInput(this, "intensity", tr("Intensity")); - intensity_val->SetMinimum(0); - intensity_val->SetDefault(25); - - rotation_val = new DoubleInput(this, "rotation", tr("Rotation")); - rotation_val->SetMinimum(0); - rotation_val->SetDefault(10); - - frequency_val = new DoubleInput(this, "frequency", tr("Frequency")); - frequency_val->SetMinimum(0); - frequency_val->SetDefault(5); - - const auto limit = std::numeric_limits::max(); - for (int i=0;i(this->randomNumber()) / limit; - } -} - -void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int) { - int lim = RANDOM_VAL_SIZE/6; - - double multiplier = intensity_val->GetDoubleAt(timecode)/lim; - double rotmult = rotation_val->GetDoubleAt(timecode)/lim/10; - double x = timecode * frequency_val->GetDoubleAt(timecode); - - double xoff = 0; - double yoff = 0; - double rotoff = 0; - - for (int i=0;i(c); -} diff --git a/effects/internal/shakeeffect.h b/effects/internal/shakeeffect.h deleted file mode 100644 index 13b818188..000000000 --- a/effects/internal/shakeeffect.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 SHAKEEFFECT_H -#define SHAKEEFFECT_H - -#include "nodes/oldeffectnode.h" - -#define RANDOM_VAL_SIZE 30 - -class ShakeEffect : public OldEffectNode { - Q_OBJECT -public: - ShakeEffect(Clip* c); - virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override; - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - DoubleInput* intensity_val; - DoubleInput* rotation_val; - DoubleInput* frequency_val; -private: - double random_vals[RANDOM_VAL_SIZE]; -}; - -#endif // SHAKEEFFECT_H diff --git a/effects/internal/solideffect.cpp b/effects/internal/solideffect.cpp deleted file mode 100644 index c5104a4e9..000000000 --- a/effects/internal/solideffect.cpp +++ /dev/null @@ -1,241 +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 "solideffect.h" - -#include -#include -#include -#include -#include -#include - -#include "timeline/clip.h" -#include "timeline/sequence.h" - -const int SMPTE_BARS = 7; -const int SMPTE_STRIP_COUNT = 3; -const int SMPTE_LOWER_BARS = 4; - -SolidEffect::SolidEffect(Clip* c) : - OldEffectNode(c) -{ - SetFlags(OldEffectNode::SuperimposeFlag); - - // Field for solid type - solid_type = new ComboInput(this, "type", tr("Type")); - solid_type->AddItem(tr("Solid Color"), SOLID_TYPE_COLOR); - solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS); - solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); - - opacity_field = new DoubleInput(this, "opacity", tr("Opacity")); - opacity_field->SetMinimum(0); - opacity_field->SetDefault(100); - opacity_field->SetMaximum(100); - - solid_color_field = new ColorInput(this, "color", tr("Color")); - solid_color_field->SetValueAt(0, QColor(Qt::red)); - - checkerboard_size_field = new DoubleInput(this, "checker_size", tr("Checkerboard Size")); - checkerboard_size_field->SetMinimum(1); - checkerboard_size_field->SetDefault(10); - - connect(solid_type, SIGNAL(DataChanged(const QVariant&)), this, SLOT(ui_update(const QVariant&))); - - // Set default UI - solid_type->SetValueAt(0, SOLID_TYPE_COLOR); - - // TODO necessary? Isn't this called from the connect() above? - ui_update(SOLID_TYPE_COLOR); - - /*vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/solideffect.frag";*/ -} - -QString SolidEffect::name() -{ - return tr("Solid"); -} - -QString SolidEffect::id() -{ - return "org.olivevideoeditor.Olive.solid"; -} - -QString SolidEffect::category() -{ - return tr("Render"); -} - -QString SolidEffect::description() -{ - return tr("Render a solid color over this clip."); -} - -EffectType SolidEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType SolidEffect::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr SolidEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void SolidEffect::redraw(double timecode) { - int w = img.width(); - int h = img.height(); - int alpha = qRound(opacity_field->GetDoubleAt(timecode)*2.55); - switch (solid_type->GetValueAt(timecode).toInt()) { - case SOLID_TYPE_COLOR: - { - QColor solidColor = solid_color_field->GetColorAt(timecode); - solidColor.setAlpha(alpha); - img.fill(solidColor); - } - break; - case SOLID_TYPE_BARS: - { - // draw smpte bars - QPainter p(&img); - img.fill(Qt::transparent); - int bar_width = qCeil(double(w) / 7.0); - int first_bar_height = qCeil(double(h) / 3.0 * 2.0); - int second_bar_height = qCeil(double(h) / 12.5); - int third_bar_y = first_bar_height + second_bar_height; - int third_bar_height = h - third_bar_y; - int third_bar_width = 0; - int bar_x, strip_width; - QColor first_color, second_color, third_color; - for (int i=0;iGetDoubleAt(timecode)); - int checker_x, checker_y; - int checkerboard_size_w = qCeil(double(w)/checker_width); - int checkerboard_size_h = qCeil(double(h)/checker_width); - - QColor checker_odd(QColor(0, 0, 0, alpha)); - QColor checker_even(solid_color_field->GetColorAt(timecode)); - checker_even.setAlpha(alpha); - QVector checker_color{checker_odd, checker_even}; - - for(int i = 0; i < checkerboard_size_w; i++){ - checker_x = checker_width*i; - for(int j = 0; j < checkerboard_size_h; j++){ - checker_y = checker_width*j; - p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]); - } - } - } - break; - } -} - -void SolidEffect::SetType(SolidEffect::SolidType type) -{ - solid_type->SetValueAt(0, type); -} - -void SolidEffect::ui_update(const QVariant& d) { - int i = d.toInt(); - - solid_color_field->SetEnabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD); - checkerboard_size_field->SetEnabled(i == SOLID_TYPE_CHECKERBOARD); -} diff --git a/effects/internal/solideffect.h b/effects/internal/solideffect.h deleted file mode 100644 index 0d3e60410..000000000 --- a/effects/internal/solideffect.h +++ /dev/null @@ -1,59 +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 SOLIDEFFECT_H -#define SOLIDEFFECT_H - -#include "nodes/oldeffectnode.h" - -#include - -class SolidEffect : public OldEffectNode { - Q_OBJECT -public: - enum SolidType { - SOLID_TYPE_COLOR, - SOLID_TYPE_BARS, - SOLID_TYPE_CHECKERBOARD - }; - - SolidEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void redraw(double timecode) override; - - void SetType(SolidType type); -private slots: - void ui_update(const QVariant &d); -private: - ComboInput* solid_type; - ColorInput* solid_color_field; - DoubleInput* opacity_field; - DoubleInput* checkerboard_size_field; -}; - -#endif // SOLIDEFFECT_H diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp deleted file mode 100644 index d82360bc0..000000000 --- a/effects/internal/texteffect.cpp +++ /dev/null @@ -1,317 +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 "texteffect.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/collapsiblewidget.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "ui/comboboxex.h" -#include "ui/colorbutton.h" -#include "ui/blur.h" -#include "global/config.h" - -TextEffect::TextEffect(Clip* c) : - OldEffectNode(c) -{ - SetFlags(OldEffectNode::SuperimposeFlag); - - text_val = new StringInput(this, "text", tr("Text"), false); - - set_font_combobox = new FontInput(this, "font", tr("Font")); - - size_val = new DoubleInput(this, "size", tr("Size")); - size_val->SetMinimum(0); - - set_color_button = new ColorInput(this, "color", tr("Color")); - - halign_field = new ComboInput(this, "halign", tr("Horizontal Alignment")); - halign_field->AddItem(tr("Left"), Qt::AlignLeft); - halign_field->AddItem(tr("Center"), Qt::AlignHCenter); - halign_field->AddItem(tr("Right"), Qt::AlignRight); - halign_field->AddItem(tr("Justify"), Qt::AlignJustify); - - valign_field = new ComboInput(this, "valign", tr("Vertical Alignment")); - valign_field->AddItem(tr("Top"), Qt::AlignTop); - valign_field->AddItem(tr("Center"), Qt::AlignVCenter); - valign_field->AddItem(tr("Bottom"), Qt::AlignBottom); - - word_wrap_field = new BoolInput(this, "wordwrap", tr("Word Wrap")); - - padding_field = new DoubleInput(this, "padding", tr("Padding")); - - position = new Vec2Input(this, "pos", tr("Position")); - - outline_bool = new BoolInput(this, "outline", tr("Outline")); - - outline_color = new ColorInput(this, "outlinecolor", tr("Outline Color")); - - outline_width = new DoubleInput(this, "outlinewidth", tr("Outline Width")); - outline_width->SetMinimum(0); - - shadow_bool = new BoolInput(this, "shadow", tr("Shadow")); - - shadow_color = new ColorInput(this, "shadowcolor", tr("Shadow Color")); - - shadow_angle = new DoubleInput(this, "shadowangle", tr("Shadow Angle")); - - shadow_distance = new DoubleInput(this, "shadowdistance", tr("Shadow Distance")); - shadow_distance->SetMinimum(0); - - shadow_softness = new DoubleInput(this, "shadowsoftness", tr("Shadow Softness")); - shadow_softness->SetMinimum(0); - - shadow_opacity = new DoubleInput(this, "shadowopacity", tr("Shadow Opacity")); - shadow_opacity->SetMinimum(0); - shadow_opacity->SetMaximum(100); - - size_val->SetDefault(48); - text_val->SetValueAt(0, tr("Sample Text")); - set_color_button->SetValueAt(0, QColor(Qt::white)); - halign_field->SetValueAt(0, Qt::AlignHCenter); - valign_field->SetValueAt(0, Qt::AlignVCenter); - word_wrap_field->SetValueAt(0, true); - outline_color->SetValueAt(0, QColor(Qt::black)); - shadow_color->SetValueAt(0, QColor(Qt::black)); - shadow_angle->SetDefault(45); - shadow_opacity->SetDefault(100); - shadow_softness->SetDefault(5); - shadow_distance->SetDefault(5); - shadow_opacity->SetDefault(80); - outline_width->SetDefault(20); - - outline_enable(false); - shadow_enable(false); - - connect(shadow_bool, SIGNAL(Toggled(bool)), this, SLOT(shadow_enable(bool))); - connect(outline_bool, SIGNAL(Toggled(bool)), this, SLOT(outline_enable(bool))); - - shader_vert_path_ = "common.vert"; - shader_frag_path_ = "dropshadow.frag"; -} - -QString TextEffect::name() -{ - return tr("Text"); -} - -QString TextEffect::id() -{ - return "org.olivevideoeditor.Olive.text"; -} - -QString TextEffect::category() -{ - return tr("Render"); -} - -QString TextEffect::description() -{ - return tr("Generate simple text over this clip"); -} - -EffectType TextEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType TextEffect::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr TextEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void TextEffect::redraw(double timecode) { - if (size_val->GetDoubleAt(timecode) <= 0) { - return; - } - - QColor bkg = set_color_button->GetColorAt(timecode); - bkg.setAlpha(0); - img.fill(bkg); - - QPainter p(&img); - p.setRenderHint(QPainter::Antialiasing); - int padding = qRound(padding_field->GetDoubleAt(timecode)); - int width = img.width() - padding * 2; - int height = img.height() - padding * 2; - - // set font - font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); - font.setFamily(set_font_combobox->GetFontAt(timecode)); - font.setPointSize(qRound(size_val->GetDoubleAt(timecode))); - p.setFont(font); - QFontMetrics fm(font); - - QStringList lines = text_val->GetStringAt(timecode).split('\n'); - - // word wrap function - if (word_wrap_field->GetBoolAt(timecode)) { - for (int i=0;i width) { - int last_space_index = 0; - for (int j=0;j width) { - break; - } else { - last_space_index = j; - } - } - } - if (last_space_index > 0) { - lines.insert(i+1, s.mid(last_space_index + 1)); - lines[i] = s.left(last_space_index); - } - } - } - } - - QPainterPath path; - - int text_height = fm.height()*lines.size(); - - for (int i=0;iGetValueAt(timecode).toInt()) { - case Qt::AlignLeft: text_x = 0; break; - case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break; - case Qt::AlignJustify: - // add spaces until the string is too big - text_x = 0; - while (fm.width(lines.at(i)) < width) { - bool space = false; - QString spaced(lines.at(i)); - for (int i=0;i width || !space) { - break; - } else { - lines[i] = spaced; - } - } - break; - case Qt::AlignHCenter: - default: - text_x = (width/2) - (fm.width(lines.at(i))/2); - break; - } - - switch (valign_field->GetValueAt(timecode).toInt()) { - case Qt::AlignTop: - text_y = (fm.height()*i)+fm.ascent(); - break; - case Qt::AlignBottom: - text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); - break; - case Qt::AlignVCenter: - default: - text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); - break; - } - - path.addText(text_x, text_y, font, lines.at(i)); - } - - path.translate(position->GetVector2DAt(timecode).toPointF() + QPointF(padding, padding)); - - // draw software shadow - if (shadow_bool->GetBoolAt(timecode)) { - p.setPen(Qt::NoPen); - - // calculate offset using distance and angle - double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0; - double distance = qFloor(shadow_distance->GetDoubleAt(timecode)); - int shadow_x_offset = qRound(qCos(angle) * distance); - int shadow_y_offset = qRound(qSin(angle) * distance); - - QPainterPath shadow_path(path); - shadow_path.translate(shadow_x_offset, shadow_y_offset); - - QColor col = shadow_color->GetColorAt(timecode); - col.setAlpha(0); - img.fill(col); - - col.setAlphaF(shadow_opacity->GetDoubleAt(timecode)*0.01); - p.setBrush(col); - p.drawPath(shadow_path); - - int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode)); - if (blurSoftness > 0) olive::ui::blur(img, img.rect(), blurSoftness, true); - } - - // draw outline - int outline_width_val = qCeil(outline_width->GetDoubleAt(timecode)); - if (outline_bool->GetBoolAt(timecode) && outline_width_val > 0) { - QPen outline(outline_color->GetColorAt(timecode)); - outline.setWidth(outline_width_val); - p.setPen(outline); - p.setBrush(Qt::NoBrush); - p.drawPath(path); - } - - // draw "master" text - p.setPen(Qt::NoPen); - p.setBrush(set_color_button->GetColorAt(timecode)); - p.drawPath(path); - - p.end(); -} - -void TextEffect::shadow_enable(bool e) { - shadow_color->SetEnabled(e); - shadow_angle->SetEnabled(e); - shadow_distance->SetEnabled(e); - shadow_softness->SetEnabled(e); - shadow_opacity->SetEnabled(e); -} - -void TextEffect::outline_enable(bool e) { - outline_color->SetEnabled(e); - outline_width->SetEnabled(e); -} diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h deleted file mode 100644 index c054caaf5..000000000 --- a/effects/internal/texteffect.h +++ /dev/null @@ -1,72 +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 TEXTEFFECT_H -#define TEXTEFFECT_H - -#include "nodes/oldeffectnode.h" - -#include -#include - -class TextEffect : public OldEffectNode { - Q_OBJECT -public: - TextEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void redraw(double timecode) override; -private slots: - void outline_enable(bool); - void shadow_enable(bool); -private: - QFont font; - - StringInput* text_val; - DoubleInput* size_val; - ColorInput* set_color_button; - FontInput* set_font_combobox; - ComboInput* halign_field; - ComboInput* valign_field; - BoolInput* word_wrap_field; - DoubleInput* padding_field; - Vec2Input* position; - - BoolInput* outline_bool; - DoubleInput* outline_width; - ColorInput* outline_color; - - BoolInput* shadow_bool; - DoubleInput* shadow_angle; - DoubleInput* shadow_distance; - ColorInput* shadow_color; - DoubleInput* shadow_softness; - DoubleInput* shadow_opacity; - -}; - -#endif // TEXTEFFECT_H diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp deleted file mode 100644 index 6e2c85517..000000000 --- a/effects/internal/timecodeeffect.cpp +++ /dev/null @@ -1,167 +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 "timecodeeffect.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/collapsiblewidget.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "global/timing.h" -#include "ui/comboboxex.h" -#include "ui/colorbutton.h" -#include "global/config.h" - -TimecodeEffect::TimecodeEffect(Clip* c) : - OldEffectNode(c) -{ - SetFlags(OldEffectNode::SuperimposeFlag); - - tc_select = new ComboInput(this, "tc_selector", tr("Timecode")); - tc_select->AddItem(tr("Sequence"), true); - tc_select->AddItem(tr("Media"), false); - tc_select->SetValueAt(0, true); - - scale_val = new DoubleInput(this, "scale", tr("Scale")); - scale_val->SetMinimum(1); - scale_val->SetDefault(100); - scale_val->SetMaximum(1000); - - color_val = new ColorInput(this, "color", tr("Color")); - color_val->SetValueAt(0, QColor(Qt::white)); - - color_bg_val = new ColorInput(this, "bgcolor", tr("Background Color")); - color_bg_val->SetValueAt(0, QColor(Qt::black)); - - bg_alpha = new DoubleInput(this, "bgalpha", tr("Background Opacity")); - bg_alpha->SetMinimum(0); - bg_alpha->SetDefault(50); - bg_alpha->SetMaximum(100); - - offset_val = new Vec2Input(this, "offset", tr("Offset")); - offset_val->SetDefault(0); - - prepend_text = new StringInput(this, "prepend", tr("Prepend"), false); -} - -QString TimecodeEffect::name() -{ - return tr("Timecode"); -} - -QString TimecodeEffect::id() -{ - return "org.olivevideoeditor.Olive.timecode"; -} - -QString TimecodeEffect::category() -{ - return tr("Render"); -} - -QString TimecodeEffect::description() -{ - return tr("Render the media or sequence timecode on this clip."); -} - -EffectType TimecodeEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType TimecodeEffect::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr TimecodeEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - - -void TimecodeEffect::redraw(double timecode) { - Sequence* sequence = parent_clip->track()->sequence(); - - if (tc_select->GetValueAt(timecode).toBool()) { - display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(sequence->playhead, - olive::config.timecode_view, - sequence->frame_rate()); - } else { - double media_rate = parent_clip->media_frame_rate(); - display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(qRound(timecode * media_rate), - olive::config.timecode_view, - media_rate); - } - img.fill(Qt::transparent); - - QPainter p(&img); - p.setRenderHint(QPainter::Antialiasing); - int width = img.width(); - int height = img.height(); - - // set font - font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); - font.setFamily("Helvetica"); - font.setPixelSize(qCeil(scale_val->GetDoubleAt(timecode)*.01*(height/10))); - p.setFont(font); - QFontMetrics fm(font); - - QPainterPath path; - - int text_x, text_y, rect_y; - int text_height = fm.height(); - int text_width = fm.width(display_timecode); - QColor background_color = color_bg_val->GetColorAt(timecode); - int alpha_val = qCeil(bg_alpha->GetDoubleAt(timecode)*2.55); - background_color.setAlpha(alpha_val); - - QVector2D offset = offset_val->GetVector2DAt(timecode); - - text_x = offset.x() + (width/2) - (text_width/2); - text_y = offset.y() + height - height/10; - rect_y = text_y + fm.descent() - text_height; - - path.addText(text_x, text_y, font, display_timecode); - - p.setPen(Qt::NoPen); - p.setBrush(background_color); - p.drawRect(QRect(text_x-fm.descent(), rect_y, text_width+fm.descent()*2, text_height)); - p.setBrush(color_val->GetColorAt(timecode)); - p.drawPath(path); -} - -bool TimecodeEffect::AlwaysUpdate() -{ - return true; -} diff --git a/effects/internal/timecodeeffect.h b/effects/internal/timecodeeffect.h deleted file mode 100644 index 74ee7fd18..000000000 --- a/effects/internal/timecodeeffect.h +++ /dev/null @@ -1,59 +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 TIMECODEEFFECT_H -#define TIMECODEEFFECT_H - -#include "nodes/oldeffectnode.h" - -#include -#include - -class TimecodeEffect : public OldEffectNode { - Q_OBJECT -public: - TimecodeEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void redraw(double timecode) override; - DoubleInput* scale_val; - ColorInput* color_val; - ColorInput* color_bg_val; - DoubleInput* bg_alpha; - Vec2Input* offset_val; - StringInput* prepend_text; - ComboInput* tc_select; - -protected: - virtual bool AlwaysUpdate() override; - -private: - QFont font; - QString display_timecode; -}; - -#endif // TIMECODEEFFECT_H diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp deleted file mode 100644 index 4ed9122e6..000000000 --- a/effects/internal/toneeffect.cpp +++ /dev/null @@ -1,114 +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 "toneeffect.h" - -#include - -#define TONE_TYPE_SINE 0 - -#include "timeline/clip.h" -#include "timeline/sequence.h" - -ToneEffect::ToneEffect(Clip* c) : OldEffectNode(c), sinX(INT_MIN) { - type_val = new ComboInput(this, "type", tr("Type")); - type_val->AddItem(tr("Sine"), TONE_TYPE_SINE); - - freq_val = new DoubleInput(this, "frequency", tr("Frequency")); - freq_val->SetMinimum(20); - freq_val->SetMaximum(20000); - freq_val->SetDefault(1000); - - amount_val = new DoubleInput(this, "amount", tr("Amount")); - amount_val->SetMinimum(0); - amount_val->SetMaximum(100); - amount_val->SetDefault(25); - - mix_val = new BoolInput(this, "mix", tr("Mix")); - mix_val->SetValueAt(0, true); -} - -QString ToneEffect::name() -{ - return tr("Tone"); -} - -QString ToneEffect::id() -{ - return "org.olivevideoeditor.Olive.tone"; -} - -QString ToneEffect::description() -{ - return tr("Generate a sine wave tone to mix into this clip's audio."); -} - -EffectType ToneEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType ToneEffect::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr ToneEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void ToneEffect::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - - Q_UNUSED(type) - - double interval = (timecode_end - timecode_start)/nb_samples; - - for (int i=0;iGetDoubleAt(timecode)) - /parent_clip->track()->sequence()->audio_frequency()) - *log_volume(amount_val->GetDoubleAt(timecode)*0.01); - - for (int j=0;jGetBoolAt(timecode)) { - - // mix with source audio - samples[j][i] += tone_sample; - - } else { - - // replace source audio - samples[j][i] = tone_sample; - - } - - } - - sinX++; - } -} diff --git a/effects/internal/toneeffect.h b/effects/internal/toneeffect.h deleted file mode 100644 index 8309a8f84..000000000 --- a/effects/internal/toneeffect.h +++ /dev/null @@ -1,54 +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 TONEEFFECT_H -#define TONEEFFECT_H - -#include "nodes/oldeffectnode.h" - -class ToneEffect : public OldEffectNode { - Q_OBJECT -public: - ToneEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; - -private: - ComboInput* type_val; - DoubleInput* freq_val; - DoubleInput* amount_val; - BoolInput* mix_val; - - int sinX; -}; - -#endif // TONEEFFECT_H diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp deleted file mode 100644 index c2a05c705..000000000 --- a/effects/internal/transformeffect.cpp +++ /dev/null @@ -1,256 +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 "transformeffect.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ui/collapsiblewidget.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "project/footage.h" -#include "global/math.h" -#include "ui/labelslider.h" -#include "ui/comboboxex.h" -#include "panels/project.h" -#include "global/debug.h" - -#include "panels/panels.h" -#include "panels/viewer.h" -#include "ui/viewerwidget.h" - -TransformEffect::TransformEffect(Clip* c) : OldEffectNode(c) { - SetFlags(OldEffectNode::CoordsFlag); - - position = new Vec2Input(this, "pos", tr("Position")); - - scale = new Vec2Input(this, "scale", tr("Scale")); - scale->SetMinimum(0); - scale->SetDefault(100); - - uniform_scale_field = new BoolInput(this, "uniformscale", tr("Uniform Scale")); - connect(uniform_scale_field, SIGNAL(Toggled(bool)), scale, SLOT(SetSingleValueMode(bool))); - uniform_scale_field->SetValueAt(0, true); - - rotation = new DoubleInput(this, "rotation", tr("Rotation")); - - anchor_point = new Vec2Input(this, "anchor", tr("Anchor Point")); - anchor_point->SetDefault(0); - - // opacity - opacity = new DoubleInput(this, "opacity", tr("Opacity")); - opacity->SetMinimum(0); - opacity->SetMaximum(100); - opacity->SetDefault(100); - - // TEMP - Create matrix output - NodeIO* matrix_output = new NodeIO(this, "matrix", "Matrix", false, false); - matrix_output->SetOutputDataType(olive::nodes::kMatrix); - - // set up gizmos - top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_left_gizmo->set_cursor(Qt::SizeFDiagCursor); - top_left_gizmo->x_field1 = static_cast(scale->Field(0)); - - top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_center_gizmo->set_cursor(Qt::SizeVerCursor); - top_center_gizmo->y_field1 = static_cast(scale->Field(0)); - - top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); - top_right_gizmo->x_field1 = static_cast(scale->Field(0)); - - bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); - bottom_left_gizmo->x_field1 = static_cast(scale->Field(0)); - - bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); - bottom_center_gizmo->y_field1 = static_cast(scale->Field(0)); - - bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); - bottom_right_gizmo->x_field1 = static_cast(scale->Field(0)); - - left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - left_center_gizmo->set_cursor(Qt::SizeHorCursor); - left_center_gizmo->x_field1 = static_cast(scale->Field(0)); - - right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - right_center_gizmo->set_cursor(Qt::SizeHorCursor); - right_center_gizmo->x_field1 = static_cast(scale->Field(0)); - - anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET); - anchor_gizmo->set_cursor(Qt::SizeAllCursor); - anchor_gizmo->x_field1 = static_cast(anchor_point->Field(0)); - anchor_gizmo->y_field1 = static_cast(anchor_point->Field(1)); - anchor_gizmo->x_field2 = static_cast(position->Field(0)); - anchor_gizmo->y_field2 = static_cast(position->Field(1)); - - rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); - rotate_gizmo->color = Qt::green; - rotate_gizmo->set_cursor(Qt::SizeAllCursor); - rotate_gizmo->x_field1 = static_cast(rotation->Field(0)); - - rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); - rect_gizmo->x_field1 = static_cast(position->Field(0)); - rect_gizmo->y_field1 = static_cast(position->Field(1)); - - connect(uniform_scale_field, SIGNAL(Toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); - - refresh(); -} - -QString TransformEffect::name() -{ - return tr("Transform"); -} - -QString TransformEffect::id() -{ - return "org.olivevideoeditor.Olive.transform"; -} - -QString TransformEffect::category() -{ - return tr("Distort"); -} - -QString TransformEffect::description() -{ - return tr("Transform the position, scale, and rotation of this clip."); -} - -EffectType TransformEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType TransformEffect::subtype() -{ - return olive::kTypeVideo; -} - -OldEffectNodePtr TransformEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void TransformEffect::refresh() { - if (parent_clip != nullptr && parent_clip->track()->sequence() != nullptr) { - - position->SetDefault({parent_clip->track()->sequence()->width()*0.5, - parent_clip->track()->sequence()->height()*0.5}); - - double x_percent_multipler = 200.0 / parent_clip->track()->sequence()->width(); - double y_percent_multipler = 200.0 / parent_clip->track()->sequence()->height(); - - top_left_gizmo->x_field_multi1 = -x_percent_multipler; - top_left_gizmo->y_field_multi1 = -y_percent_multipler; - top_center_gizmo->y_field_multi1 = -y_percent_multipler; - top_right_gizmo->x_field_multi1 = x_percent_multipler; - top_right_gizmo->y_field_multi1 = -y_percent_multipler; - bottom_left_gizmo->x_field_multi1 = -x_percent_multipler; - bottom_left_gizmo->y_field_multi1 = y_percent_multipler; - bottom_center_gizmo->y_field_multi1 = y_percent_multipler; - bottom_right_gizmo->x_field_multi1 = x_percent_multipler; - bottom_right_gizmo->y_field_multi1 = y_percent_multipler; - left_center_gizmo->x_field_multi1 = -x_percent_multipler; - right_center_gizmo->x_field_multi1 = x_percent_multipler; - rotate_gizmo->x_field_multi1 = x_percent_multipler; - - } -} - -void TransformEffect::toggle_uniform_scale(bool enabled) { - scale->SetSingleValueMode(enabled); - - DoubleField* scale_x = static_cast(scale->Field(0)); - DoubleField* scale_y = static_cast(scale->Field(1)); - - top_center_gizmo->y_field1 = enabled ? scale_x : scale_y; - bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y; - top_left_gizmo->y_field1 = enabled ? nullptr : scale_y; - top_right_gizmo->y_field1 = enabled ? nullptr : scale_y; - bottom_left_gizmo->y_field1 = enabled ? nullptr : scale_y; - bottom_right_gizmo->y_field1 = enabled ? nullptr : scale_y; -} - -void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { - // position - coords.matrix.translate(position->GetVector2DAt(timecode) - - QVector2D(parent_clip->track()->sequence()->width()*0.5f, - parent_clip->track()->sequence()->height()*0.5f)); - - // anchor point - QVector2D anchor_val = anchor_point->GetVector2DAt(timecode); - - coords.vertex_top_left -= anchor_val; - coords.vertex_top_right -= anchor_val; - coords.vertex_bottom_left -= anchor_val; - coords.vertex_bottom_right -= anchor_val; - - // rotation - coords.matrix.rotate(QQuaternion::fromEulerAngles(0, 0, float(rotation->GetDoubleAt(timecode)))); - - // scale - coords.matrix.scale(scale->GetVector2DAt(timecode)*0.01f); - - // opacity - coords.opacity *= float(opacity->GetDoubleAt(timecode)*0.01); -} - -QVector3D LerpVector3D(const QVector3D& a, const QVector3D& b, float t) { - return QVector3D( - float_lerp(a.x(), b.x(), t), - float_lerp(a.y(), b.y(), t), - float_lerp(a.z(), b.z(), t) - ); -} - -void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) { - top_left_gizmo->world_pos[0] = coords.vertex_top_left; - top_right_gizmo->world_pos[0] = coords.vertex_top_right; - bottom_right_gizmo->world_pos[0] = coords.vertex_bottom_right; - bottom_left_gizmo->world_pos[0] = coords.vertex_bottom_left; - - top_center_gizmo->world_pos[0] = LerpVector3D(coords.vertex_top_left, coords.vertex_top_right, 0.5); - right_center_gizmo->world_pos[0] = LerpVector3D(coords.vertex_top_right, coords.vertex_bottom_right, 0.5); - bottom_center_gizmo->world_pos[0] = LerpVector3D(coords.vertex_bottom_right, coords.vertex_bottom_left, 0.5); - left_center_gizmo->world_pos[0] = LerpVector3D(coords.vertex_bottom_left, coords.vertex_top_left, 0.5); - - rotate_gizmo->world_pos[0] = QVector3D( - float_lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), 0.5f), - float_lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1f), - 0.0f - ); - - rect_gizmo->world_pos[0] = coords.vertex_top_left; - rect_gizmo->world_pos[1] = coords.vertex_top_right; - rect_gizmo->world_pos[2] = coords.vertex_bottom_right; - rect_gizmo->world_pos[3] = coords.vertex_bottom_left; -} diff --git a/effects/internal/transformeffect.h b/effects/internal/transformeffect.h deleted file mode 100644 index 132c6d164..000000000 --- a/effects/internal/transformeffect.h +++ /dev/null @@ -1,68 +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 TRANSFORMEFFECT_H -#define TRANSFORMEFFECT_H - -#include "nodes/oldeffectnode.h" - -class TransformEffect : public OldEffectNode { - Q_OBJECT -public: - TransformEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString category() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void refresh() override; - virtual void process_coords(double timecode, GLTextureCoords& coords, int data) override; - - virtual void gizmo_draw(double timecode, GLTextureCoords& coords) override; - -public slots: - void toggle_uniform_scale(bool enabled); - -private: - Vec2Input* position; - Vec2Input* scale; - BoolInput* uniform_scale_field; - DoubleInput* rotation; - Vec2Input* anchor_point; - DoubleInput* opacity; - - EffectGizmo* top_left_gizmo; - EffectGizmo* top_center_gizmo; - EffectGizmo* top_right_gizmo; - EffectGizmo* bottom_left_gizmo; - EffectGizmo* bottom_center_gizmo; - EffectGizmo* bottom_right_gizmo; - EffectGizmo* left_center_gizmo; - EffectGizmo* right_center_gizmo; - EffectGizmo* anchor_gizmo; - EffectGizmo* rotate_gizmo; - EffectGizmo* rect_gizmo; -}; - -#endif // TRANSFORMEFFECT_H diff --git a/effects/internal/voideffect.cpp b/effects/internal/voideffect.cpp deleted file mode 100644 index fd81cd400..000000000 --- a/effects/internal/voideffect.cpp +++ /dev/null @@ -1,123 +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 "voideffect.h" - -#include -#include -#include - -#include "ui/collapsiblewidget.h" -#include "global/debug.h" - -VoidEffect::VoidEffect(Clip* c, const QString& n, const QString& id) : - OldEffectNode(c), - display_name_(n), - id_(id) -{ - if (display_name_.isEmpty()) { - display_name_ = tr("(unknown)"); - } - - new LabelWidget(this, tr("Missing Effect"), display_name_); -} - -QString VoidEffect::name() -{ - return display_name_; -} - -QString VoidEffect::id() -{ - return id_; -} - -QString VoidEffect::description() -{ - return QString(); -} - -EffectType VoidEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType VoidEffect::subtype() -{ - return olive::kTypeVideo; -} - -bool VoidEffect::IsCreatable() -{ - return false; -} - -OldEffectNodePtr VoidEffect::Create(Clip *) -{ - return nullptr; -} - -OldEffectNodePtr VoidEffect::copy(Clip* c) { - OldEffectNodePtr copy = std::make_shared(c, display_name_, id_); - copy->SetEnabled(IsEnabled()); - copy_field_keyframes(copy); - return copy; -} - -void VoidEffect::load(QXmlStreamReader &stream) { - QString tag = stream.name().toString(); - - QXmlStreamWriter writer(&bytes_); - - // copy XML from reader to writer - while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { - stream.readNext(); - - if (stream.isStartElement()) { - writer.writeStartElement(stream.name().toString()); - } - if (stream.isEndElement()) { - writer.writeEndElement(); - } - if (stream.isCharacters()) { - writer.writeCharacters(stream.text().toString()); - } - for (int i=0;i tag, ignored when loading - stream.writeStartElement("void"); - stream.writeEndElement(); - - if (!bytes_.isEmpty()) { - // write stored data - QIODevice* device = stream.device(); - device->write(bytes_); - } - } -} diff --git a/effects/internal/voideffect.h b/effects/internal/voideffect.h deleted file mode 100644 index 323e04c05..000000000 --- a/effects/internal/voideffect.h +++ /dev/null @@ -1,54 +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 VOIDEFFECT_H -#define VOIDEFFECT_H - -/* VoidEffect is a placeholder used when Olive is unable to find an effect - * requested by a loaded project. It displays a missing effect so the user knows - * an effect is missing, and stores the XML project data verbatim so that it - * isn't lost if the user saves over the project. - */ - -#include "nodes/oldeffectnode.h" - -class VoidEffect : public OldEffectNode { - Q_OBJECT -public: - VoidEffect(Clip* c, const QString& n, const QString &id); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual bool IsCreatable() override; - virtual OldEffectNodePtr Create(Clip *c) override; - virtual OldEffectNodePtr copy(Clip* c) override; - - virtual void load(QXmlStreamReader &stream) override; - virtual void save(QXmlStreamWriter &stream) override; -private: - QByteArray bytes_; - QString display_name_; - QString id_; -}; - -#endif // VOIDEFFECT_H diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp deleted file mode 100644 index 21dab6655..000000000 --- a/effects/internal/volumeeffect.cpp +++ /dev/null @@ -1,90 +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 "volumeeffect.h" - -#include -#include -#include -#include - -#include "ui/labelslider.h" -#include "ui/collapsiblewidget.h" - -VolumeEffect::VolumeEffect(Clip* c) : OldEffectNode(c) { - volume_val = new DoubleInput(this, "volume", tr("Volume")); - - // set defaults - volume_val->SetDefault(1); - volume_val->SetDisplayType(LabelSlider::Decibel); -} - -QString VolumeEffect::name() -{ - return tr("Volume"); -} - -QString VolumeEffect::id() -{ - return "org.olivevideoeditor.Olive.volume"; -} - -QString VolumeEffect::description() -{ - return tr("Adjust the volume of this clip's audio"); -} - -EffectType VolumeEffect::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType VolumeEffect::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr VolumeEffect::Create(Clip *c) -{ - return std::make_shared(c); -} - -void VolumeEffect::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - - Q_UNUSED(type) - - double interval = (timecode_end-timecode_start)/nb_samples; - - for (int i=0;iGetDoubleAt(timecode_start+(interval*i)); - - for (int j=0;j. - -***/ - -#ifndef VOLUMEEFFECT_H -#define VOLUMEEFFECT_H - -#include "nodes/oldeffectnode.h" - -class VolumeEffect : public OldEffectNode { - Q_OBJECT -public: - VolumeEffect(Clip* c); - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; - -private: - DoubleInput* volume_val; -}; - -#endif // VOLUMEEFFECT_H diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp deleted file mode 100644 index 46cb50b10..000000000 --- a/effects/internal/vsthost.cpp +++ /dev/null @@ -1,432 +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 "vsthost.h" - -// adapted from http://teragonaudio.com/article/How-to-make-your-own-VST-host.html - -#include -#include -#include -#include -#include -#include - -#include "rendering/audio.h" -#include "ui/mainwindow.h" -#include "global/global.h" -#include "global/debug.h" - -// Load libraries for retrieving the native window handle. Used for VST plugins that have a separate window -// dedicated to controls. -#if defined(Q_OS_WIN) -#include -#elif defined(Q_OS_MACOS) -#include -class NSWindow; -#elif defined(Q_OS_LINUX) -#include -#endif - -#define BLOCK_SIZE 512 - -struct VSTRect { - int16_t top; - int16_t left; - int16_t bottom; - int16_t right; -}; - -#define effGetChunk 23 -#define effSetChunk 24 - -// C callbacks -extern "C" { -// Main host callback -intptr_t hostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) { - Q_UNUSED(value) - - switch(opcode) { - case audioMasterAutomate: - effect->setParameter(effect, index, opt); - break; - case audioMasterVersion: - return 2400; - case audioMasterIdle: - effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0); - break; - case audioMasterWantMidi: - // no midi support, return 0 - break; - case audioMasterGetSampleRate: - return current_audio_freq(); - case audioMasterGetBlockSize: - return BLOCK_SIZE; - case audioMasterGetCurrentProcessLevel: - // process level happens to be 0 - break; - case audioMasterGetProductString: - strcpy(static_cast(ptr), "OLIVETEAM"); - break; - case audioMasterBeginEdit: - // we don't really care about this - // but we are aware of it - break; - case audioMasterEndEdit: // change made - olive::Global->set_modified(true); - break; - default: - qInfo() << "Plugin requested unhandled opcode" << opcode; - } - return 0; -} -} - -// Plugin's entry point -typedef AEffect *(*vstPluginFuncPtr)(audioMasterCallback host); -// Plugin's getParameter() method -typedef float (*getParameterFuncPtr)(AEffect *effect, int32_t index); -// Plugin's setParameter() method -typedef void (*setParameterFuncPtr)(AEffect *effect, int32_t index, float value); -// Plugin's processEvents() method -typedef int32_t (*processEventsFuncPtr)(VstEvents *events); -// Plugin's process() method -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; - } - - // Try to load the plugin - modulePtr.setFileName(dll_fn); - if (!modulePtr.load()) { - - // 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; - - } - - // 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 == 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); - -} - -void VSTHost::freePlugin() { - if (plugin != nullptr) { - stopPlugin(); - data_cache.clear(); - modulePtr.unload(); - plugin = nullptr; - } -} - -bool VSTHost::configurePluginCallbacks() { - // Check plugin's magic number - // If incorrect, then the file either was not loaded properly, is not a - // real VST plugin, or is otherwise corrupt. - if(plugin->magic != kEffectMagic) { - qCritical() << "Plugin's magic number is bad"; - QMessageBox::critical(olive::MainWindow, tr("VST Error"), tr("Plugin's magic number is invalid")); - return false; - } - - // Create dispatcher handle - dispatcher = reinterpret_cast(plugin->dispatcher); - - // Set up plugin callback functions - plugin->getParameter = reinterpret_cast(plugin->getParameter); - plugin->processReplacing = reinterpret_cast(plugin->processReplacing); - plugin->setParameter = reinterpret_cast(plugin->setParameter); - - return true; -} - -void VSTHost::startPlugin() { - dispatcher(plugin, effOpen, 0, 0, nullptr, 0.0f); - - // Set some default properties - dispatcher(plugin, effSetSampleRate, 0, 0, nullptr, current_audio_freq()); - dispatcher(plugin, effSetBlockSize, 0, BLOCK_SIZE, nullptr, 0.0f); - - resumePlugin(); -} - -void VSTHost::stopPlugin() { - suspendPlugin(); - - dispatcher(plugin, effClose, 0, 0, nullptr, 0); -} - -void VSTHost::resumePlugin() { - dispatcher(plugin, effMainsChanged, 0, 1, nullptr, 0.0f); -} - -void VSTHost::suspendPlugin() { - dispatcher(plugin, effMainsChanged, 0, 0, nullptr, 0.0f); -} - -bool VSTHost::canPluginDo(char *canDoString) { - return (dispatcher(plugin, effCanDo, 0, 0, static_cast(canDoString), 0.0f) > 0); -} - -void VSTHost::CreateDialogIfNull() -{ - if (dialog == nullptr) { - dialog = new QDialog(olive::MainWindow); - dialog->setWindowTitle(tr("VST Plugin")); - dialog->setAttribute(Qt::WA_NativeWindow, true); - dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint); - connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button())); - } -} - -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) : - OldEffectNode(c), - plugin(nullptr), - dialog(nullptr), - input_cache(BLOCK_SIZE), - output_cache(BLOCK_SIZE) -{ - plugin = nullptr; - - file_field = new FileInput(this, "filename", tr("Plugin"), true, false); - connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()), Qt::QueuedConnection); - - show_interface_btn = new ButtonWidget(this, tr("Interface"), tr("Show")); - show_interface_btn->SetCheckable(true); - show_interface_btn->SetEnabled(false); - connect(show_interface_btn, SIGNAL(Toggled(bool)), this, SLOT(show_interface(bool))); -} - -VSTHost::~VSTHost() { - freePlugin(); -} - -QString VSTHost::name() -{ - return tr("VST Plugin 2.x"); -} - -QString VSTHost::id() -{ - return "org.olivevideoeditor.Olive.vst2x"; -} - -QString VSTHost::description() -{ - return tr("Use a VST 2.x plugin on this clip's audio."); -} - -EffectType VSTHost::type() -{ - return EFFECT_TYPE_EFFECT; -} - -olive::TrackType VSTHost::subtype() -{ - return olive::kTypeAudio; -} - -OldEffectNodePtr VSTHost::Create(Clip *c) -{ - return std::make_shared(c); -} - -void VSTHost::process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) { - if (plugin != nullptr) { - - // Make copy of audio - input_cache.Create(channel_count); - output_cache.Create(channel_count); - - for (int i=0;iprocessReplacing(plugin, input_cache.data(), output_cache.data(), sample_size); - - // Copy output cache back to samples - for (int j=0;j 0) { - stream.writeTextElement("plugindata", data_cache.toBase64()); - } -} - -void VSTHost::show_interface(bool show) { - CreateDialogIfNull(); - dialog->setVisible(show); - - if (show) { -#if defined(Q_OS_WIN) - dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast(dialog->windowHandle()->winId()), 0); -#elif defined(Q_OS_MACOS) - dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast(dialog->windowHandle()->winId()), 0); -#elif defined(Q_OS_LINUX) || defined(__HAIKU__) - dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast(dialog->windowHandle()->winId()), 0); -#endif - } else { - dispatcher(plugin, effEditClose, 0, 0, nullptr, 0); - } -} - -void VSTHost::uncheck_show_button() { - show_interface_btn->SetChecked(false); -} - -void VSTHost::change_plugin() { - freePlugin(); - loadPlugin(); - if (plugin != nullptr) { - if (configurePluginCallbacks()) { - startPlugin(); - - 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); - - } else { - - modulePtr.unload(); - plugin = nullptr; - - } - } - show_interface_btn->SetEnabled(plugin != nullptr); -} - -SampleCache::SampleCache(int block_size) : - block_size_(block_size), - channel_count_(0), - array_(nullptr) -{ -} - -SampleCache::~SampleCache() -{ - destroy(); -} - -void SampleCache::Create(int channels) -{ - if (channel_count_ != channels) { - - if (channel_count_ > 0) { - destroy(); - } - - channel_count_ = channels; - - array_ = new float* [channel_count_]; - for (int i=0;i. - -***/ - -#ifndef VSTHOSTWIN_H -#define VSTHOSTWIN_H - -#include -#include - -#include "nodes/oldeffectnode.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); - -class SampleCache { -public: - SampleCache(int block_size); - ~SampleCache(); - - void Create(int channels); - void SetZero(); - - float** data(); -private: - int channel_count_; - int block_size_; - float** array_; - void destroy(); -}; - -class VSTHost : public OldEffectNode { - Q_OBJECT -public: - VSTHost(Clip* c); - virtual ~VSTHost() override; - - virtual QString name() override; - virtual QString id() override; - virtual QString description() override; - virtual EffectType type() override; - virtual olive::TrackType subtype() override; - virtual OldEffectNodePtr Create(Clip *c) override; - - virtual void process_audio(double timecode_start, - double timecode_end, - float **samples, - int nb_samples, - int channel_count, - int type) override; - - virtual void custom_load(QXmlStreamReader& stream) override; - virtual void save(QXmlStreamWriter& stream) override; -private slots: - void show_interface(bool show); - void uncheck_show_button(); - void change_plugin(); -private: - FileInput* file_field; - ButtonWidget* show_interface_btn; - - void loadPlugin(); - void freePlugin(); - dispatcherFuncPtr dispatcher; - AEffect* plugin; - bool configurePluginCallbacks(); - void startPlugin(); - void stopPlugin(); - void resumePlugin(); - void suspendPlugin(); - bool canPluginDo(char *canDoString); - void CreateDialogIfNull(); - QDialog* dialog; - QByteArray data_cache; - SampleCache input_cache; - SampleCache output_cache; - - void send_data_cache_to_plugin(); - - QLibrary modulePtr; -}; - -#endif // VSTHOSTWIN_H diff --git a/effects/keyframe.cpp b/effects/keyframe.cpp deleted file mode 100644 index 4ec5c0def..000000000 --- a/effects/keyframe.cpp +++ /dev/null @@ -1,66 +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 "keyframe.h" - -#include - -#include "effectfields.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "panels/panels.h" - -EffectKeyframe::EffectKeyframe() -{ - pre_handle = QPointF(-40, 0); - post_handle = QPointF(40, 0); -} - -void delete_keyframes(QVector& selected_key_fields, QVector &selected_keys) { - QVector fields; - QVector key_indices; - - for (int i=0;i 0) { - ComboAction* ca = new ComboAction(); - for (int i=0;iappend(new KeyframeDelete(fields.at(i), key_indices.at(i))); - } - olive::undo_stack.push(ca); - selected_keys.clear(); - selected_key_fields.clear(); - update_ui(false); - } -} diff --git a/effects/keyframe.h b/effects/keyframe.h deleted file mode 100644 index 924d554a2..000000000 --- a/effects/keyframe.h +++ /dev/null @@ -1,44 +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 KEYFRAME_H -#define KEYFRAME_H - -#include -#include - -class EffectField; - -class EffectKeyframe { -public: - EffectKeyframe(); - - int type; - double time; - QVariant data; - - // only for bezier type - QPointF pre_handle; - QPointF post_handle; -}; - -void delete_keyframes(QVector &selected_key_fields, QVector &selected_keys); - -#endif // KEYFRAME_H diff --git a/effects/shaders/boxblur.frag b/effects/shaders/boxblur.frag deleted file mode 100644 index d2b29fc8f..000000000 --- a/effects/shaders/boxblur.frag +++ /dev/null @@ -1,27 +0,0 @@ -uniform float radius; -uniform bool horiz_blur; -uniform bool vert_blur; -uniform int iteration; -uniform vec2 resolution; - -vec4 process(vec4 col) { - float rad = ceil(radius); - - float divider = 1.0 / rad; - vec4 color = vec4(0.0); - bool radius_is_zero = (rad == 0.0); - - if (iteration == 0 && horiz_blur && !radius_is_zero) { - for (float x=-rad+0.5;x<=rad;x+=2.0) { - color += texture2D(texture, vec2(gl_FragCoord.x+x, gl_FragCoord.y)/resolution)*(divider); - } - return color; - } else if (iteration == 1 && vert_blur && !radius_is_zero) { - for (float x=-rad+0.5;x<=rad;x+=2.0) { - color += texture2D(texture, vec2(gl_FragCoord.x, gl_FragCoord.y+x)/resolution)*(divider); - } - return color; - } else { - return col; - } -} diff --git a/effects/shaders/boxblur.xml b/effects/shaders/boxblur.xml deleted file mode 100644 index d1de2b8fc..000000000 --- a/effects/shaders/boxblur.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/effects/shaders/bulge.frag b/effects/shaders/bulge.frag deleted file mode 100644 index 18b3271ac..000000000 --- a/effects/shaders/bulge.frag +++ /dev/null @@ -1,28 +0,0 @@ -const float PI = 3.1415926535; - -uniform vec2 resolution; -uniform float amount; -uniform float xoff; -uniform float yoff; - -vec2 distort(vec2 p, vec2 offset) { - float theta = atan(p.y, p.x); - float radius = length(p); - radius = pow(radius, (1.0+amount*0.01)); - p.x = radius * cos(theta) + offset.x; - p.y = radius * sin(theta) + offset.y; - return 0.5 * (p + 1.0); -} - -vec4 process(vec4 col) { - vec2 offset = vec2(xoff/resolution.x, yoff/resolution.y); - vec2 xy = 2.0 * v_texcoord - 1.0 - offset; - vec2 uv; - float d = length(xy); - uv = distort(xy, offset); - if (uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0) { - return texture2D(texture, uv); - } else { - return vec4(0.0); - } -} \ No newline at end of file diff --git a/effects/shaders/bulge.xml b/effects/shaders/bulge.xml deleted file mode 100644 index 6fe41571f..000000000 --- a/effects/shaders/bulge.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/chromaticaberration.frag b/effects/shaders/chromaticaberration.frag deleted file mode 100644 index 1b795f348..000000000 --- a/effects/shaders/chromaticaberration.frag +++ /dev/null @@ -1,17 +0,0 @@ -uniform float red_amount; -uniform float green_amount; -uniform float blue_amount; - -uniform vec2 resolution; - -vec4 process(vec4 col) { - vec2 rOffset = vec2(red_amount*0.01)/resolution; - vec2 gOffset = vec2(green_amount*0.01)/resolution; - vec2 bOffset = vec2(blue_amount*0.01)/resolution; - - vec4 rValue = texture2D(texture, v_texcoord - rOffset); - vec4 gValue = texture2D(texture, v_texcoord - gOffset); - vec4 bValue = texture2D(texture, v_texcoord - bOffset); - - return vec4(rValue.r, gValue.g, bValue.b, col.a); -} \ No newline at end of file diff --git a/effects/shaders/chromaticaberration.xml b/effects/shaders/chromaticaberration.xml deleted file mode 100644 index 5f90a5737..000000000 --- a/effects/shaders/chromaticaberration.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/crop.frag b/effects/shaders/crop.frag deleted file mode 100644 index 65b95df39..000000000 --- a/effects/shaders/crop.frag +++ /dev/null @@ -1,47 +0,0 @@ -uniform float left; -uniform float top; -uniform float right; -uniform float bottom; -uniform float feather; -uniform bool invert; -uniform vec2 resolution; - -uniform mediump float amount_val; - -vec4 process(vec4 col) { - float alpha = 1.0; - - - if (feather == 0.0) { - if (v_texcoord.x < (left*0.01) || v_texcoord.y < (top*0.01) || v_texcoord.x > (1.0-(right*0.01)) || v_texcoord.y > (1.0-(bottom*0.01))) { - alpha = 0.0; - } - } else { - - float f = pow(2.0, 10.0-(feather*0.25)); - - if (left > 0.0) { - alpha *= clamp(((resolution.x*v_texcoord.x+(0.5/f))-(left*0.01*resolution.x))*f, 0.0, 1.0); // left - } - - if (top > 0.0) { - alpha *= clamp(((resolution.y*v_texcoord.y+(0.5/f))-(top*0.01*resolution.y))*f, 0.0, 1.0); // top - } - - if (right > 0.0) { - alpha *= clamp(((resolution.x*(1.0-v_texcoord.x)+(0.5/f))-(right*0.01*resolution.x))*f, 0.0, 1.0); // right - } - - if (bottom > 0.0) { - alpha *= clamp(((resolution.y*(1.0-v_texcoord.y)+(0.5/f))-(bottom*0.01*resolution.y))*f, 0.0, 1.0); // bottom - } - - - } - - if (invert) { - return col * (1.0-alpha); - } else { - return col * alpha; - } -} \ No newline at end of file diff --git a/effects/shaders/crop.xml b/effects/shaders/crop.xml deleted file mode 100644 index 80d1717ea..000000000 --- a/effects/shaders/crop.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/despill.frag b/effects/shaders/despill.frag deleted file mode 100644 index df6ae2bbd..000000000 --- a/effects/shaders/despill.frag +++ /dev/null @@ -1,69 +0,0 @@ -/*** - Despill - for cleaning up keying residue. - Written by unfa for Olive Video Editor. -***/ - -uniform sampler2D tex; -varying vec2 uTexCoord; -uniform vec2 resolution; -uniform int channel; -uniform float factorIn; -uniform float balanceIn; - -const vec2 renderScale = vec2(1,1); - -float average(float a, float b, float balance) -{ - return ( ( (a * ( 1 + balance)) + (b * (1 - balance)) ) * 0.5 ); -} - -float composite(float a, float b, float factor) -{ - return (( min(a, b) * factor ) + (a * ( 1.0 - factor))); -} - -void main(void) -{ - - float factor = factorIn * 0.01; // convert factor from 0..100 scale to 0..1 scale - float balance = balanceIn * 0.01; // convert balance from -100..100 scale to -1..1 scale - - vec2 uv = gl_FragCoord.xy/resolution.xy; - - vec4 col = texture2D(tex, uv); - - // separate channels - - float r = col.r; - float g = col.g; - float b = col.b; - float a = col.a; - - // Select despilled channel: 0 = RED; 1 = GREEN; 2 = BLUE; - - if (channel == 0) // RED - { - // replace new channel by avaraging between existing channels - float r2 = average(g, b, balance); - - // now composite the original and new channel using the "darken" mode - r = composite(r, r2, factor); - } - - if (channel == 1) // GREEN - { - float g2 = average(r, b, balance); - - g = composite(g, g2, factor); - } - - if (channel == 2) // BLUE - { - float b2 = average(r, g, balance); - - b = composite(b, b2, factor); - } - - // return the result - gl_FragColor = vec4(r, g, b, a); -} diff --git a/effects/shaders/despill.xml b/effects/shaders/despill.xml deleted file mode 100644 index 53a419951..000000000 --- a/effects/shaders/despill.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/effects/shaders/directionalblur.frag b/effects/shaders/directionalblur.frag deleted file mode 100644 index 4384746c6..000000000 --- a/effects/shaders/directionalblur.frag +++ /dev/null @@ -1,26 +0,0 @@ -#define M_PI 3.1415926535897932384626433832795 - -uniform float angle; // degrees -uniform float length; - -uniform vec2 resolution; - -vec4 process(vec4 col) { - if (length > 0.0) { - float ceillen = ceil(length); - float radians = (angle*M_PI)/180.0; - float divider = 1.0 / ceillen; - float sin_angle = sin(radians); - float cos_angle = cos(radians); - - vec4 color = vec4(0.0); - for (float i=-ceillen+0.5;i<=ceillen;i+=2.0) { - float y = sin_angle * i; - float x = cos_angle * i; - color += texture2D(texture, vec2(gl_FragCoord.x+x, gl_FragCoord.y+y)/resolution)*(divider); - } - return color; - } else { - return col; - } -} \ No newline at end of file diff --git a/effects/shaders/directionalblur.xml b/effects/shaders/directionalblur.xml deleted file mode 100644 index 654f6cdad..000000000 --- a/effects/shaders/directionalblur.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/flip.frag b/effects/shaders/flip.frag deleted file mode 100644 index dbc62f67e..000000000 --- a/effects/shaders/flip.frag +++ /dev/null @@ -1,14 +0,0 @@ -uniform bool horiz; -uniform bool vert; - -vec4 process(vec4 col) { - float x = v_texcoord.x; - float y = v_texcoord.y; - - if (!horiz && !vert) return col; - - if (horiz) x = 1.0 - x; - if (vert) y = 1.0 - y; - - return texture2D(texture, vec2(x, y)); -} \ No newline at end of file diff --git a/effects/shaders/flip.xml b/effects/shaders/flip.xml deleted file mode 100644 index 7e083aafa..000000000 --- a/effects/shaders/flip.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/gaussianblur.frag b/effects/shaders/gaussianblur.frag deleted file mode 100644 index ae332c7c3..000000000 --- a/effects/shaders/gaussianblur.frag +++ /dev/null @@ -1,47 +0,0 @@ -#define M_PI 3.1415926535897932384626433832795 - -uniform float sigma; -uniform vec2 resolution; -uniform bool horiz_blur; -uniform bool vert_blur; -uniform int iteration; - -float gaussian(float x, float sigma) { - return (1.0/(sigma*sqrt(2.0*M_PI)))*exp(-0.5*pow(x/sigma, 2.0)); -} - -float gaussian2(float x, float y, float sigma) { - return (1.0/(pow(sigma, 2.0)*2.0*M_PI))*exp(-0.5*((pow(x, 2.0) + pow(y, 2.0))/pow(sigma, 2.0))); -} - -vec4 process(vec4 col) { - float rad = ceil(3.0 * sigma); - - float sum = 0.0; - - vec4 color = vec4(0.0); - - bool radius_is_zero = (rad == 0.0 || sigma == 0.0); - - if (!radius_is_zero) { - for (float x=-rad+0.5;x<=rad;x+=2.0) { - sum += gaussian2(x, 0.0, sigma); - } - } - - if (iteration == 0 && horiz_blur && !radius_is_zero) { - for (float x=-rad+0.5;x<=rad;x+=2.0) { - float weight = (gaussian2(x, 0.0, sigma)/sum); - color += texture2D(texture, vec2(gl_FragCoord.x+x, gl_FragCoord.y)/resolution)*(weight); - } - return color; - } else if (iteration == 1 && vert_blur && !radius_is_zero) { - for (float x=-rad+0.5;x<=rad;x+=2.0) { - float weight = (gaussian2(0.0, x, sigma)/sum); - color += texture2D(texture, vec2(gl_FragCoord.x, gl_FragCoord.y+x)/resolution)*(weight); - } - return color; - } else { - return col; - } -} \ No newline at end of file diff --git a/effects/shaders/gaussianblur.xml b/effects/shaders/gaussianblur.xml deleted file mode 100644 index a2710cac0..000000000 --- a/effects/shaders/gaussianblur.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/chromakey.frag b/effects/shaders/need checking/chromakey.frag deleted file mode 100644 index 9b48a6213..000000000 --- a/effects/shaders/need checking/chromakey.frag +++ /dev/null @@ -1,67 +0,0 @@ -/*a fast implementation of the chromakey program -(c) 2008 Edward Cannon (adapted to GLSL by Olive Team) -feel free to use or modify at will*/ - -/*the following three functions convert RGB into YCbCr in the same manner as in JPEG images*/ - -uniform vec3 key_color; -uniform float tola; -uniform float tolb; -uniform bool opt; -uniform int mode; - -float rgb2y (vec3 c) { - /*a utility function to convert colors from REC.709 RGB into YCbCr*/ - -// This isn’t colour managed and is a huge mess, but in the -// short term, using correct weights will give significantly -// more ideal results. The correct weights for REC.709 are -// 0.2126 R, 0.7152 G, and 0.0722 B. Easy change. -// The coefficients for YCbCr are calculated off of the -// REC.709 values. - return (0.2126*c.r + 0.7152*c.g + 0.0722*c.b); -} - -float rgb2cb (vec3 c) { - /*a utility function to convert colors from REC.709 RGB into YCbCr*/ - return (0.5 + -0.1145721061*c.r - 0.3854278939*c.g + 0.5*c.b); -} - -float rgb2cr (vec3 c) { - /*a utility function to convert colors from REC.709 RGB into YCbCr*/ - return (0.5 + 0.5*c.r - 0.4541529083*c.g - 0.0458470917*c.b); -} - -float colorclose(float Cb_p,float Cr_p,float Cb_key,float Cr_key,float tola,float tolb) { - /*decides if a color is close to the specified hue*/ - float temp = sqrt(((Cb_key-Cb_p)*(Cb_key-Cb_p))+((Cr_key-Cr_p)*(Cr_key-Cr_p))); - if (temp < tola) {return (0.0);} - if (temp < tolb) {return ((temp-tola)/(tolb-tola));} - return (1.0); -} - -vec4 process(vec4 texture_color) { - float cb_key = rgb2cb(key_color); - float cr_key = rgb2cr(key_color); - - float cb = rgb2cb(texture_color.rgb); - float cr = rgb2cr(texture_color.rgb); - float mask = colorclose(cb, cr, cb_key, cr_key, (tola/100.0), (tolb/100.0)); - - if (mode == 0) { // composite - //float submask = 1.0-mask; - float submask = 0.0; - texture_color.r = max(texture_color.r - submask*key_color.r, 0.0) + submask; - texture_color.g = max(texture_color.g - submask*key_color.g, 0.0) + submask; - texture_color.b = max(texture_color.b - submask*key_color.b, 0.0) + submask; - texture_color.a *= mask; - - // premultiply - texture_color.rgb *= texture_color.a; - } else if (mode == 1) { // alpha - texture_color.rgb = vec3(mask); - } else if (mode == 2) { // original - } - - return texture_color; -} diff --git a/effects/shaders/need checking/chromakey.xml b/effects/shaders/need checking/chromakey.xml deleted file mode 100644 index ebe442dbf..000000000 --- a/effects/shaders/need checking/chromakey.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/colorcorrection.frag b/effects/shaders/need checking/colorcorrection.frag deleted file mode 100644 index 58f36a277..000000000 --- a/effects/shaders/need checking/colorcorrection.frag +++ /dev/null @@ -1,74 +0,0 @@ -#version 110 - -uniform float temperature; -uniform float tint; -uniform float exposure; -uniform float contrast; -uniform float highlights; -uniform float shadows; -uniform float whites; -uniform float blacks; -uniform float saturation; - -uniform sampler2D myTexture; -varying vec2 vTexCoord; - -void main(void) { - vec4 textureColor = texture2D(myTexture, vTexCoord); - - vec3 rgb = textureColor.rgb; - - // temperature - float temp = temperature * 0.01; - float redTemp = (temp <= 66.0) ? 1.0 : min(1.0, max(0.0, - (1.2929361861 * pow(temp - 60.0, -0.1332047592)) - )); - float greenTemp = min(1.0, max(0.0, - (temp <= 66.0) ? (0.3900815788 * log(temp) - 0.6318414438) : (1.1298908609 * pow(temp - 60.0, -0.0755148492)) - )); - float blueTemp = (temp >= 66.0) ? 1.0 : min(1.0, max(0.0, - (0.5432067891 * log(temp - 10.0) - 1.1962540891) - )); - rgb *= vec3(redTemp, greenTemp, blueTemp); - - // tint - rgb.g *= ((tint*0.01)+1.0); - - // exposure - rgb *= pow(2.0, exposure*0.01); - - // contrast - float contr_val = (contrast*0.01); - rgb = (rgb*contr_val)-((contr_val-1.0)*0.5); - - - // shadows/highlights - //float luma = 0.33*rgb.r + 0.5*rgb.g + 0.16*rgb.b; - if (rgb.r < 0.5 && rgb.g < 0.5 && rgb.b < 0.5) { - float shadow_val = 1.0-(shadows*0.01); - rgb = vec3(pow(rgb.r*2.0, shadow_val)*0.5, pow(rgb.g*2.0, shadow_val)*0.5, pow(rgb.b*2.0, shadow_val)*0.5); - } else if (rgb.r > 0.5 && rgb.g > 0.5 && rgb.b > 0.5) { - float highlight_val = 1.0-(highlights*0.01); - rgb = vec3((pow((rgb.r-0.5)*2.0, highlight_val)*0.5)+0.5, (pow((rgb.g-0.5)*2.0, highlight_val)*0.5)+0.5, (pow((rgb.b-0.5)*2.0, highlight_val)*0.5)+0.5); - } - - - // whites - rgb *= (whites*0.01); - - // blacks - float black_val = 2.0-(blacks*0.01); - rgb = (rgb*black_val)-(black_val-1.0); - - // saturation - const vec3 W = vec3(0.2125, 0.7154, 0.0721); - vec3 intensity = vec3(dot(rgb, W)); - rgb = mix(intensity, rgb, saturation*0.01); - - gl_FragColor = vec4( - rgb.r, - rgb.g, - rgb.b, - textureColor.a - ); -} diff --git a/effects/shaders/need checking/colorcorrection.xml b/effects/shaders/need checking/colorcorrection.xml deleted file mode 100644 index 14c39a28c..000000000 --- a/effects/shaders/need checking/colorcorrection.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/colorsel.frag b/effects/shaders/need checking/colorsel.frag deleted file mode 100644 index 785d13d3a..000000000 --- a/effects/shaders/need checking/colorsel.frag +++ /dev/null @@ -1,78 +0,0 @@ -/* Filter by color characteristic simple program -Based on Edward Cannon's Simple Chroma Key (adaptation by Olive Team) -RGB to HSV based on MattKC's toonify source code -Feel free to modify and use at will */ - -uniform float loc; -uniform float hic; -uniform int compo; -uniform bool invert; - -float rgb2luma(vec3 c) { - return (max(max(c.r,c.g), c.b) + min(min(c.r,c.g), c.b))/2.0; -} - -vec3 rgb2hsv(vec3 c) -{ - float r = c.r; - float b = c.b; - float g = c.g; - float minv, maxv, delta; - vec3 res; - - minv = min(min(r, g), b); - maxv = max(max(r, g), b); - res.z = maxv; // v - - delta = maxv - minv; - - if( maxv != 0.0 ) - res.y = delta / maxv; // s - else { - // r = g = b = 0 // s = 0, v is undefined - res.y = 0.0; - res.x = -1.0; - return res; - } - - if( r == maxv ) - res.x = ( g - b ) / delta; // between yellow & magenta - else if( g == maxv ) - res.x = 2.0 + ( b - r ) / delta; // between cyan & yellow - else - res.x = 4.0 + ( r - g ) / delta; // between magenta & cyan - - res.x = res.x * 60.0; // degrees - if( res.x < 0.0 ) - res.x = res.x + 360.0; - - return res; -} - -bool isNotIncreasingSequence(float a, float b, float c) { - return (c < b || a > b); -} - -vec4 process(vec4 texture_color) { - vec3 color = texture_color.rgb; - float toCheck = 0.0; - - if (compo == 0) { - toCheck = rgb2luma(color)*100.0; - } else if (compo == 4) { - toCheck = color.r*100.0; - } else if (compo == 5) { - toCheck = color.g*100.0; - } else if (compo == 6) { - toCheck = color.b*100.0; - } else if (compo == 1) { - toCheck = rgb2hsv(color).z*100.0; - } else if (compo == 2) { - toCheck = rgb2hsv(color).x/3.6; - } else if (compo == 3) { - toCheck = rgb2hsv(color).y*100.0; - } - texture_color.a = isNotIncreasingSequence(loc, toCheck, hic) ? (invert ? texture_color.a : 0.0) : (invert ? 0.0 : texture_color.a); - texture_color.rgb *= texture_color.a; - return texture_color; -} diff --git a/effects/shaders/need checking/colorsel.xml b/effects/shaders/need checking/colorsel.xml deleted file mode 100644 index 7a3e7cf7a..000000000 --- a/effects/shaders/need checking/colorsel.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/effects/shaders/need checking/common.frag b/effects/shaders/need checking/common.frag deleted file mode 100644 index a8d338af5..000000000 --- a/effects/shaders/need checking/common.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 110 - -uniform sampler2D tex; -varying vec2 vTexCoord; - -void main(void) { - vec4 textureColor = texture2D(tex, vTexCoord); - gl_FragColor = textureColor; -} \ No newline at end of file diff --git a/effects/shaders/need checking/common.vert b/effects/shaders/need checking/common.vert deleted file mode 100644 index d698c628e..000000000 --- a/effects/shaders/need checking/common.vert +++ /dev/null @@ -1,8 +0,0 @@ -#version 110 - -varying vec2 vTexCoord; - -void main() { - vTexCoord = gl_MultiTexCoord0.xy; - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; -} \ No newline at end of file diff --git a/effects/shaders/need checking/crossstitch.frag b/effects/shaders/need checking/crossstitch.frag deleted file mode 100644 index a7e6df237..000000000 --- a/effects/shaders/need checking/crossstitch.frag +++ /dev/null @@ -1,44 +0,0 @@ -#version 110 - -uniform sampler2D tex0; -uniform float time; -uniform vec2 resolution; -uniform float stitching_size; -uniform bool invert; - -varying vec2 vTexCoord; - -vec4 PostFX(sampler2D tex, vec2 uv, float time) { - vec4 c = vec4(0.0); - float size = stitching_size; - vec2 cPos = uv * resolution; - vec2 tlPos = floor(cPos / vec2(size, size)); - tlPos *= size; - int remX = int(mod(cPos.x, size)); - int remY = int(mod(cPos.y, size)); - if (remX == 0 && remY == 0) - tlPos = cPos; - vec2 blPos = tlPos; - blPos.y += (size - 1.0); - if ((remX == remY) || - (((int(cPos.x) - int(blPos.x)) == (int(blPos.y) - int(cPos.y))))) - { - if (!invert) - c = vec4(0.2, 0.15, 0.05, 1.0); - else - c = texture2D(tex, tlPos * vec2(1.0/resolution.x, 1.0/resolution.y)) * 1.4; - } - else - { - if (!invert) - c = texture2D(tex, tlPos * vec2(1.0/resolution.x, 1.0/resolution.y)) * 1.4; - else - c = vec4(0.0, 0.0, 0.0, 1.0); - } - return c; -} - -void main(void) { - vec2 uv = vTexCoord; - gl_FragColor = PostFX(tex0, uv, time); -} \ No newline at end of file diff --git a/effects/shaders/need checking/crossstitch.xml b/effects/shaders/need checking/crossstitch.xml deleted file mode 100644 index 4b628f2ba..000000000 --- a/effects/shaders/need checking/crossstitch.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/emboss.frag b/effects/shaders/need checking/emboss.frag deleted file mode 100644 index ff1fb99c9..000000000 --- a/effects/shaders/need checking/emboss.frag +++ /dev/null @@ -1,38 +0,0 @@ -/* Original source code: https://www.youtube.com/watch?v=I23zT7iu_Y4 -Adapted */ - -varying vec2 vTexCoord; -uniform vec2 resolution; -uniform sampler2D tex; - -uniform float contrast100; -uniform float level; -uniform bool invert; -uniform bool hslmode; // luminance is 2*V - -void main() { - - float contrast = contrast100 / 100.0; - - vec2 onePixel = vec2(floor(level) / resolution.x, floor(level) / resolution.y); // calculating the size of one pixel on the screen for the current resolution - - vec3 color = vec3(.5); // initialize color with half value on all channels - if (invert) { - color += texture2D(tex, vTexCoord - onePixel).rgb * contrast; - color -= texture2D(tex, vTexCoord + onePixel).rgb * contrast; - } else { - color -= texture2D(tex, vTexCoord - onePixel).rgb * contrast; - color += texture2D(tex, vTexCoord + onePixel).rgb * contrast; - } - - // original color - vec4 color0 = texture2D(tex,vTexCoord); - - // grayscale - float gray = (color.r + color.g + color.b) / (hslmode ? 3.0 : 1.5); - - //self-multiply - color = color0.rgb * gray; - - gl_FragColor = vec4(color * color0.a, color0.a); -} diff --git a/effects/shaders/need checking/emboss.xml b/effects/shaders/need checking/emboss.xml deleted file mode 100644 index df8cef189..000000000 --- a/effects/shaders/need checking/emboss.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/effects/shaders/need checking/findedges.frag b/effects/shaders/need checking/findedges.frag deleted file mode 100644 index 5431590ee..000000000 --- a/effects/shaders/need checking/findedges.frag +++ /dev/null @@ -1,53 +0,0 @@ -#version 110 - -/*varying vec4 vertColor; -varying vec4 vertTexCoord; -uniform sampler2D texture; -//uniform vec2 texOffset; - -void main(void) { - // Grouping texcoord variables in order to make it work in the GMA 950. See post #13 - // in this thread: - // http://www.idevgames.com/forums/thread-3467.html - vec2 texOffset = vec2(1.0); - - vec2 tc0 = vertTexCoord.st + vec2(-texOffset.s, -texOffset.t); - vec2 tc1 = vertTexCoord.st + vec2( 0.0, -texOffset.t); - vec2 tc2 = vertTexCoord.st + vec2(+texOffset.s, -texOffset.t); - vec2 tc3 = vertTexCoord.st + vec2(-texOffset.s, 0.0); - vec2 tc4 = vertTexCoord.st + vec2( 0.0, 0.0); - vec2 tc5 = vertTexCoord.st + vec2(+texOffset.s, 0.0); - vec2 tc6 = vertTexCoord.st + vec2(-texOffset.s, +texOffset.t); - vec2 tc7 = vertTexCoord.st + vec2( 0.0, +texOffset.t); - vec2 tc8 = vertTexCoord.st + vec2(+texOffset.s, +texOffset.t); - - vec4 col0 = texture2D(texture, tc0); - vec4 col1 = texture2D(texture, tc1); - vec4 col2 = texture2D(texture, tc2); - vec4 col3 = texture2D(texture, tc3); - vec4 col4 = texture2D(texture, tc4); - vec4 col5 = texture2D(texture, tc5); - vec4 col6 = texture2D(texture, tc6); - vec4 col7 = texture2D(texture, tc7); - vec4 col8 = texture2D(texture, tc8); - - vec4 sum = 8.0 * col4 - (col0 + col1 + col2 + col3 + col5 + col6 + col7 + col8); - gl_FragColor = vec4(sum.rgb, 1.0);// * vertColor; -}*/ - -varying vec4 vertTexCoord; -uniform sampler2D texture; -//uniform vec2 pixels; - -void main(void) -{ - vec2 pixels = vec2(16.0, 9.0); - - vec2 p = vertTexCoord.st; - - p.x -= mod(p.x, 1.0 / pixels.x); - p.y -= mod(p.y, 1.0 / pixels.y); - - vec3 col = texture2D(texture, p).rgb; - gl_FragColor = vec4(col, 1.0); -} \ No newline at end of file diff --git a/effects/shaders/need checking/findedges.xml.disabled b/effects/shaders/need checking/findedges.xml.disabled deleted file mode 100644 index 7f4ec3e5b..000000000 --- a/effects/shaders/need checking/findedges.xml.disabled +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/fisheye.frag b/effects/shaders/need checking/fisheye.frag deleted file mode 100644 index a8b57b7a1..000000000 --- a/effects/shaders/need checking/fisheye.frag +++ /dev/null @@ -1,23 +0,0 @@ -#define M_PI 3.1415926535897932384626433832795 - -uniform float size; - -vec4 process(vec4 col) { - float maxFactor = 2.0 - (size * 0.01); - - vec2 uv; - vec2 xy = 2.0 * v_texcoord - 1.0; - float d = length(xy); - if (d < (2.0-maxFactor)) { - d = length(xy * maxFactor); - float z = sqrt(1.0 - d * d); - float r = atan(d, z) / M_PI; - float phi = atan(xy.y, xy.x); - - uv.x = r * cos(phi) + 0.5; - uv.y = r * sin(phi) + 0.5; - } else { - uv = v_texcoord; - } - return texture2D(texture, uv); -} \ No newline at end of file diff --git a/effects/shaders/need checking/fisheye.xml b/effects/shaders/need checking/fisheye.xml deleted file mode 100644 index 2074ccf31..000000000 --- a/effects/shaders/need checking/fisheye.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/huesatbri.frag b/effects/shaders/need checking/huesatbri.frag deleted file mode 100644 index 0efe90540..000000000 --- a/effects/shaders/need checking/huesatbri.frag +++ /dev/null @@ -1,33 +0,0 @@ -uniform float hue; -uniform float saturation; -uniform float brightness; - -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} - -vec4 process(vec4 tex_color) { - vec3 hsv = rgb2hsv(tex_color.rgb); - hsv.r += (hue/360.0); - hsv.g *= (saturation*0.01); - hsv.b *= (brightness*0.01); - - vec3 rgb = hsv2rgb(hsv); - - return vec4( - rgb.rgb, - tex_color.a - ); -} \ No newline at end of file diff --git a/effects/shaders/need checking/huesatbri.xml b/effects/shaders/need checking/huesatbri.xml deleted file mode 100644 index 9ee74aae5..000000000 --- a/effects/shaders/need checking/huesatbri.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/invert.frag b/effects/shaders/need checking/invert.frag deleted file mode 100644 index 454d8e74a..000000000 --- a/effects/shaders/need checking/invert.frag +++ /dev/null @@ -1,7 +0,0 @@ -uniform float amount; - -vec4 process(vec4 col) { - float amount_val = amount * 0.01; - vec3 color = col.rgb+((vec3(1.0)-col.rgb-col.rgb)*vec3(amount_val)); - return vec4(color, col.a); -} \ No newline at end of file diff --git a/effects/shaders/need checking/invert.xml b/effects/shaders/need checking/invert.xml deleted file mode 100644 index 6c93dc92e..000000000 --- a/effects/shaders/need checking/invert.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/lumakey.frag b/effects/shaders/need checking/lumakey.frag deleted file mode 100644 index b376a60ac..000000000 --- a/effects/shaders/need checking/lumakey.frag +++ /dev/null @@ -1,29 +0,0 @@ -/* Luma key simple program -Based on Edward Cannon's Simple Chroma Key (adaptation by Olive Team) -Feel free to modify and use at will */ - -uniform sampler2D tex; -varying vec2 vTexCoord; - -uniform float loc; -uniform float hic; -uniform bool invert; - -void main(void) { - vec4 texture_color = texture2D(tex,vTexCoord); - - float luma = max(max(texture_color.r,texture_color.g), texture_color.b) + min(min(texture_color.r,texture_color.g), texture_color.b); - - luma /= 2.0; - - if (luma > hic/100.0) { - texture_color.a = (invert ? 0.0 : 1.0); - } else if (luma < loc/100.0) { - texture_color.a = (invert ? 1.0 : 0.0); - } else { - texture_color.a = (invert ? 1.0-luma : luma); - } - - texture_color.rgb *= texture_color.a; - gl_FragColor = texture_color; -} diff --git a/effects/shaders/need checking/lumakey.xml b/effects/shaders/need checking/lumakey.xml deleted file mode 100644 index ba297ef71..000000000 --- a/effects/shaders/need checking/lumakey.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/effects/shaders/need checking/posterize.frag b/effects/shaders/need checking/posterize.frag deleted file mode 100644 index 85ee2c1dc..000000000 --- a/effects/shaders/need checking/posterize.frag +++ /dev/null @@ -1,13 +0,0 @@ -uniform float gamma_cent; // 0.6 -uniform float numColors; // 8.0 - -vec4 process(vec4 color) { - float gamma = gamma_cent*0.01; - vec3 c = color.rgb; - c = pow(c, vec3(gamma, gamma, gamma)); - c = c * numColors; - c = floor(c); - c = c / numColors; - c = pow(c, vec3(1.0/gamma)); - return vec4(c, color.a); -} \ No newline at end of file diff --git a/effects/shaders/need checking/posterize.xml b/effects/shaders/need checking/posterize.xml deleted file mode 100644 index f4ce8e9cd..000000000 --- a/effects/shaders/need checking/posterize.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/toonify.frag b/effects/shaders/need checking/toonify.frag deleted file mode 100644 index e34103ca1..000000000 --- a/effects/shaders/need checking/toonify.frag +++ /dev/null @@ -1,168 +0,0 @@ -#version 150 -uniform sampler2D tex0; -in vec2 vTexCoord; -out vec4 FragColor; - -uniform float colors; // 12.0 -uniform float sat_levels; // 4.0 -uniform float bri_levels; // 4.0 -uniform float edge_thres; // 0.2; -uniform float edge_thres2; // 5.0; - -vec3 RGBtoHSV( float r, float g, float b) -{ - float minv, maxv, delta; - vec3 res; - - minv = min(min(r, g), b); - maxv = max(max(r, g), b); - res.z = maxv; // v - - delta = maxv - minv; - - if( maxv != 0.0 ) - res.y = delta / maxv; // s - else { - // r = g = b = 0 // s = 0, v is undefined - res.y = 0.0; - res.x = -1.0; - return res; - } - - if( r == maxv ) - res.x = ( g - b ) / delta; // between yellow & magenta - else if( g == maxv ) - res.x = 2.0 + ( b - r ) / delta; // between cyan & yellow - else - res.x = 4.0 + ( r - g ) / delta; // between magenta & cyan - - res.x = res.x * 60.0; // degrees - if( res.x < 0.0 ) - res.x = res.x + 360.0; - - return res; -} - -vec3 HSVtoRGB(float h, float s, float v ) -{ - int i; - float f, p, q, t; - vec3 res; - - if( s == 0.0 ) - { - // achromatic (grey) - res.x = v; - res.y = v; - res.z = v; - return res; - } - - h /= 60.0; // sector 0 to 5 - i = int(floor( h )); - f = h - float(i); // factorial part of h - p = v * ( 1.0 - s ); - q = v * ( 1.0 - s * f ); - t = v * ( 1.0 - s * ( 1.0 - f ) ); - - switch(i) - { - case 0: - res.x = v; - res.y = t; - res.z = p; - break; - case 1: - res.x = q; - res.y = v; - res.z = p; - break; - case 2: - res.x = p; - res.y = v; - res.z = t; - break; - case 3: - res.x = p; - res.y = q; - res.z = v; - break; - case 4: - res.x = t; - res.y = p; - res.z = v; - break; - default: // case 5: - res.x = v; - res.y = p; - res.z = q; - break; - } - return res; -} - -// averaged pixel intensity from 3 color channels -float avg_intensity(vec4 pix) -{ - return (pix.r + pix.g + pix.b)/3.; -} - -vec4 get_pixel(vec2 coords, float dx, float dy) -{ - return texture(tex0,coords + vec2(dx, dy)); -} - -// returns pixel color -float IsEdge(in vec2 coords) -{ - float dxtex = 1.0 /float(textureSize(tex0,0)) ; - float dytex = 1.0 /float(textureSize(tex0,0)); - float pix[9]; - int k = -1; - float delta; - - // read neighboring pixel intensities - for (int i=-1; i<2; i++) { - for(int j=-1; j<2; j++) { - k++; - pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex, - float(j)*dytex)); - } - } - - // average color differences around neighboring pixels - delta = (abs(pix[1]-pix[7])+ - abs(pix[5]-pix[3]) + - abs(pix[0]-pix[8])+ - abs(pix[2]-pix[6]) - )/4.; - - //return clamp(5.5*delta,0.0,1.0); - return clamp(edge_thres2*delta,0.0,1.0); -} - -void main() { - vec2 uv = vTexCoord.xy; - vec4 tc = vec4(1.0, 0.0, 0.0, 1.0); - vec3 colorOrg = texture(tex0, uv).rgb; - vec3 vHSV = RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b); - - // hue limiting - if (colors == 0.0) { - vHSV.y = 0.0; - } else { - float hue_divider = (360.0/colors); - vHSV.x = round(vHSV.x/hue_divider)*hue_divider; - - float sat_divider = 100.0/sat_levels; - vHSV.y = round((vHSV.y*100.0)/sat_divider)*sat_divider/100.0; - } - - float bri_divider = 100.0/bri_levels; - vHSV.z = round((vHSV.z*100.0)/bri_divider)*bri_divider/100.0; - - float edg = IsEdge(uv); - vec3 vRGB = (edg >= (1.0-((edge_thres-1.0)*0.01)))? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z); - tc = vec4(vRGB.x,vRGB.y,vRGB.z, 1); - FragColor = tc; -} \ No newline at end of file diff --git a/effects/shaders/need checking/toonify.xml b/effects/shaders/need checking/toonify.xml deleted file mode 100644 index 7cad76af4..000000000 --- a/effects/shaders/need checking/toonify.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/need checking/volumetriclight.frag b/effects/shaders/need checking/volumetriclight.frag deleted file mode 100644 index bf27e17d7..000000000 --- a/effects/shaders/need checking/volumetriclight.frag +++ /dev/null @@ -1,15 +0,0 @@ -uniform float amount; - -uniform vec2 resolution; // screen resolution - -vec4 process(vec4 col) { - float alpha = texture2D(texture, v_texcoord)[3]; - - vec3 p = gl_FragCoord.xyz/vec3(resolution, 1.0)-.5; - vec4 color = texture2D(texture,.5+(p.xy*=.992)); - vec3 o = color.rgb; - for (float i=0.;i - - - - - - \ No newline at end of file diff --git a/effects/shaders/noise.frag b/effects/shaders/noise.frag deleted file mode 100644 index 352560d40..000000000 --- a/effects/shaders/noise.frag +++ /dev/null @@ -1,33 +0,0 @@ -uniform vec2 resolution; -uniform float time; - -uniform float amount; -uniform bool color; -uniform bool blend; - -// precision lowp float; - -float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio -float PI = 3.14159265358979323846264 * 00000.1; // PI -float SQ2 = 1.41421356237309504880169 * 10000.0; // Square Root of Two - -float gold_noise(vec2 coordinate, float seed){ - return fract(tan(distance(coordinate*(seed+PHI), vec2(PHI, PI)))*SQ2)*(amount*0.01); -} - -vec4 process(vec4 col) { - vec3 noise; - if (color) { - noise = vec3(gold_noise(v_texcoord, time + 42069.0), gold_noise(v_texcoord, time + 69220.0), gold_noise(v_texcoord, time + 1337.0)); - } else { - noise = vec3(gold_noise(v_texcoord, time + 69420.0)); - } - - if (blend) { - noise = (noise - vec3(amount*0.005))*vec3(2.0); - - return vec4(col.rgb+noise, col.a); - } else { - return vec4(noise, 1.0); - } -} diff --git a/effects/shaders/noise.xml b/effects/shaders/noise.xml deleted file mode 100644 index 229f967d2..000000000 --- a/effects/shaders/noise.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/pixelate.frag b/effects/shaders/pixelate.frag deleted file mode 100644 index 7f9a57bb1..000000000 --- a/effects/shaders/pixelate.frag +++ /dev/null @@ -1,16 +0,0 @@ -uniform float pixels_x; -uniform float pixels_y; -uniform bool bypass; - -vec4 process(vec4 col) { - if (bypass) { - return col; - } else { - vec2 p = v_texcoord; - - p.x -= mod(p.x, 1.0 / pixels_x); - p.y -= mod(p.y, 1.0 / pixels_y); - - return texture2D(texture, p); - } -} \ No newline at end of file diff --git a/effects/shaders/pixelate.xml b/effects/shaders/pixelate.xml deleted file mode 100644 index 8fa63a932..000000000 --- a/effects/shaders/pixelate.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/radialblur.frag b/effects/shaders/radialblur.frag deleted file mode 100644 index 203ad81f6..000000000 --- a/effects/shaders/radialblur.frag +++ /dev/null @@ -1,34 +0,0 @@ -#define M_PI 3.1415926535897932384626433832795 - -uniform float radius; -uniform float center_x; -uniform float center_y; - -uniform vec2 resolution; - -vec4 process(vec4 col) { - if (radius > 0.0) { - vec2 distance = vec2((gl_FragCoord.x - (resolution.x/2.0) - center_x), (gl_FragCoord.y - (resolution.y/2.0) - center_y)); - - float angle = atan(distance.y/distance.x); - float sin_angle = sin(angle); - float cos_angle = cos(angle); - - float multiplier = length(distance/resolution); - - float limit = ceil(radius * multiplier); - - float divider = 1.0 / limit; - - vec4 color = vec4(0.0); - - for (float i=-limit+0.5;i<=limit;i+=2.0) { - float y = sin_angle * i; - float x = cos_angle * i; - color += texture2D(texture, vec2(gl_FragCoord.x+x, gl_FragCoord.y+y)/resolution)*(divider); - } - return color; - } else { - return col; - } -} \ No newline at end of file diff --git a/effects/shaders/radialblur.xml b/effects/shaders/radialblur.xml deleted file mode 100644 index 547ffe8f4..000000000 --- a/effects/shaders/radialblur.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/ripple.frag b/effects/shaders/ripple.frag deleted file mode 100644 index 89f053208..000000000 --- a/effects/shaders/ripple.frag +++ /dev/null @@ -1,29 +0,0 @@ -uniform float speed; -uniform float intensity; -uniform float frequency; -uniform float xoff; -uniform float yoff; -uniform bool reverse; -uniform bool stretch; - -uniform vec2 resolution; // Screen resolution -uniform float time; // time in seconds - -vec4 process(vec4 col) { - vec2 texCoord = v_texcoord; - vec2 center = vec2(1.0); - - if (!stretch) { - texCoord.x *= (resolution.x/resolution.y); - center.x += (resolution.x/resolution.y)/2.0; - } - - center += vec2(xoff, yoff)*0.01; - - float real_time = (reverse) ? -time : time; - - vec2 p = 2.0 * texCoord - center; - float len = length(p); - vec2 uv = v_texcoord + (p/len)*cos((frequency*0.01)*(len*12.0-real_time*(speed*0.05)))*(intensity*0.0005); - return texture2D(texture, uv); -} \ No newline at end of file diff --git a/effects/shaders/ripple.xml b/effects/shaders/ripple.xml deleted file mode 100644 index 15f4a09cf..000000000 --- a/effects/shaders/ripple.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/sphere.frag b/effects/shaders/sphere.frag deleted file mode 100644 index ff20d28fa..000000000 --- a/effects/shaders/sphere.frag +++ /dev/null @@ -1,40 +0,0 @@ -uniform vec2 resolution; // Screen resolution - -uniform float xoff; -uniform float yoff; -uniform float scale; -uniform bool tile; -uniform bool hide_edges; -uniform bool stretch; - -vec4 process(vec4 col) { - vec2 texCoord = v_texcoord; - - vec2 offset = vec2(1.0); - - if (!stretch) { - if (resolution.x > resolution.y) { - offset.x = (resolution.x/resolution.y); - texCoord.x *= offset.x; - } else { - offset.y = (resolution.y/resolution.x); - texCoord.y *= offset.y; - } - } - - vec2 p = 2.0 * texCoord - offset; - vec2 adj_tc = 2.0 * v_texcoord - 1.0; - float r = dot(p,p); - if (r > 1.0) discard; - float f = (1.0-sqrt(1.0-r))/(r); - vec2 uv; - uv.x = (adj_tc.x*(1.5-scale*0.01))*f+0.5-(xoff*0.01); - uv.y = (adj_tc.y*(1.5-scale*0.01))*f+0.5-(yoff*0.01); - if (tile) { - uv.x = mod(uv.x, 1.0); - uv.y = mod(uv.y, 1.0); - } else if (hide_edges && (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)) { - return vec4(0.0); - } - return vec4(texture2D(texture,uv)); -} diff --git a/effects/shaders/sphere.xml b/effects/shaders/sphere.xml deleted file mode 100644 index 8b469d84a..000000000 --- a/effects/shaders/sphere.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/swirl.frag b/effects/shaders/swirl.frag deleted file mode 100644 index 3463e01a3..000000000 --- a/effects/shaders/swirl.frag +++ /dev/null @@ -1,26 +0,0 @@ -// Swirl effect parameters -uniform float radius; -uniform float angle; -uniform float center_x; -uniform float center_y; -uniform vec2 resolution; - -vec4 process(vec4 col) { - vec2 center = vec2((resolution.x*0.5)+center_x, (resolution.y*0.5)+center_y); - - vec2 uv = v_texcoord.st; - - vec2 tc = uv * resolution; - tc -= center; - float dist = length(tc); - if (dist < radius) { - float percent = (radius - dist) / radius; - float theta = percent * percent * (-angle*0.05) * 8.0; - float s = sin(theta); - float c = cos(theta); - tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c))); - } - tc += center; - - return texture2D(texture, tc / resolution); -} \ No newline at end of file diff --git a/effects/shaders/swirl.xml b/effects/shaders/swirl.xml deleted file mode 100644 index 7acdec918..000000000 --- a/effects/shaders/swirl.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/tile.frag b/effects/shaders/tile.frag deleted file mode 100644 index ac3b6d65d..000000000 --- a/effects/shaders/tile.frag +++ /dev/null @@ -1,25 +0,0 @@ -uniform float scale; -uniform float centerx; -uniform float centery; -uniform bool mirrorx; -uniform bool mirrory; - -vec4 process(vec4 col) { - - float adj_scale = scale*0.01; - - vec2 scaled_coords = (v_texcoord/adj_scale); - vec2 coord = scaled_coords-vec2(0.5/adj_scale, 0.5/adj_scale)+vec2(0.5, 0.5)+vec2(-centerx*0.01, -centery*0.01); - vec2 modcoord = mod(coord, 1.0); - - if (mirrorx && mod(coord.x, 2.0) > 1.0) { - modcoord.x = 1.0 - modcoord.x; - } - - if (mirrory && mod(coord.y, 2.0) > 1.0) { - modcoord.y = 1.0 - modcoord.y; - } - - return vec4(texture2D(texture, modcoord)); - -} \ No newline at end of file diff --git a/effects/shaders/tile.xml b/effects/shaders/tile.xml deleted file mode 100644 index 7bb54ec45..000000000 --- a/effects/shaders/tile.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/vignette.frag b/effects/shaders/vignette.frag deleted file mode 100644 index d73404f2b..000000000 --- a/effects/shaders/vignette.frag +++ /dev/null @@ -1,29 +0,0 @@ -uniform float lensRadiusX; -uniform float lensRadiusY; -uniform float centerX; -uniform float centerY; -uniform bool circular; -uniform vec2 resolution; -uniform bool invert; -// uniform vec2 lensRadius; // 0.45, 0.38 - -vec4 process(vec4 c) { - if (lensRadiusX == 0.0) { - return vec4(0.0); - } - vec2 vignetteCoord = v_texcoord; - if (circular) { - float ar = (resolution.x/resolution.y); - vignetteCoord.x *= ar; - vignetteCoord.x -= (1.0-(1.0/ar)); - } - float dist = distance(vignetteCoord, vec2(0.5 + centerX*0.01, 0.5 + centerY*0.01)); - float size = (lensRadiusX*0.01); - - if (invert) - {c *= 1.0 - smoothstep(size, size*0.99*(1.0-lensRadiusY*0.01), dist);} - else - {c *= smoothstep(size, size*0.99*(1.0-lensRadiusY*0.01), dist);} - - return c; -} diff --git a/effects/shaders/vignette.xml b/effects/shaders/vignette.xml deleted file mode 100644 index d479157ed..000000000 --- a/effects/shaders/vignette.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/shaders/wave.frag b/effects/shaders/wave.frag deleted file mode 100644 index 89f9276ea..000000000 --- a/effects/shaders/wave.frag +++ /dev/null @@ -1,21 +0,0 @@ -uniform float frequency; -uniform float intensity; -uniform float evolution; -uniform bool vertical; - -vec4 process(vec4 col) { - float x = v_texcoord.x; - float y = v_texcoord.y; - - if (vertical) { - x -= sin((v_texcoord.y-(evolution*0.01))*frequency)*intensity*0.01; - } else { - y -= sin((v_texcoord.x-(evolution*0.01))*frequency)*intensity*0.01; - } - - if (y < 0.0 || y > 1.0 || x < 0.0 || x > 1.0) { - return vec4(0.0); - } else { - return texture2D(texture, vec2(x, y)); - } -} \ No newline at end of file diff --git a/effects/shaders/wave.xml b/effects/shaders/wave.xml deleted file mode 100644 index 76be754da..000000000 --- a/effects/shaders/wave.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/effects/transition.cpp b/effects/transition.cpp deleted file mode 100644 index 493463b24..000000000 --- a/effects/transition.cpp +++ /dev/null @@ -1,165 +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 "transition.h" - -#include "ui/mainwindow.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "global/debug.h" -#include "global/clipboard.h" - -#include "effects/internal/crossdissolvetransition.h" -#include "effects/internal/linearfadetransition.h" -#include "effects/internal/exponentialfadetransition.h" -#include "effects/internal/logarithmicfadetransition.h" -#include "effects/internal/cubetransition.h" - -#include "ui/labelslider.h" - -#include "panels/panels.h" -#include "panels/timeline.h" - -#include -#include - -Transition::Transition(Clip *c) : - OldEffectNode(c), - secondary_clip(nullptr) -{ - length_field = new DoubleInput(this, "length", tr("Length"), false, false); - length_field->SetDefault(30); - length_field->SetMinimum(1); - length_field->SetDisplayType(LabelSlider::FrameNumber); - - if (parent_clip != nullptr) { - length_field->SetFrameRate(parent_clip->track()->sequence() == nullptr ? - parent_clip->cached_frame_rate() : parent_clip->track()->sequence()->frame_rate()); - } - - connect(length_field, SIGNAL(Changed()), this, SLOT(UpdateMaximumLength())); -} - -OldEffectNodePtr Transition::copy(Clip *c) { - OldEffectNodePtr node = OldEffectNode::copy(c); - - static_cast(node.get())->set_length(get_true_length()); - - return node; -} - -void Transition::save(QXmlStreamWriter &stream) { - stream.writeAttribute("length", QString::number(get_true_length())); - OldEffectNode::save(stream); -} - -void Transition::set_length(int l) { - length_field->SetValueAt(0, l); -} - -int Transition::get_true_length() { - return length_field->GetValueAt(0).toInt(); -} - -int Transition::get_length() { - if (secondary_clip != nullptr) { - return get_true_length() * 2; - } - return get_true_length(); -} - -Clip* Transition::get_opened_clip() { - if (parent_clip->opening_transition.get() == this) { - return parent_clip; - } else if (secondary_clip != nullptr && secondary_clip->opening_transition.get() == this) { - return secondary_clip; - } - return nullptr; -} - -Clip* Transition::get_closed_clip() { - if (parent_clip->closing_transition.get() == this) { - return parent_clip; - } else if (secondary_clip != nullptr && secondary_clip->closing_transition.get() == this) { - return secondary_clip; - } - return nullptr; -} - -/* -TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s) { - if (!em->filename.isEmpty()) { - // load effect from file - return TransitionPtr(new Transition(c, s, em)); - } else if (em->internal >= 0 && em->internal < TRANSITION_INTERNAL_COUNT) { - // must be an internal effect - switch (em->internal) { - case kCrossDissolveTransition: return TransitionPtr(new CrossDissolveTransition(c, s, em)); - case kLinearFadeTransition: return TransitionPtr(new LinearFadeTransition(c, s, em)); - case kExponentialFadeTransition: return TransitionPtr(new ExponentialFadeTransition(c, s, em)); - case kLogarithmicFadeTransition: return TransitionPtr(new LogarithmicFadeTransition(c, s, em)); - //case TRANSITION_INTERNAL_CUBE: return TransitionPtr(new CubeTransition(c, s, em)); - } - } else { - qCritical() << "Invalid transition data"; - QMessageBox::critical(olive::MainWindow, - QCoreApplication::translate("transition", "Invalid transition"), - QCoreApplication::translate("transition", "No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive.").arg(em->name) - ); - } - return nullptr; -} -*/ - -void Transition::UpdateMaximumLength() -{ - // Get the maximum area this transition can occupy on the clip - long maximum_length = GetMaximumEmptySpaceOnClip(parent_clip); - - // If this clip is a shared transition, get the maximum area this can occupy on the other clip too - if (secondary_clip != nullptr) { - long secondary_max_length = GetMaximumEmptySpaceOnClip(secondary_clip); - - maximum_length = qMin(secondary_max_length, maximum_length); - } - - length_field->SetMaximum(maximum_length); -} - -long Transition::GetMaximumEmptySpaceOnClip(Clip *c) -{ - long maximum_transition_length = c->length(); - - Transition* opposite_transition; - - // See if this clip has a transition on the opposite side that we need to account for - if (c->opening_transition.get() == this) { - opposite_transition = c->closing_transition.get(); - } else { - opposite_transition = c->opening_transition.get(); - } - - // If is does, subtract the maximum length by the transition's length - if (opposite_transition != nullptr) { - maximum_transition_length -= opposite_transition->get_true_length(); - } - - return maximum_transition_length; -} diff --git a/effects/transition.h b/effects/transition.h deleted file mode 100644 index 6ff842e0d..000000000 --- a/effects/transition.h +++ /dev/null @@ -1,63 +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 TRANSITION_H -#define TRANSITION_H - -#include "nodes/oldeffectnode.h" -#include "nodes/inputs.h" - -enum TransitionType { - kTransitionNone, - kTransitionOpening, - kTransitionClosing -}; - -class Transition; -using TransitionPtr = std::shared_ptr; - -class Transition : public OldEffectNode { - Q_OBJECT -public: - Transition(Clip* c); - - virtual OldEffectNodePtr copy(Clip* c) override; - - Clip* secondary_clip; - - virtual void save(QXmlStreamWriter& stream) override; - - void set_length(int l); - int get_true_length(); - int get_length(); - - Clip* get_opened_clip(); - Clip* get_closed_clip(); - - -private: - DoubleInput* length_field; - -private slots: - void UpdateMaximumLength(); - long GetMaximumEmptySpaceOnClip(Clip* c); -}; - -#endif // TRANSITION_H diff --git a/global/clipboard.cpp b/global/clipboard.cpp deleted file mode 100644 index 24fd1346f..000000000 --- a/global/clipboard.cpp +++ /dev/null @@ -1,104 +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 "clipboard.h" - -#include "timeline/clip.h" -#include "nodes/oldeffectnode.h" -#include "effects/transition.h" -#include "undo/undo.h" - -Clipboard::Clipboard() : - type_(CLIPBOARD_TYPE_CLIP) -{ -} - -void Clipboard::Append(VoidPtr obj) -{ - clipboard_.append(obj); -} - -void Clipboard::Insert(int pos, VoidPtr obj) -{ - clipboard_.insert(pos, obj); -} - -void Clipboard::RemoveAt(int pos) -{ - clipboard_.removeAt(pos); -} - -void Clipboard::Clear() -{ - clipboard_.clear(); - clipboard_transitions_.clear(); -} - -int Clipboard::Count() -{ - return clipboard_.size(); -} - -VoidPtr Clipboard::Get(int i) -{ - return clipboard_.at(i); -} - -void Clipboard::SetType(Clipboard::Type type) -{ - if (type == type_) { - return; - } - - Clear(); - type_ = type; -} - -bool Clipboard::IsEmpty() -{ - return clipboard_.isEmpty(); -} - -Clipboard::Type Clipboard::type() -{ - return type_; -} - -bool Clipboard::DeleteClipsWithMedia(ComboAction *ca, Media *m) -{ - if (type_ != CLIPBOARD_TYPE_CLIP) { - return false; - } - - int delete_count = 0; - - for (int i=0;i(clipboard_.at(i)).get(); - - if (c->media() == m) { - ca->append(new RemoveClipsFromClipboard(i-delete_count)); - delete_count++; - } - } - - return (delete_count > 0); -} - -Clipboard olive::clipboard; diff --git a/global/clipboard.h b/global/clipboard.h deleted file mode 100644 index be3190c2d..000000000 --- a/global/clipboard.h +++ /dev/null @@ -1,62 +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 CLIPBOARD_H -#define CLIPBOARD_H - -#include - -#include "effects/transition.h" -#include "project/media.h" - -using VoidPtr = std::shared_ptr; - -class Clipboard { -public: - enum Type { - CLIPBOARD_TYPE_CLIP, - CLIPBOARD_TYPE_EFFECT - }; - - Clipboard(); - void Append(VoidPtr obj); - void Insert(int pos, VoidPtr obj); - void RemoveAt(int pos); - void Clear(); - int Count(); - VoidPtr Get(int i); - void SetType(Type type); - bool IsEmpty(); - Type type(); - - bool DeleteClipsWithMedia(ComboAction* ca, Media* m); - -private: - Type type_; - - QVector clipboard_transitions_; - QVector clipboard_; -}; - -namespace olive { -extern Clipboard clipboard; -} - -#endif // CLIPBOARD_H diff --git a/global/config.cpp b/global/config.cpp deleted file mode 100644 index 82cf4fac9..000000000 --- a/global/config.cpp +++ /dev/null @@ -1,365 +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 "config.h" - -#include -#include -#include - -#include "panels/project.h" -#include "panels/panels.h" - -#include "debug.h" - -Config olive::config; -RuntimeConfig olive::runtime_config; - -Config::Config() - : scroll_zooms(false), - edit_tool_selects_links(false), - edit_tool_also_seeks(false), - select_also_seeks(false), - paste_seeks(true), - img_seq_formats("jpg|jpeg|bmp|tiff|tif|psd|png|tga|jp2|gif"), - rectified_waveforms(false), - default_transition_length(30), - timecode_view(olive::kTimecodeDrop), - show_title_safe_area(false), - use_custom_title_safe_ratio(false), - custom_title_safe_ratio(1), - enable_drag_files_to_timeline(true), - autoscale_by_default(false), - recording_mode(2), - enable_seek_to_import(false), - enable_audio_scrubbing(true), - drop_on_media_to_replace(true), - autoscroll(olive::AUTOSCROLL_PAGE_SCROLL), - audio_rate(48000), - hover_focus(false), - project_view_type(olive::PROJECT_VIEW_TREE), - set_name_with_marker(true), - show_project_toolbar(true), - previous_queue_size(3), - previous_queue_type(olive::FRAME_QUEUE_TYPE_FRAMES), - upcoming_queue_size(0.5), - 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), - waveform_resolution(64), - thumbnail_resolution(120), - add_default_effects_to_clips(true), - invert_timeline_scroll_axes(true), - enable_color_management(false), - style(olive::styling::kOliveDefaultDark), - use_native_menu_styling(true), - default_sequence_width(1920), - default_sequence_height(1080), - default_sequence_framerate(29.97), - default_sequence_audio_frequency(48000), - default_sequence_audio_channel_layout(3), - playback_bit_depth(olive::PIX_FMT_RGBA16F), - export_bit_depth(olive::PIX_FMT_RGBA32F), - dont_use_proxies_on_export(true), - maximum_recent_projects(10), - locked_panels(false) -{} - -void Config::load(QString path) { - QFile f(path); - if (f.exists() && f.open(QIODevice::ReadOnly)) { - QXmlStreamReader stream(&f); - - while (!stream.atEnd()) { - stream.readNext(); - if (stream.isStartElement()) { - if (stream.name() == "ScrollZooms") { - stream.readNext(); - scroll_zooms = (stream.text() == "1"); - } else if (stream.name() == "InvertTimelineScrollAxes") { - stream.readNext(); - invert_timeline_scroll_axes = (stream.text() == "1"); - } else if (stream.name() == "EditToolSelectsLinks") { - stream.readNext(); - edit_tool_selects_links = (stream.text() == "1"); - } else if (stream.name() == "EditToolAlsoSeeks") { - stream.readNext(); - edit_tool_also_seeks = (stream.text() == "1"); - } else if (stream.name() == "SelectAlsoSeeks") { - stream.readNext(); - select_also_seeks = (stream.text() == "1"); - } else if (stream.name() == "PasteSeeks") { - stream.readNext(); - paste_seeks = (stream.text() == "1"); - } else if (stream.name() == "ImageSequenceFormats") { - stream.readNext(); - img_seq_formats = stream.text().toString(); - } else if (stream.name() == "RectifiedWaveforms") { - stream.readNext(); - rectified_waveforms = (stream.text() == "1"); - } else if (stream.name() == "DefaultTransitionLength") { - stream.readNext(); - default_transition_length = stream.text().toInt(); - } else if (stream.name() == "TimecodeView") { - stream.readNext(); - timecode_view = stream.text().toInt(); - } else if (stream.name() == "ShowTitleSafeArea") { - stream.readNext(); - show_title_safe_area = (stream.text() == "1"); - } else if (stream.name() == "UseCustomTitleSafeRatio") { - stream.readNext(); - use_custom_title_safe_ratio = (stream.text() == "1"); - } else if (stream.name() == "CustomTitleSafeRatio") { - stream.readNext(); - custom_title_safe_ratio = stream.text().toDouble(); - } else if (stream.name() == "EnableDragFilesToTimeline") { - stream.readNext(); - enable_drag_files_to_timeline = (stream.text() == "1");; - } else if (stream.name() == "AutoscaleByDefault") { - stream.readNext(); - autoscale_by_default = (stream.text() == "1"); - } else if (stream.name() == "RecordingMode") { - stream.readNext(); - recording_mode = stream.text().toInt(); - } else if (stream.name() == "EnableSeekToImport") { - stream.readNext(); - enable_seek_to_import = (stream.text() == "1"); - } else if (stream.name() == "AudioScrubbing") { - stream.readNext(); - enable_audio_scrubbing = (stream.text() == "1"); - } else if (stream.name() == "DropFileOnMediaToReplace") { - stream.readNext(); - drop_on_media_to_replace = (stream.text() == "1"); - } else if (stream.name() == "Autoscroll") { - stream.readNext(); - autoscroll = stream.text().toInt(); - } else if (stream.name() == "AudioRate") { - stream.readNext(); - audio_rate = stream.text().toInt(); - } 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(); - } else if (stream.name() == "SetNameWithMarker") { - stream.readNext(); - set_name_with_marker = (stream.text() == "1"); - } else if (stream.name() == "ShowProjectToolbar") { - stream.readNext(); - show_project_toolbar = (stream.text() == "1"); - } else if (stream.name() == "PreviousFrameQueueSize") { - stream.readNext(); - previous_queue_size = stream.text().toDouble(); - } else if (stream.name() == "PreviousFrameQueueType") { - stream.readNext(); - previous_queue_type = stream.text().toInt(); - } else if (stream.name() == "UpcomingFrameQueueSize") { - stream.readNext(); - upcoming_queue_size = stream.text().toDouble(); - } else if (stream.name() == "UpcomingFrameQueueType") { - stream.readNext(); - upcoming_queue_type = stream.text().toInt(); - } else if (stream.name() == "Loop") { - stream.readNext(); - loop = (stream.text() == "1"); - } 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(); - } else if (stream.name() == "EffectTextboxLines") { - stream.readNext(); - effect_textbox_lines = stream.text().toInt(); - } else if (stream.name() == "UseSoftwareFallback") { - stream.readNext(); - use_software_fallback = (stream.text() == "1"); - } else if (stream.name() == "CenterTimelineTimecodes") { - stream.readNext(); - center_timeline_timecodes = (stream.text() == "1"); - } else if (stream.name() == "PreferredAudioOutput") { - stream.readNext(); - preferred_audio_output = stream.text().toString(); - } else if (stream.name() == "PreferredAudioInput") { - stream.readNext(); - preferred_audio_input = stream.text().toString(); - } else if (stream.name() == "LanguageFile") { - stream.readNext(); - language_file = stream.text().toString(); - } else if (stream.name() == "ThumbnailResolution") { - stream.readNext(); - thumbnail_resolution = stream.text().toInt(); - } else if (stream.name() == "WaveformResolution") { - stream.readNext(); - waveform_resolution = stream.text().toInt(); - } else if (stream.name() == "AddDefaultEffectsToClips") { - stream.readNext(); - add_default_effects_to_clips = (stream.text() == "1"); - } else if (stream.name() == "EnableColorManagement") { - stream.readNext(); - enable_color_management = (stream.text() == "1"); - } else if (stream.name() == "OCIOConfigPath") { - stream.readNext(); - ocio_config_path = stream.text().toString(); - } else if (stream.name() == "OCIODisplay") { - stream.readNext(); - ocio_display = stream.text().toString(); - } else if (stream.name() == "OCIOView") { - stream.readNext(); - ocio_view = stream.text().toString(); - } else if (stream.name() == "OCIOLook") { - stream.readNext(); - ocio_look = stream.text().toString(); - } else if (stream.name() == "OCIODefaultInput") { - stream.readNext(); - ocio_default_input_colorspace = stream.text().toString(); - } else if (stream.name() == "Style") { - stream.readNext(); - style = static_cast(stream.text().toInt()); - } 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(); - } else if (stream.name() == "PlaybackBitDepth") { - stream.readNext(); - playback_bit_depth = static_cast(stream.text().toInt()); - } else if (stream.name() == "ExportBitDepth") { - stream.readNext(); - export_bit_depth = static_cast(stream.text().toInt()); - } else if (stream.name() == "DontUseProxiesOnExport") { - stream.readNext(); - dont_use_proxies_on_export = (stream.text() == "1"); - } else if (stream.name() == "LockedPanels") { - stream.readNext(); - locked_panels = (stream.text() == "1"); - } - } - } - if (stream.hasError()) { - qCritical() << "Error parsing config XML." << stream.errorString(); - } - - f.close(); - } -} - -void Config::save(QString path) { - QFile f(path); - if (!f.open(QIODevice::WriteOnly)) { - qCritical() << "Could not save configuration"; - return; - } - - QXmlStreamWriter stream(&f); - stream.setAutoFormatting(true); - stream.writeStartDocument(); // doc - stream.writeStartElement("Configuration"); // configuration - - stream.writeTextElement("Version", QString::number(olive::kSaveVersion)); - stream.writeTextElement("ScrollZooms", QString::number(scroll_zooms)); - stream.writeTextElement("InvertTimelineScrollAxes", QString::number(invert_timeline_scroll_axes)); - stream.writeTextElement("EditToolSelectsLinks", QString::number(edit_tool_selects_links)); - stream.writeTextElement("EditToolAlsoSeeks", QString::number(edit_tool_also_seeks)); - stream.writeTextElement("SelectAlsoSeeks", QString::number(select_also_seeks)); - stream.writeTextElement("PasteSeeks", QString::number(paste_seeks)); - stream.writeTextElement("ImageSequenceFormats", img_seq_formats); - stream.writeTextElement("RectifiedWaveforms", QString::number(rectified_waveforms)); - stream.writeTextElement("DefaultTransitionLength", QString::number(default_transition_length)); - stream.writeTextElement("TimecodeView", QString::number(timecode_view)); - stream.writeTextElement("ShowTitleSafeArea", QString::number(show_title_safe_area)); - stream.writeTextElement("UseCustomTitleSafeRatio", QString::number(use_custom_title_safe_ratio)); - stream.writeTextElement("CustomTitleSafeRatio", QString::number(custom_title_safe_ratio)); - stream.writeTextElement("EnableDragFilesToTimeline", QString::number(enable_drag_files_to_timeline)); - stream.writeTextElement("AutoscaleByDefault", QString::number(autoscale_by_default)); - stream.writeTextElement("RecordingMode", QString::number(recording_mode)); - stream.writeTextElement("EnableSeekToImport", QString::number(enable_seek_to_import)); - stream.writeTextElement("AudioScrubbing", QString::number(enable_audio_scrubbing)); - 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("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.first()->IsToolbarVisible())); - stream.writeTextElement("PreviousFrameQueueSize", QString::number(previous_queue_size)); - stream.writeTextElement("PreviousFrameQueueType", QString::number(previous_queue_type)); - stream.writeTextElement("UpcomingFrameQueueSize", QString::number(upcoming_queue_size)); - 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)); - stream.writeTextElement("CenterTimelineTimecodes", QString::number(center_timeline_timecodes)); - stream.writeTextElement("PreferredAudioOutput", preferred_audio_output); - stream.writeTextElement("PreferredAudioInput", preferred_audio_input); - stream.writeTextElement("LanguageFile", language_file); - stream.writeTextElement("ThumbnailResolution", QString::number(thumbnail_resolution)); - stream.writeTextElement("WaveformResolution", QString::number(waveform_resolution)); - stream.writeTextElement("AddDefaultEffectsToClips", QString::number(add_default_effects_to_clips)); - stream.writeTextElement("EnableColorManagement", QString::number(enable_color_management)); - stream.writeTextElement("OCIOConfigPath", ocio_config_path); - stream.writeTextElement("OCIODisplay", ocio_display); - stream.writeTextElement("OCIOView", ocio_view); - stream.writeTextElement("OCIOLook", ocio_look); - stream.writeTextElement("OCIODefaultInput", ocio_default_input_colorspace); - stream.writeTextElement("Style", QString::number(style)); - stream.writeTextElement("NativeMenuStyling", QString::number(use_native_menu_styling)); - stream.writeTextElement("DefaultSequenceWidth", QString::number(default_sequence_width)); - 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.writeTextElement("PlaybackBitDepth", QString::number(playback_bit_depth)); - stream.writeTextElement("ExportBitDepth", QString::number(export_bit_depth)); - stream.writeTextElement("DontUseProxiesOnExport", QString::number(dont_use_proxies_on_export)); - stream.writeTextElement("LockedPanels", QString::number(locked_panels)); - - stream.writeEndElement(); // configuration - stream.writeEndDocument(); // doc - f.close(); -} - -RuntimeConfig::RuntimeConfig() : - shaders_are_enabled(true) -{} diff --git a/global/config.h b/global/config.h deleted file mode 100644 index 8b9e31c13..000000000 --- a/global/config.h +++ /dev/null @@ -1,681 +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 CONFIG_H -#define CONFIG_H - -#include - -#include "ui/styling.h" -#include "timeline/timelinetools.h" -#include "rendering/pixelformats.h" - -namespace olive { - /** - * @brief Version identifier for saved projects - * - * This constant is used to identify what version of Olive a project file was saved with. Every project file - * is saved with the current version number and the version is checked whenever an Olive project is loaded to - * determine how compatible it'll be with the current version. - * - * Sometimes this version identifier is used to invoke backwards compatibility in order to keep older project files - * able to load, but in this early rapidly developing stage, often backwards compatibility is abandoned. Ideally - * in the future, a class should be made that's able to "convert" an older project into one that the current - * loading system understands (so that the loading system doesn't get too bloated with backwards compatibility - * functions). - */ - const int kSaveVersion = 190219; // YYMMDD - - /** - * @brief Minimum project version that this version of Olive can open - * - * When loading a project, the project's version number is actually checked whether it is somewhere between - * kSaveVersion and this value (inclusive). This is used if the current version of Olive contains backwards - * compatibility functionality for older project versions, and is bumped up if such backwards compatibility is - * ever removed. - * - * As stated in kSaveVersion documentation, ideally in the future, a system would be in place to account for all - * project version differences and bring them up to date for the current loading algorithm. This means ideally, this - * constant stays the same forever, but in this early stage it's not strictly necessary. - */ - const int kMinimumSaveVersion = 190219; // lowest compatible project version - - /** - * @brief The TimecodeType enum - * - * Frame numbers can be displayed in various different ways. The timecode_to_frame() and frame_to_timecode() - * functions (which should be used for all frame <-> timecode conversions) respond to the timecode display type - * set in Config::timecode_view corresponding to a value from this enum. - */ - enum TimecodeType { - /** Show frame number as a drop-frame timecode */ - kTimecodeDrop, - - /** Show frame number as a non-drop-frame timecode */ - kTimecodeNonDrop, - - /** Show frame number as-is with no modifications */ - kTimecodeFrames, - - /** Show frame number as milliseconds */ - kTimecodeMilliseconds - }; - - /** - * @brief The RecordingMode enum - * - * Olive currently supports recording mono or stereo and gives users the option of which mode to use when - * recording audio in-app. Audio recording responds to Config::recording_mode to a value from this enum. - */ - enum RecordingMode { - /** Record all audio in mono */ - RECORD_MODE_MONO, - - /** Record all audio in stereo */ - RECORD_MODE_STEREO - }; - - /** - * @brief The AutoScrollMode enum - * - * The Timeline in Olive can automatically scroll to follow the playhead when the sequence is playing. - * The Timeline will respond to Config::autoscroll set to a value from this enum. - */ - enum AutoScrollMode { - /** Don't auto-scroll, scrolling will not follow the playhead */ - AUTOSCROLL_NO_SCROLL, - - /** Page auto-scroll (default), if the playhead goes off-screen while playing, the scroll will jump ahead - * one "page" to follow it */ - AUTOSCROLL_PAGE_SCROLL, - - /** Smooth auto-scroll, Olive will scroll to keep the playhead in the center of the screen at all times while - * playing */ - AUTOSCROLL_SMOOTH_SCROLL - }; - - /** - * @brief The ProjectView enum - * - * The media in the Project panel can be displayed as a tree hierarchy or as an icon view. The Project panel - * responds to Config::project_view_type set to a value from this enum. - */ - enum ProjectView { - /** Display project media in tree hierarchy */ - PROJECT_VIEW_TREE, - - /** Display project media in icon browser */ - PROJECT_VIEW_ICON, - - /** Display project media in list browser */ - PROJECT_VIEW_LIST - }; - - /** - * @brief The FrameQueueType enum - * - * Olive keeps a "frame queue" in memory to allow smoother playback/seeking. In order to give users control over - * the amount of memory consumption vs. playback performance, they can control how many frames are cached into - * memory. For extra fidelity, they can choose this value as a metric of either frames or seconds. - * - * The playback engine (playback/playback.h) responds to both Config::previous_queue_type and - * Config::upcoming_queue_type set to a value from this enum. - */ - enum FrameQueueType { - /** Queue size value is in frames */ - FRAME_QUEUE_TYPE_FRAMES, - - /** Queue size value is in seconds */ - FRAME_QUEUE_TYPE_SECONDS - }; -} - -/** - * @brief The Config struct - * - * This struct handles any configuration that should persist between restarting Olive. It contains several variables - * as well as functions that load and save all the variables to file. - */ -struct Config { - /** - * @brief Config Constructor - * - * Sets all configuration variables to their defaults. - */ - Config(); - - /** - * @brief The scroll wheel zooms rather than scrolls - * - * **TRUE** if the scroll wheel should zoom in and out rather than scroll up and down. - * The Control key temporarily toggles this setting. - */ - bool scroll_zooms; - - /** - * @brief Edit tool selects links - * - * **TRUE** if the edit tool should also select links when the user selects a clip. - */ - bool edit_tool_selects_links; - - /** - * @brief Edit tool also seeks - * - * **TRUE** if using the edit tool should also seek the sequence's playhead - */ - bool edit_tool_also_seeks; - - /** - * @brief Selecting also seeks - * - * **TRUE** if the playhead should automatically seek to the start of any clip that gets selected - */ - bool select_also_seeks; - - /** - * @brief Paste also seeks - * - * **TRUE** if the playhead should seek to the end of clips that are pasted - */ - bool paste_seeks; - - /** - * @brief Image sequence formats - * - * A '|' separated list of file extensions that Olive will perform an image sequence test heuristic on when importing - */ - QString img_seq_formats; - - /** - * @brief Use rectified waveforms - * - * **TRUE** if Olive should display waveforms as "rectified". Rectified waveforms start at the bottom rather than - * from the middle. - */ - bool rectified_waveforms; - - /** - * @brief Default transition length - * - * The default transition length used when making a transition without the transition tool - */ - int default_transition_length; - - /** - * @brief Timecode display mode - * - * The display mode with which timecode_to_frame() and frame_to_timecode() will use to convert frame numbers to - * more human-readable values. - * - * Set to a member of enum TimecodeType. - */ - int timecode_view; - - /** - * @brief Show title/action safe area - * - * **TRUE** if the title/action safe area should be shown on the Viewer. - */ - bool show_title_safe_area; - - /** - * @brief Use custom title/action safe area aspect ratio - * - * **TRUE** if the title/action save area should use a custom aspect ratio - */ - bool use_custom_title_safe_ratio; - - /** - * @brief Custom title/action safe area aspect ratio - * - * If Config::use_custom_title_safe_ratio is true, this is the aspect ratio to use. - * - * Set to the result of an aspect ratio division (i.e. for 4:3 set to 1.333333 (4.0 / 3.0) - */ - double custom_title_safe_ratio; - - /** - * @brief Enable dragging files outside Olive directly into the Timeline - * - * **TRUE** if the Timeline should respond to files dropped from outside Olive. - */ - bool enable_drag_files_to_timeline; - - /** - * @brief Auto-scale by default - * - * **TRUE** if clips imported into the timeline should have Clip::autoscale **TRUE** by default. If a Clip is - * smaller or larger than the Sequence, auto-scale will automatically resize it to fit to the Sequence boundaries. - */ - bool autoscale_by_default; - - /** - * @brief Recording mode/channel layout - * - * When recording audio within Olive, use this mode/channel layout (e.g. mono or stereo). - * - * Set to a member of enum RecordingMode. - */ - int recording_mode; - - /** - * @brief Enable seek to import - * - * **TRUE** if the playhead should automatically seek to any newly imported clips - */ - bool enable_seek_to_import; - - /** - * @brief Enable audio scrubbing - * - * **TRUE** if audio should "scrub" as the user drags the playhead around - */ - bool enable_audio_scrubbing; - - /** - * @brief Enable drop on media to replace - * - * **TRUE** if dropping a file from outside Olive onto a media item in the Project panel should prompt the user - * whether the dropped file should replace the media item that the file was dropped on. - */ - bool drop_on_media_to_replace; - - /** - * @brief Auto-scroll mode - * - * The Timeline behavior regarding scrolling to keep the playhead within view while a Sequence is playing. - * - * Set to a member of enum AutoScrollMode. - */ - int autoscroll; - - /** - * @brief Current audio sample rate - * - * The sample rate to set the audio output device to. Also used as the value to resample audio to during playback - * (but not during rendering). - */ - int audio_rate; - - /** - * @brief Enable hover focus - * - * Default behavior is panels are focused (and therefore respond to certain keyboard shortcuts)when they are clicked - * on, but Olive also supports panels being considered "focused" if the mouse is hovered over them. - * - * **TRUE** to enable hover focus mode. - */ - bool hover_focus; - - /** - * @brief Project view type - * - * Whether to show media in the Project panel as a tree hierarchy or as a browser of icons. - * - * Set to a member of enum ProjectView. - */ - int project_view_type; - - /** - * @brief Ask for a marker name when setting a marker - * - * **TRUE** if Olive should ask the user to name a marker when setting one. **FALSE** if markers should just be - * created without asking. - */ - bool set_name_with_marker; - - /** - * @brief Show the project toolbar - * - * Olive has an optional toolbar for the Project panel. - * - * Set to **TRUE** to show it. - */ - bool show_project_toolbar; - - /** - * @brief Previous frame queue size - * - * Olive caches frames in memory to improve playback performance (see enum FrameQueueType documentation for more - * details). This variable states how many frames to keep in memory prior to the playhead (in most cases, frames that - * have already been played, but are kept in memory in case the user wants to backtrack at any time). - * - * This value corresponds to Config::previous_queue_type. - */ - double previous_queue_size; - - /** - * @brief Previous frame queue type - * - * The metric of which Config::previous_queue_size is using. For example, if Config::previous_queue_size is - * 3, this variable states whether that is 3 frames or 3 seconds. - * - * Set to a member of enum FrameQueueType. - */ - int previous_queue_type; - - /** - * @brief Upcoming frame queue size - * - * Olive caches frames in memory to improve playback performance (see enum FrameQueueType documentation for more - * details). This variable states how many upcoming frames are stored in memory. Generally this value will be higher - * than Config::previous_queue_size since the user will be playing forwards most of the time. - * - * This value corresponds to Config::upcoming_queue_type. - */ - double upcoming_queue_size; - - /** - * @brief Upcoming frame queue type - * - * The metric of which Config::upcoming_queue_size is using. For example, if Config::upcoming_queue_size is - * 3, this variable states whether that is 3 frames or 3 seconds. - * - * Set to a member of enum FrameQueueType. - */ - int upcoming_queue_type; - - /** - * @brief Loop - * - * If an in/out point are set on the Sequence (Sequence::using_workarea is **TRUE**), set this to **TRUE** if Olive - * should rewind to the in point and start playing again after it reaches the out point repeatedly until the user - * pauses. - */ - bool loop; - - /** - * @brief Seeking also selects - * - * Olive supports automatically selecting clips that the playhead is currently touching for a more efficient workflow. - * - * **TRUE** if this mode should be enabled. - */ - 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 - * - * The URL to a CSS file if the user has loaded a custom stylesheet in. **EMPTY** if the user has not set a - * stylesheet. - */ - QString css_path; - - /** - * @brief Number of lines that an Effect's textbox has - * - * The height of a Effect's textbox field in terms of lines. - * - * Set to a value >= 1 - */ - int effect_textbox_lines; - - /** - * @brief Use software fallbacks when possible - * - * Olive uses a lot of OpenGL-based hardware acceleration for performance. Some older hardware has difficulty - * supporting this functionality, so some of it has software-based (not hardware accelerated) fallbacks for these - * users. - * - * **TRUE** if Olive should prefer software fallbacks to hardware acceleration when they're available. - */ - bool use_software_fallback; - - /** - * @brief Center Timeline timecodes - * - * By default, Olive shows timecodes in the TimelineHeader centered to the corresponding frame point. This may not - * always be desirable as, for example, this forces the initial 00:00:00;00 timecode's left half to be cut off. - * Olive supports aligning the timecode to the right of the frame rather than the center to address this. - */ - bool center_timeline_timecodes; - - /** - * @brief Preferred audio output device - * - * Sets the audio device Olive should use to output audio to. - * - * Set to the name of the audio device or **EMPTY** to try using the default. - */ - QString preferred_audio_output; - - /** - * @brief Preferred audio input device - * - * Sets the audio device Olive should use to input audio from. - * - * Set to the name of the audio device or **EMPTY** to try using the default. - */ - QString preferred_audio_input; - - /** - * @brief Language/translation file - * - * Sets the translation file to load to display Olive in a different language. - * - * Set to the URL of the language file to load, or **EMPTY** to use default en-US language. - */ - QString language_file; - - /** - * @brief Waveform resolution - * - * Sets how detailed the waveforms should be in the Timeline. Higher value = more detail. - * - * Specifically sets how many samples per second should be "cached" for preview. If the waveforms are too blocky, - * set this higher. If Timeline performance is slow, set this lower. - */ - int waveform_resolution; - - /** - * @brief Thumbnail resolution - * - * The vertical pixel height to use for generating thumbnails. - */ - int thumbnail_resolution; - - /** - * @brief Add default effects to clips - * - * **TRUE** if new clips imported into the Timeline should have a set of default effects (TransformEffect, - * VolumeEffect, and PanEffect) added to them by default. - */ - bool add_default_effects_to_clips; - - /** - * @brief Invert Timeline scroll axes - * - * **TRUE** if scrolling vertically on the Timeline should scroll it horizontally - */ - bool invert_timeline_scroll_axes; - - /** - * @brief Enable color managemennt - * - * **TRUE** if color management through OpenColorIO should be enabled - */ - bool enable_color_management; - - /** - * @brief Path to OpenColorIO configuration file - * - * Used if Config::enable_color_management is true. - */ - QString ocio_config_path; - - /** - * @brief OpenColorIO Display - * - * Used if Config::enable_color_management is true - */ - QString ocio_display; - - /** - * @brief OpenColorIO View - * - * Used if Config::enable_color_management is true - */ - QString ocio_view; - - /** - * @brief OpenColorIO Look - * - * Used if Config::enable_color_management is true - */ - QString ocio_look; - - /** - * @brief OpenColorIO Default Input Colorspace - * - * The colorspace to default to if no colorspace can be determined from the filename or a manual setting. - */ - QString ocio_default_input_colorspace; - - /** - * @brief Style to use when theming Olive. - * - * Set to a member of olive::styling::Style. - */ - olive::styling::Style style; - - /** - * @brief Use native menu styling - * - * Use native styling on menus rather than cross-platform Fusion. - */ - 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 Playback bit depth (an index of olive::rendering::bit_depths) - */ - olive::PixelFormat playback_bit_depth; - - /** - * @brief Export bit depth (an index of olive::rendering::bit_depths) - */ - olive::PixelFormat export_bit_depth; - - /** - * @brief Don't use proxies on export (use originals instead) - */ - bool dont_use_proxies_on_export; - - /** - * @brief The maximum amount of recent projects stored in the Open Recent list - */ - int maximum_recent_projects; - - /** - * @brief Sets whether panels should load locked or not - */ - bool locked_panels; - - /** - * @brief Load config from file - * - * Load configuration parameters from file - * - * @param path - * - * URL to the configuration file to load - */ - void load(QString path); - - /** - * @brief Save config to file - * - * Save current configuration parameters to file - * - * @param path - * - * URL to save the configuration file to. - */ - void save(QString path); -}; - -/** - * @brief The RuntimeConfig struct - * - * This struct handles any configuration that's set as a command-line argument to Olive, and shouldn't be persistent - * between restarts of Olive. - */ -struct RuntimeConfig { - /** - * @brief RuntimeConfig Constructor - * - * Sets default runtime configuration - */ - RuntimeConfig(); - - /** - * @brief Enable shaders - * - * Debugging tool. Set to **FALSE** to bypass OpenGL shaders. - */ - bool shaders_are_enabled; - - /** - * @brief Load an external translation file - * - * Overrides Config::language_file and sets the path to a language file to use. - */ - QString external_translation_file; - -}; - -namespace olive { -extern Config config; -extern RuntimeConfig runtime_config; -} - -#endif // CONFIG_H diff --git a/global/crashhandler.cpp b/global/crashhandler.cpp deleted file mode 100644 index 41d1a7061..000000000 --- a/global/crashhandler.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "crashhandler.h" - -#include -#include - -#include "dialogs/crashdialog.h" - -#ifdef __GNUC__ -#ifdef Q_OS_WIN -#include -#include -#elif defined(Q_OS_LINUX) -#include -#endif -#include -#endif - -#ifdef __GNUC__ -void handler(int sig) { - QStringList strings; - -#ifdef Q_OS_WIN - HANDLE process = GetCurrentProcess(); - HANDLE thread = GetCurrentThread(); - - CONTEXT context; - memset(&context, 0, sizeof(CONTEXT)); - context.ContextFlags = CONTEXT_FULL; - RtlCaptureContext(&context); - - SymInitialize(process, NULL, TRUE); - - DWORD image; - STACKFRAME64 stackframe; - ZeroMemory(&stackframe, sizeof(STACKFRAME64)); - -#ifdef _M_IX86 - image = IMAGE_FILE_MACHINE_I386; - stackframe.AddrPC.Offset = context.Eip; - stackframe.AddrPC.Mode = AddrModeFlat; - stackframe.AddrFrame.Offset = context.Ebp; - stackframe.AddrFrame.Mode = AddrModeFlat; - stackframe.AddrStack.Offset = context.Esp; - stackframe.AddrStack.Mode = AddrModeFlat; -#elif _M_X64 - image = IMAGE_FILE_MACHINE_AMD64; - stackframe.AddrPC.Offset = context.Rip; - stackframe.AddrPC.Mode = AddrModeFlat; - stackframe.AddrFrame.Offset = context.Rsp; - stackframe.AddrFrame.Mode = AddrModeFlat; - stackframe.AddrStack.Offset = context.Rsp; - stackframe.AddrStack.Mode = AddrModeFlat; -#elif _M_IA64 - image = IMAGE_FILE_MACHINE_IA64; - stackframe.AddrPC.Offset = context.StIIP; - stackframe.AddrPC.Mode = AddrModeFlat; - stackframe.AddrFrame.Offset = context.IntSp; - stackframe.AddrFrame.Mode = AddrModeFlat; - stackframe.AddrBStore.Offset = context.RsBSP; - stackframe.AddrBStore.Mode = AddrModeFlat; - stackframe.AddrStack.Offset = context.IntSp; - stackframe.AddrStack.Mode = AddrModeFlat; -#endif - - int counter = 0; - QString line_template = "[%1] %2"; - while (StackWalk64( - image, process, thread, - &stackframe, &context, NULL, - SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { - - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = MAX_SYM_NAME; - - DWORD64 displacement = 0; - - - QString sym_name; - if (SymFromAddr(process, stackframe.AddrPC.Offset, &displacement, symbol)) { - sym_name = symbol->Name; - } else { - sym_name = "???"; - } - QString s = line_template.arg(QString::number(counter), sym_name); - strings.append(s); - std::cout << s.data() << std::endl << std::flush; - - counter++; - } - - SymCleanup(process); -#elif defined(Q_OS_LINUX) - void *array[10]; - size_t size; - - // get void*'s for all entries on the stack - size = backtrace(array, 10); - - // print out all the frames to stderr - fprintf(stderr, "Signal: %d\n\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); - - // try to show a GUI crash report - char** bt_syms = backtrace_symbols(array, size); - for (int i=0;iSetData(sig, strings); - olive::crash_dialog->exec(); - - abort(); -} -#endif diff --git a/global/crashhandler.h b/global/crashhandler.h deleted file mode 100644 index 4dab03089..000000000 --- a/global/crashhandler.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef CRASHHANDLER_H -#define CRASHHANDLER_H - -#ifdef __GNUC__ -#include -void handler(int sig); -#endif - -#endif // CRASHHANDLER_H diff --git a/global/crossplatformlib.cpp b/global/crossplatformlib.cpp deleted file mode 100644 index b6f7a2655..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 068f49604..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/global/debug.cpp b/global/debug.cpp deleted file mode 100644 index f5a3b4ac0..000000000 --- a/global/debug.cpp +++ /dev/null @@ -1,112 +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 "debug.h" - -#include -#include -#include -#include -#include - -#include "dialogs/debugdialog.h" - -QString debug_info; -QMutex debug_mutex; -QFile debug_file; -QTextStream debug_stream; - -void open_debug_file() { - QDir debug_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - debug_dir.mkpath("."); - if (debug_dir.exists()) { - debug_file.setFileName(debug_dir.path() + "/debug_log"); - if (debug_file.open(QFile::WriteOnly)) { - debug_stream.setDevice(&debug_file); - } else { - qWarning() << "Couldn't open debug log file, debug log will not be saved"; - } - } -} - -void close_debug_file() -{ - if (debug_file.isOpen()) { - debug_file.close(); - } -} - -void debug_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - debug_mutex.lock(); - const QByteArray localMsg = msg.toLocal8Bit(); - const QDateTime now = QDateTime::currentDateTime(); - const QByteArray timeRepr(now.toString(Qt::ISODate).toLocal8Bit()); - QString msgTag; - QString fontColor; - switch (type) { - case QtDebugMsg: - msgTag = "DEBUG"; - fontColor = "grey"; - break; - case QtInfoMsg: - msgTag = "INFO"; - fontColor = "blue"; - break; - case QtWarningMsg: - msgTag = "WARNING"; - fontColor = "yellow"; - break; - case QtCriticalMsg: - msgTag = "ERROR"; - fontColor = "red"; - break; - case QtFatalMsg: - msgTag = "FATAL"; - fontColor = "red"; - break; - default: - fprintf(stderr, "Unknown debug msg type"); - fflush(stderr); - break; - }//switch - - /*fprintf(stderr, "%s [%s] %s (%s:%u, %s)\n", timeRepr.data(), msgTag.toLocal8Bit().constData(), localMsg.data(), - context.file, context.line, context.function);*/ - - fprintf(stderr, "%s [%s] %s\n", timeRepr.data(), msgTag.toLocal8Bit().constData(), localMsg.data()); - - if (debug_file.isOpen()) { - debug_stream << QString("[%1] %2 (%3:%4, %5)\n") - .arg(msgTag, localMsg, context.file, QString::number(context.line), context.function); - } - debug_info.append(QString("[%2] %3 (%4:%5, %6)
") - .arg(fontColor, msgTag, localMsg, context.file, QString::number(context.line), context.function)); - fflush(stderr); - if (olive::DebugDialog != nullptr && olive::DebugDialog->isVisible()) { - QMetaObject::invokeMethod(olive::DebugDialog, "update_log", Qt::QueuedConnection); - } - debug_mutex.unlock(); -} - -const QString &get_debug_str() -{ - return debug_info; -} diff --git a/global/debug.h b/global/debug.h deleted file mode 100644 index 0d686794a..000000000 --- a/global/debug.h +++ /dev/null @@ -1,31 +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 DEBUG_H -#define DEBUG_H - -#include - -void debug_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg); -const QString& get_debug_str(); -void open_debug_file(); -void close_debug_file(); - -#endif // DEBUG_H diff --git a/global/global.cpp b/global/global.cpp deleted file mode 100644 index 03c2a8b9a..000000000 --- a/global/global.cpp +++ /dev/null @@ -1,831 +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 "global/global.h" - -#include -#include -#include -#include -#include -#include - -#include "panels/panels.h" -#include "global/path.h" -#include "global/config.h" -#include "global/timing.h" -#include "global/clipboard.h" -#include "rendering/audio.h" -#include "dialogs/demonotice.h" -#include "dialogs/preferencesdialog.h" -#include "dialogs/exportdialog.h" -#include "dialogs/debugdialog.h" -#include "dialogs/aboutdialog.h" -#include "dialogs/speeddialog.h" -#include "dialogs/actionsearch.h" -#include "dialogs/newsequencedialog.h" -#include "dialogs/loaddialog.h" -#include "dialogs/autocutsilencedialog.h" -#include "effects/effectloaders.h" -#include "project/loadthread.h" -#include "project/savethread.h" -#include "timeline/sequence.h" -#include "ui/mediaiconservice.h" -#include "ui/mainwindow.h" -#include "ui/menu.h" -#include "ui/updatenotification.h" -#include "undo/undostack.h" - -std::unique_ptr olive::Global; -QString olive::ActiveProjectFilename; -QString olive::AppName; - -OliveGlobal::OliveGlobal() : - changed_since_last_autorecovery(false), - rendering_(false) -{ - // sets current app name - QString version_id; - - // if available, append the current Git hash (defined by `qmake` and the Makefile) -#ifdef GITHASH - version_id = QString(" | %1").arg(GITHASH); -#endif - - olive::AppName = QString("Olive (May 2019 | Alpha%1)").arg(version_id); - - // set the file filter used in all file dialogs pertaining to Olive project files. - project_file_filter = tr("Olive Project %1").arg("(*.ove)"); - - // set default value - enable_load_project_on_init = false; - - // alloc QTranslator - translator = std::unique_ptr(new QTranslator()); -} - -const QString &OliveGlobal::get_project_file_filter() { - return project_file_filter; -} - -void OliveGlobal::update_project_filename(const QString &s) { - // set filename to s - olive::ActiveProjectFilename = s; - - // update main window title to reflect new project filename - olive::MainWindow->updateTitle(); -} - -void OliveGlobal::check_for_autorecovery_file() { - QString data_dir = get_data_path(); - if (!data_dir.isEmpty()) { - // 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) { - enable_load_project_on_init = false; - OpenProjectWorker(autorecovery_filename, true); - } - } - autorecovery_timer.setInterval(60000); - QObject::connect(&autorecovery_timer, SIGNAL(timeout()), this, SLOT(save_autorecovery_file())); - autorecovery_timer.start(); - } -} - -bool OliveGlobal::is_exporting() -{ - return rendering_; -} - -const olive::PixelFormat &OliveGlobal::effective_bit_depth() -{ - // FIXME uncomment this -// return olive::Global->is_exporting() ? olive::config.export_bit_depth : olive::config.playback_bit_depth; - return olive::config.export_bit_depth; -} - -void OliveGlobal::set_export_state(bool rendering) { - rendering_ = rendering; - if (rendering) { - autorecovery_timer.stop(); - } else { - autorecovery_timer.start(); - } -} - -void OliveGlobal::set_modified(bool modified) -{ - olive::MainWindow->setWindowModified(modified); - changed_since_last_autorecovery = modified; -} - -bool OliveGlobal::is_modified() -{ - return olive::MainWindow->isWindowModified(); -} - -void OliveGlobal::load_project_on_launch(const QString& s) { - olive::ActiveProjectFilename = s; - enable_load_project_on_init = true; -} - -QString OliveGlobal::get_recent_project_list_file() { - return get_data_dir().filePath("recents"); -} - -void OliveGlobal::load_translation_from_config() { - QString language_file = olive::runtime_config.external_translation_file.isEmpty() ? - olive::config.language_file : - olive::runtime_config.external_translation_file; - - // clear runtime language file so if the user sets a different language, we won't load it next time - olive::runtime_config.external_translation_file.clear(); - - // remove current translation if there is one - QApplication::removeTranslator(translator.get()); - - if (!language_file.isEmpty()) { - - // translation files are stored relative to app path (see GitHub issue #454) - QString full_language_path = QDir(get_app_path()).filePath(language_file); - - // load translation file - if (QFileInfo::exists(full_language_path) - && translator->load(full_language_path)) { - QApplication::installTranslator(translator.get()); - } else { - qWarning() << "Failed to load translation file" << full_language_path << ". No language will be loaded."; - } - } -} - -void OliveGlobal::SetNativeStyling(QWidget *w) -{ -#ifdef Q_OS_WIN - w->setStyleSheet(""); - w->setPalette(w->style()->standardPalette()); - w->setStyle(QStyleFactory::create("windowsvista")); -#else - Q_UNUSED(w) -#endif -} - -void OliveGlobal::add_recent_project(const QString &url) -{ - bool found = false; - for (int i=0;i olive::config.maximum_recent_projects) { - recent_projects.removeLast(); - } - } - save_recent_projects(); -} - -void OliveGlobal::load_recent_projects() -{ - QFile f(get_recent_project_list_file()); - if (f.exists() && f.open(QFile::ReadOnly | QFile::Text)) { - QTextStream text_stream(&f); - while (true) { - QString line = text_stream.readLine(); - if (line.isNull()) { - break; - } else { - recent_projects.append(line); - } - } - f.close(); - } -} - -int OliveGlobal::recent_project_count() -{ - return recent_projects.size(); -} - -const QString &OliveGlobal::recent_project(int index) -{ - return recent_projects.at(index); -} - -const QString &OliveGlobal::get_autorecovery_filename() -{ - return autorecovery_filename; -} - -void OliveGlobal::LoadProject(const QString &fn, bool autorecovery) -{ - // QSortFilterProxyModels are not thread-safe, and as we'll be loading in another thread, leaving it connected - // can cause glitches in its presentation. Therefore for the duration of the loading process, we disconnect it, - // and reconnect it later once the loading is complete. - - for (int i=0;iDisconnectFilterToModel(); - } - - 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())); - connect(lt, SIGNAL(error()), &ld, SLOT(reject())); - connect(lt, SIGNAL(error()), this, SLOT(new_project())); - connect(lt, SIGNAL(report_progress(int)), &ld, SLOT(setValue(int))); - lt->start(); - - for (int i=0;iConnectFilterToModel(); - } -} - -void OliveGlobal::ClearProject() -{ - // clear graph editor - panel_graph_editor->set_row(nullptr); - - // clear effects panel - panel_effect_controls->Clear(true); - - // clear existing project - Timeline::CloseAll(); - panel_footage_viewer->set_media(nullptr); - - // delete sequences first because it's important to close all the clips before deleting the media - QVector sequences = olive::project_model.GetAllSequences(); - for (int i=0;iset_sequence(nullptr); - } - - // clear project contents (footage, sequences, etc.) - olive::project_model.clear(); - - // clear undo stack - olive::undo_stack.clear(); - - // empty current project filename - update_project_filename(""); - - // full update of all panels - update_ui(false); - - // set to unmodified - set_modified(false); -} - -void OliveGlobal::save_recent_projects() -{ - // save to file - QFile f(get_recent_project_list_file()); - if (f.open(QFile::WriteOnly | QFile::Truncate | QFile::Text)) { - QTextStream out(&f); - for (int i=0;i 0) { - out << "\n"; - } - out << recent_projects.at(i); - } - f.close(); - } else { - qWarning() << "Could not save recent projects"; - } -} - -void OliveGlobal::PasteInternal(Sequence *s, bool insert) -{ - if (s == nullptr) { - return; - } - - if (!olive::clipboard.IsEmpty()) { - if (olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_CLIP) { - ComboAction* ca = new ComboAction(); - - // create copies and delete areas that we'll be pasting to - QVector delete_areas; - QVector original_clips; - QVector pasted_clips; - long paste_start = LONG_MAX; - long paste_end = LONG_MIN; - - for (int i=0;i(olive::clipboard.Get(i)); - - // create copy of clip and offset by playhead - ClipPtr cc = c->copy(s->TrackAt(c->track()->type(), c->track()->Index())); - - // convert frame rates - cc->set_timeline_in(rescale_frame_number(cc->timeline_in(), c->cached_frame_rate(), s->frame_rate())); - cc->set_timeline_out(rescale_frame_number(cc->timeline_out(), c->cached_frame_rate(), s->frame_rate())); - cc->set_clip_in(rescale_frame_number(cc->clip_in(), c->cached_frame_rate(), s->frame_rate())); - - cc->set_timeline_in(cc->timeline_in() + s->playhead); - cc->set_timeline_out(cc->timeline_out() + s->playhead); - cc->set_track(c->track()); - - paste_start = qMin(paste_start, cc->timeline_in()); - paste_end = qMax(paste_end, cc->timeline_out()); - - original_clips.append(c.get()); - pasted_clips.append(cc); - - if (!insert) { - delete_areas.append(Selection(cc->timeline_in(), cc->timeline_out(), c->track())); - } - } - if (insert) { - s->SplitAllClipsAtPoint(ca, s->playhead); - s->Ripple(ca, paste_start, paste_end - paste_start); - } else { - s->DeleteAreas(ca, delete_areas, false); - } - - // correct linked clips - olive::timeline::RelinkClips(original_clips, pasted_clips); - - ca->append(new AddClipCommand(pasted_clips)); - - olive::undo_stack.push(ca); - - update_ui(true); - - if (olive::config.paste_seeks) { - panel_sequence_viewer->seek(paste_end); - } - - } else if (olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_EFFECT) { - ComboAction* ca = new ComboAction(); - - bool replace = false; - bool skip = false; - bool ask_conflict = true; - - QVector selected_clips = s->SelectedClips(); - - for (int i=0;i(olive::clipboard.Get(j)); - if (c->type() == e->subtype()) { - int found = -1; - if (ask_conflict) { - replace = false; - skip = false; - } - for (int k=0;keffects.size();k++) { - if (c->effects.at(k)->id() == e->id()) { - found = k; - break; - } - } - if (found >= 0 && ask_conflict) { - QMessageBox box(olive::MainWindow); - box.setWindowTitle(tr("Effect already exists")); - box.setText(tr("Clip '%1' already contains a '%2' effect. " - "Would you like to replace it with the pasted one or add it as a separate effect?") - .arg(c->name(), e->name())); - box.setIcon(QMessageBox::Icon::Question); - - box.addButton(tr("Add"), QMessageBox::YesRole); - QPushButton* replace_button = box.addButton(tr("Replace"), QMessageBox::NoRole); - QPushButton* skip_button = box.addButton(tr("Skip"), QMessageBox::RejectRole); - - QCheckBox* future_box = new QCheckBox(tr("Do this for all conflicts found"), &box); - box.setCheckBox(future_box); - - box.exec(); - - if (box.clickedButton() == replace_button) { - replace = true; - } else if (box.clickedButton() == skip_button) { - skip = true; - } - ask_conflict = !future_box->isChecked(); - } - - if (found >= 0 && skip) { - // do nothing - } else if (found >= 0 && replace) { - ca->append(new EffectDeleteCommand(c->effects.at(found).get())); - - ca->append(new AddEffectCommand(c, e->copy(c), kInvalidNode, found)); - } else { - ca->append(new AddEffectCommand(c, e->copy(c), kInvalidNode)); - } - } - } - } - if (ca->hasActions()) { - ca->appendPost(new ReloadEffectsCommand()); - olive::undo_stack.push(ca); - } else { - delete ca; - } - update_ui(true); - } - } -} - -void OliveGlobal::EffectMenuAction(QAction *q) -{ - ComboAction* ca = new ComboAction(); - - NodeType node_type = static_cast(q->data().toInt()); - OldEffectNode* n = olive::node_library[node_type].get(); - - for (int i=0;itype() == n->subtype()) { - if (n->type() == EFFECT_TYPE_TRANSITION) { - if (c->opening_transition == nullptr) { - ca->append(new AddTransitionCommand(c, - nullptr, - nullptr, - node_type, - olive::config.default_transition_length)); - } - if (c->closing_transition == nullptr) { - ca->append(new AddTransitionCommand(nullptr, - c, - nullptr, - node_type, - olive::config.default_transition_length)); - } - } else { - ca->append(new AddEffectCommand(c, nullptr, node_type)); - } - } - } - olive::undo_stack.push(ca); - update_ui(true); -} - -void OliveGlobal::ImportProject(const QString &fn) -{ - LoadProject(fn, false); - set_modified(true); -} - -void OliveGlobal::new_project() { - if (can_close_project()) { - ClearProject(); - } -} - -void OliveGlobal::OpenProject() { - QString fn = QFileDialog::getOpenFileName(olive::MainWindow, tr("Open Project..."), "", project_file_filter); - if (!fn.isEmpty() && can_close_project()) { - OpenProjectWorker(fn, false); - } -} - -void OliveGlobal::open_recent(int index) { - QString recent_url = recent_projects.at(index); - if (!QFile::exists(recent_url)) { - if (QMessageBox::question( - olive::MainWindow, - tr("Missing recent project"), - tr("The project '%1' no longer exists. Would you like to remove it from the recent projects list?").arg(recent_url), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - recent_projects.removeAt(index); - save_recent_projects(); - } - } else if (can_close_project()) { - OpenProjectWorker(recent_url, false); - } -} - -bool OliveGlobal::save_project_as() { - QString fn = QFileDialog::getSaveFileName(olive::MainWindow, tr("Save Project As..."), "", project_file_filter); - if (!fn.isEmpty()) { - if (!fn.endsWith(".ove", Qt::CaseInsensitive)) { - fn += ".ove"; - } - update_project_filename(fn); - olive::Save(false); - return true; - } - return false; -} - -bool OliveGlobal::save_project() { - if (olive::ActiveProjectFilename.isEmpty()) { - return save_project_as(); - } else { - olive::Save(false); - return true; - } -} - -bool OliveGlobal::can_close_project() { - if (is_modified()) { - QMessageBox* m = new QMessageBox( - QMessageBox::Question, - tr("Unsaved Project"), - tr("This project has changed since it was last saved. Would you like to save it before closing?"), - QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, - olive::MainWindow - ); - m->setWindowModality(Qt::WindowModal); - int r = m->exec(); - delete m; - if (r == QMessageBox::Yes) { - return save_project(); - } else if (r == QMessageBox::Cancel) { - return false; - } - } - return true; -} - -void OliveGlobal::open_new_sequence_dialog() -{ - NewSequenceDialog nsd(olive::MainWindow); - nsd.set_sequence_name(olive::project_model.GetNextSequenceName()); - nsd.exec(); -} - -void OliveGlobal::open_import_dialog() -{ - QFileDialog fd(olive::MainWindow, tr("Import media..."), "", tr("All Files") + " (*)"); - fd.setFileMode(QFileDialog::ExistingFiles); - - if (fd.exec()) { - QStringList files = fd.selectedFiles(); - - Media* parent = nullptr; - for (int i=0;ifocused()) { - parent = panel_project.at(i)->get_selected_folder(); - break; - } - } - - olive::project_model.process_file_list(files, false, nullptr, parent); - } -} - -void OliveGlobal::open_export_dialog() { - if (CheckForActiveSequence()) { - ExportDialog e(olive::MainWindow, Timeline::GetTopSequence().get()); - e.exec(); - } -} - -void OliveGlobal::finished_initialize() { - if (enable_load_project_on_init) { - - // if a project was set as a command line argument, we load it here - if (QFileInfo::exists(olive::ActiveProjectFilename)) { - OpenProjectWorker(olive::ActiveProjectFilename, false); - } else { - QMessageBox::critical(olive::MainWindow, - tr("Missing Project File"), - tr("Specified project '%1' does not exist.").arg(olive::ActiveProjectFilename), - QMessageBox::Ok); - update_project_filename(nullptr); - } - - enable_load_project_on_init = false; - - } else { - // if we are not loading a project on launch and are running a release build, open the demo notice dialog -#ifndef QT_DEBUG - DemoNotice* d = new DemoNotice(olive::MainWindow); - connect(d, SIGNAL(finished(int)), d, SLOT(deleteLater())); - d->open(); -#endif - } - - // Check for updates - olive::update_notifier.check(); -} - -void OliveGlobal::save_autorecovery_file() { - if (changed_since_last_autorecovery) { - olive::Save(true); - - changed_since_last_autorecovery = false; - - qInfo() << "Auto-recovery project saved"; - } -} - -void OliveGlobal::open_preferences() { - panel_sequence_viewer->pause(); - panel_footage_viewer->pause(); - - PreferencesDialog pd(olive::MainWindow); - pd.exec(); -} - -void OliveGlobal::PrimarySequenceChanged() -{ - panel_graph_editor->set_row(nullptr); - panel_effect_controls->Clear(true); -} - -void OliveGlobal::clear_recent_projects() -{ - recent_projects.clear(); - save_recent_projects(); -} - -void OliveGlobal::OpenProjectWorker(QString fn, bool autorecovery) { - ClearProject(); - update_project_filename(fn); - LoadProject(fn, autorecovery); - olive::undo_stack.clear(); -} - -bool OliveGlobal::CheckForActiveSequence(bool show_msg) -{ - if (Timeline::GetTopSequence() == nullptr) { - - if (show_msg) { - QMessageBox::information(olive::MainWindow, - tr("No active sequence"), - tr("Please open the sequence to perform this action."), - QMessageBox::Ok); - } - - return false; - } - return true; -} - -void OliveGlobal::ShowEffectMenu(EffectType type, olive::TrackType subtype, const QVector selected_clips) -{ - effect_menu_selected_clips = selected_clips; - - olive::effects_loaded.lock(); - - Menu effects_menu(olive::MainWindow); - effects_menu.setToolTipsVisible(true); - - for (int i=0;itype() == type && node->subtype() == subtype) { - QAction* action = new QAction(&effects_menu); - action->setText(node->name()); - action->setData(i); - if (!node->description().isEmpty()) { - action->setToolTip(node->description()); - } - - QMenu* parent = &effects_menu; - if (!node->category().isEmpty()) { - bool found = false; - for (int j=0;jmenu() != nullptr) { - if (action->menu()->title() == node->category()) { - parent = action->menu(); - found = true; - break; - } - } - } - if (!found) { - parent = new Menu(&effects_menu); - parent->setToolTipsVisible(true); - parent->setTitle(node->category()); - - bool found = false; - for (int i=0;itext() > node->category()) { - effects_menu.insertMenu(comp_action, parent); - found = true; - break; - } - } - if (!found) effects_menu.addMenu(parent); - } - } - - bool found = false; - for (int i=0;iactions().size();i++) { - QAction* comp_action = parent->actions().at(i); - if (comp_action->text() > action->text()) { - parent->insertAction(comp_action, action); - found = true; - break; - } - } - if (!found) parent->addAction(action); - } - } - - olive::effects_loaded.unlock(); - - connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(EffectMenuAction(QAction*))); - effects_menu.exec(QCursor::pos()); -} - -void OliveGlobal::undo() { - // workaround to prevent crash (and also users should never need to do this) - if (!Timeline::IsImporting()) { - olive::undo_stack.undo(); - update_ui(true); - } -} - -void OliveGlobal::redo() { - // workaround to prevent crash (and also users should never need to do this) - if (!Timeline::IsImporting()) { - olive::undo_stack.redo(); - update_ui(true); - } -} - -void OliveGlobal::paste() { - PasteInternal(Timeline::GetTopSequence().get(), false); -} - -void OliveGlobal::paste_insert() { - PasteInternal(Timeline::GetTopSequence().get(), true); -} - -void OliveGlobal::open_about_dialog() { - AboutDialog a(olive::MainWindow); - a.exec(); -} - -void OliveGlobal::open_debug_log() { - olive::DebugDialog->show(); -} - -void OliveGlobal::open_speed_dialog() { - if (Timeline::GetTopSequence() != nullptr) { - - QVector selected_clips = Timeline::GetTopSequence()->SelectedClips(); - - if (!selected_clips.isEmpty()) { - SpeedDialog s(olive::MainWindow, selected_clips); - s.exec(); - } - } -} - -void OliveGlobal::open_autocut_silence_dialog() { - if (CheckForActiveSequence()) { - - QVector selected_clips = Timeline::GetTopSequence()->SelectedClips(); - - if (selected_clips.isEmpty()) { - QMessageBox::critical(olive::MainWindow, - tr("No clips selected"), - tr("Select the clips you wish to auto-cut"), - QMessageBox::Ok); - } else { - AutoCutSilenceDialog s(olive::MainWindow, selected_clips); - s.exec(); - } - - } -} - -void OliveGlobal::clear_undo_stack() { - olive::undo_stack.clear(); -} - -void OliveGlobal::open_action_search() { - ActionSearch as(olive::MainWindow); - as.exec(); -} diff --git a/global/global.h b/global/global.h deleted file mode 100644 index d121fc417..000000000 --- a/global/global.h +++ /dev/null @@ -1,573 +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 OLIVEGLOBAL_H -#define OLIVEGLOBAL_H - -#include - -#include -#include -#include - -#include "undo/undo.h" -#include "rendering/pixelformats.h" - -/** - * @brief The Olive Global class - * - * A resource for various global functions used throughout Olive. - */ -class OliveGlobal : public QObject { - Q_OBJECT -public: - /** - * @brief OliveGlobal Constructor - * - * Creates Olive Global object. Also sets some default runtime settings and the application name. - */ - OliveGlobal(); - - /** - * @brief Returns the file dialog filter used when interfacing with Olive project files. - * - * @return The file filter string used by QFileDialog to limit the files shown to Olive (*.ove) files. - */ - const QString& get_project_file_filter(); - - /** - * @brief Change the current active project filename - * - * Triggered to change the current active project filename. Call this before calling any internal project - * saving or loading functions in order to set which file to work with (OliveGlobal::open_project() and - * OliveGlobal::save_project_as() do this automatically). Also updates the main window title to reflect the - * project filename. - * - * @param s - * - * The URL of the project file to work with. Can be an empty string, in which case Olive will treat the project - * as an unsaved project. - */ - void update_project_filename(const QString& s); - - /** - * @brief Check whether an auto-recovery file exists and ask the user if they want to load it. - * - * Usually called on initialization. Checks if an auto-recovery file exists (meaning the last session of Olive - * didn't close correctly). If it finds one, asks the user if they want to load it. If so, loads the auto-recovery - * project. - */ - void check_for_autorecovery_file(); - - /** - * @brief Get whether the project is currently being rendered or not. Useful for determining whether to treat the - * render as online or offline. - * - * @return - * - * TRUE if the project is being exported, FALSE if not. - */ - bool is_exporting(); - - /** - * @brief Returns the "effective" bit depth for the composition pipeline - * - * Convenience function for using Config::playback_bit_depth or Config::export_bit_depth depending on the state of - * OliveGlobal::is_exporting() - */ - const olive::PixelFormat& effective_bit_depth(); - - /** - * @brief Set the application state depending on if the user is exporting a video - * - * Some background functions shouldn't run while Olive is exporting a video. This function will disable/enable them - * as necessary. - * - * The current functions are as follows: - * * Auto-recovery interval. Olive saves an auto-recovery just before exporting anyway and seeing as the user - * cannot make changes while rendering, there's no reason to continue saving auto-recovery files. - * * Audio device playback. Olive uses the same internal audio buffer for exporting as it does for playback, but - * this buffer does not need to be forwarded to the output device when exporting. - * - * @param rendering - * - * **TRUE** if Olive is about to export a video. **FALSE** if Olive has finished exporting. - */ - void set_export_state(bool rendering); - - /** - * @brief Set the application's "modified" state - * - * Primarily controls whether the application prompts the user to save the project upon closing or not. Also - * technically controls whether to create autorecovery files as they'll only be generated if there are unsaved - * changes. - * - * @param modified - * - * TRUE if the project has been modified, FALSE if it has not. - */ - void set_modified(bool modified); - - /** - * @brief Get application's current "modified" state - * - * Currently just a wrapper around MainWindow::isWindowModified(), but use this instead in case it changes. - * This value is used to determine whether the currently open project has unsaved changes. - * - * @return - * - * TRUE if the project has been modified since the last save. - */ - bool is_modified(); - - /** - * @brief Set a project to load just after launching - * - * Called by main() if Olive was called with a project file as a running argument. Sets up Olive to load the - * specified project once its finished initializing. - * - * @param s - * - * The URL of the project file to load. - */ - void load_project_on_launch(const QString& s); - - /** - * @brief Retrieves the URL of the config file containing the autorecovery projects - * @return The URL as a string - */ - QString get_recent_project_list_file(); - - /** - * @brief (Re)load translation file from olive::config - */ - void load_translation_from_config(); - - /** - * @brief Set native UI styling on a given widget - * - * @param w - * - * The widget to set styling on. - */ - static void SetNativeStyling(QWidget* w); - - /** - * @brief Adds a project URL to the recent projects list - * - * @param url - * - * The project URL to add - */ - void add_recent_project(const QString& url); - - /** - * @brief Load recent projects from file - * - * Should be called on application startup. - */ - void load_recent_projects(); - - /** - * @brief Total count of recent projects - * - * @return - * - * Number of recent projects in the list - */ - int recent_project_count(); - - /** - * @brief Get the recent project at a given index - * - * @param index - * - * @return - * - * The recent project at index - */ - const QString& recent_project(int index); - - /** - * @brief Retrieves the filename of the autorecovery file to save to during this session - * - * @return - * - * A URL pointing to the autorecovery file - */ - const QString& get_autorecovery_filename(); - - /** - * @brief Returns whether a Sequence is currently active or not, and optionally displays a messagebox if not - * - * Checks whether a Sequence is active and can display a messagebox if not to inform users to make one active in - * order to perform said action. - * - * @return - * - * TRUE if there is an active Sequence, FALSE if not. - */ - bool CheckForActiveSequence(bool show_msg = true); - - - void ShowEffectMenu(EffectType type, olive::TrackType subtype, const QVector selected_clips); - -public slots: - /** - * @brief Undo user's last action - */ - void undo(); - - /** - * @brief Redo user's last action - */ - void redo(); - - /** - * @brief Paste contents of clipboard - * - * Pastes contents of clipboard. Seeing as several types of data can be copied into the clipboard, this - * function will automatically determine what type of data is in the clipboard and paste it in the correct - * location (e.g. clip data will go to the Timeline, effect data will go to Effect Controls). - */ - void paste(); - - /** - * @brief Paste contents of clipboard, making space for it when possible - * - * Pastes contents of clipboard (same as paste()). If the clipboard contains clip data, the clips are cut at the - * current playhead and ripple forward to make space for the clips in the clipboard. Can be considered - * semi-non-destructive as a result (as opposed to paste() overwriting clips). If the clipboard contains effect - * data, the functionality is identical to paste(). - */ - void paste_insert(); - - /** - * @brief Create new project. - * - * Confirms whether the current project can be closed, and if so, clears all current project data and resets - * program state. Standard `File > New` behavior. - */ - void new_project(); - - /** - * @brief Open a project from file. - * - * Confirms whether the current project can be closed, and if so, shows an open file dialog to allow the user to - * select a project file and then triggers a project load with it. - */ - void OpenProject(); - - /** - * @brief Import project from file - * - * Imports an Olive project into the current project, effectively merging them. - * - * @param fn - * - * The filename of the project to import. - */ - void ImportProject(const QString& fn); - - /** - * @brief Open recent project from list - * - * Triggers a project load from the internal recent projects list. - * - * @param index - * - * Index in the list of the project file to load - */ - void open_recent(int index); - - /** - * @brief Shows a save file dialog and saves the project as the resulting filename - * - * Shows a save file dialog for the user to save their current project as a different filename from the current - * one. Also triggered by save_project() if the file hasn't been saved yet. - * - * @return **TRUE** if the user saved the project. **FALSE** if they cancelled out of the save file dialog. Useful - * if a user is closing an unsaved project, clicks "Yes" to save, we know if they actually saved or not and won't - * continue closing the project if they didn't. - */ - bool save_project_as(); - - /** - * @brief Saves the current project to file - * - * If the project has been saved already, this function will overwrite the project file with the current project - * data. Calls save_project_as() if the file has not been saved before. - * - * @return **TRUE** if the project has been saved before and was successfully overwritten. Otherwise returns the - * value of save_project_as(). Useful if the user closing an unsaved project, clicks "Yes" to save, we know if they - * actually saved or not and won't continue closing the project if they didn't. - */ - bool save_project(); - - /** - * @brief Determine whether the current project can be closed. - * - * Queried any time the current project is going to be closed (e.g. starting a new project, loading a project, - * exiting Olive, etc.) If the project has unsaved changes, this function asks the user whether they want to save or - * not. If the user does, calls save_project() (which may in turn call save_project_as() if the project has never - * been saved). - * - * @return **TRUE** if the project can be closed. FALSE if not. If the project does NOT have unsaved changes, always - * returns **TRUE**. If it does and the user clicks YES, this returns the result of save_project(). If the user - * clicks NO, this returns **TRUE**. If the user clicks CANCEL, this returns **FALSE**. - */ - bool can_close_project(); - - /** - * @brief Opens the NewSequenceDialog to create a new Sequence - */ - void open_new_sequence_dialog(); - - /** - * @brief Open a file dialog for importing files into the project - */ - void open_import_dialog(); - - /** - * @brief Open the Export dialog to trigger an export of the current sequence. - */ - void open_export_dialog(); - - /** - * @brief Open the About Olive dialog. - */ - void open_about_dialog(); - - /** - * @brief Open the Debug Log window. - */ - void open_debug_log(); - - /** - * @brief Open the Speed/Duration dialog. - */ - void open_speed_dialog(); - - /** - * @brief Open the auto-cut silence dialog. - */ - void open_autocut_silence_dialog(); - - /** - * @brief Open the Action Search overlay. - */ - void open_action_search(); - - /** - * @brief Clears the current undo stack. - * - * Clears all current commands in the undo stack. Mostly used for debugging. - */ - void clear_undo_stack(); - - /** - * @brief Function called when Olive has finished starting up - * - * Sets up some last things for Olive that must be run after Olive has completed initialization. If a project was - * loaded as a command line argument, it's loaded here. - */ - void finished_initialize(); - - /** - * @brief Save an auto-recovery file of the current project. - * - * Call this function to save the current state of the project as an auto-recovery project. Called regularly by - * `autorecovery_timer`. - */ - void save_autorecovery_file(); - - /** - * @brief Opens the Preferences dialog - */ - void open_preferences(); - - /** - * @brief Clear the recent projects list - * - * Also saves the cleared recent projects to the config file making it permanent. - */ - void clear_recent_projects(); - - /** - * @brief Slot for when the primary sequence has changed. - * - * Usually by opening a sequence or bringing a corresponding - * Timeline widget on top. - */ - void PrimarySequenceChanged(); - -private: - /** - * @brief Internal function to handle loading a project from file - * - * Start loading a project. Doesn't check if the current project can be closed, doesn't check if the project exists. - * In most cases, you'll want open_project() to be end-user friendly. - * - * @param fn - * - * The URL to the project to load. - * - * @param autorecovery - * - * Whether this file is an autorecovery file. If it is, after the load Olive will set the project URL to a new file - * beside the original project file so that it does not overwrite the original and so that the user is not working - * on the autorecovery project in Olive's application data directory. - */ - void OpenProjectWorker(QString fn, bool autorecovery); - - /** - * @brief Create a LoadDialog and start a LoadThread to load data from a project - * - * Loads data from an Olive project file creating a LoadDialog to show visual information and a LoadThread to load - * outside of the main/GUI thread. - * - * All project loading functions eventually lead to this one and there's no reason to use it directly. Instead use - * one of the following functions: - * - * * OpenProject() - to check if the current project can be closed and prompt the user for the new project file - * * OpenProjectWorker() - if you already have the filename and wish to close the current project and open it - * * ImportProject() - to import a project file into this one, effectively merging them both - * - * @param fn - * - * The URL of the project file to open - * - * @param autorecovery - * - * TRUE if this file is an autorecovery file, in which case it's loaded slightly differently - * - * @param clear - * - * 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); - - /** - * @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 Saves current recent project list to the configuration file - * - * This should be called whenever the recent projects change so the changes can be persistent. - */ - void save_recent_projects(); - - /** - * @brief Internal pasting function - */ - void PasteInternal(Sequence* s, bool insert); - - /** - * @brief File filter used for any file dialogs relating to Olive project files. - */ - QString project_file_filter; - - /** - * @brief Regular interval to save an auto-recovery project. - */ - QTimer autorecovery_timer; - - /** - * @brief Internal variable set to **TRUE** by main() if a project file was set as an argument - */ - bool enable_load_project_on_init; - - /** - * @brief Internal translator object that interfaces with the currently loaded language file - */ - std::unique_ptr translator; - - /** - * @brief Internal variable for whether the project has changed since the last autorecovery - * - * Set by set_modified(), which should be called alongside any change made to the project file and is "unset" when - * an autorecovery file is made. Provides an extra layer of abstraction from the application "modified" state to - * prevents an autorecovery file saving multiple times if the project hasn't actually changed since the last - * autorecovery, but still hasn't been saved into the original file yet. - */ - bool changed_since_last_autorecovery; - - /** - * @brief Internal variable for rendering state (set by set_rendering_state() and accessed by is_rendering() ). - */ - bool rendering_; - - /** - * @brief Internal variable for the filename to the autorecovery project file - */ - QString autorecovery_filename; - - /** - * @brief Internal list of recent projects - */ - QStringList recent_projects; - - /** - * @brief Internal array of selected clips that a menu created by ShowEffectMenu will act on - */ - QVector effect_menu_selected_clips; - -private slots: - /** - * @brief Receiver for a menu initiated by ShowEffectMenu - * - * Adds the selected effect/node to the clips in - * - * @param q - */ - void EffectMenuAction(QAction* q); -}; - -namespace olive { -/** - * @brief Object resource for various global functions used throughout Olive - */ -extern std::unique_ptr Global; - -/** - * @brief Currently active project filename - * - * Filename for the currently active project. Empty means the file has not - * been saved yet. - */ -extern QString ActiveProjectFilename; - -/** - * @brief Current application name - */ -extern QString AppName; - -/** - * Rational type for - */ -} - -#endif // OLIVEGLOBAL_H diff --git a/global/math.cpp b/global/math.cpp deleted file mode 100644 index 09ff22431..000000000 --- a/global/math.cpp +++ /dev/null @@ -1,107 +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 "math.h" - -#include -#include - -#include "debug.h" - -int lerp(int a, int b, double t) { - return qRound(((1.0 - t) * a) + (t * b)); -} - -float float_lerp(float a, float b, float t) { - return ((1.0F - t) * a) + (t * b); -} - -double double_lerp(double a, double b, double t) { - 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; -} - -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); -} - -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; -} - -double cubic_t_from_x(double x_target, double a, double b, double c, double d) { - double tolerance = 0.0001; - - double lower = 0.0; - double upper = 1.0; - - 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; - } - - percent = (upper + lower) / 2.0; - x = cubic_from_t(a, b, c, d, percent); - } - - return percent; -} - -double amplitude_to_db(double amplitude) { - return (20.0*(qLn(amplitude)/qLn(10.0))); -} - -double db_to_amplitude(double db) { - 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); - } -} - -template -const T &clamp(const T &val, T &min, T &max) -{ - return qMax(qMin(max, val), min); -} diff --git a/global/math.h b/global/math.h deleted file mode 100644 index 04f2bbb9b..000000000 --- a/global/math.h +++ /dev/null @@ -1,48 +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 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); -double quad_from_t(double a, double b, double c, double t); -double quad_t_from_x(double x, double a, double b, double c); -double cubic_from_t(double a, double b, double c, double d, double t); -double cubic_t_from_x(double x_target, double a, double b, double c, double d); -double solveCubicBezier(double p0, double p1, double p2, double p3, double x); - -template -const T& clamp(const T& val, T& min, T& max); - -QRect fit_size_into_rect(const QRect& r, int width, int height); - -// decibel conversion functions -double amplitude_to_db(double amplitude); -double db_to_amplitude(double db); - -// frame <-> pixel conversion functions -int getScreenPointFromFrame(double zoom, long frame); -long getFrameFromScreenPoint(double zoom, int x); - -#endif // MATH_H diff --git a/global/path.cpp b/global/path.cpp deleted file mode 100644 index 56c8ca148..000000000 --- a/global/path.cpp +++ /dev/null @@ -1,122 +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 "path.h" - -#include -#include -#include -#include -#include - -#include "debug.h" - -QString get_app_path() { - return QCoreApplication::applicationDirPath(); -} - -QDir get_app_dir() { - return QDir(get_app_path()); -} - -QString get_data_path() { - QDir app_dir = get_app_dir(); - if (QFileInfo::exists(app_dir.filePath("portable"))) { - return app_dir.absolutePath(); - } else { - return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - } -} - -QDir get_data_dir() { - return QDir(get_data_path()); -} - -QString get_config_path() { - QDir app_dir = get_app_dir(); - if (QFileInfo::exists(app_dir.filePath("portable"))) { - return app_dir.absolutePath(); - } else { - return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); - } -} - -QDir get_config_dir() { - return QDir(get_config_path()); -} - -QList get_effects_paths() { - // returns a list of the effects paths to search - - QList effects_paths; - - // get current app working directory - QDir app_dir = get_app_dir(); - - // "effects" subfolder in program folder - best for Windows - effects_paths.append(app_dir.filePath("effects")); - - // "Effects" folder one level above the program's directory - best for Mac - effects_paths.append(app_dir.filePath("../Effects")); - - // folder in share folder - best for Linux - effects_paths.append(app_dir.filePath("../share/olive-editor/effects")); - - // user path - best for linux - effects_paths.append(QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("effects")); - - // Olive will also accept a manually provided folder with an environment variable - QString env_path(qgetenv("OLIVE_EFFECTS_PATH")); - if (!env_path.isEmpty()) effects_paths.append(env_path); - - return effects_paths; -} - -QString get_file_hash(const QString& filename) { - QFileInfo file_info(filename); - - QString cache_file = filename.mid(filename.lastIndexOf('/')+1) - + QString::number(file_info.size()) - + QString::number(file_info.lastModified().toMSecsSinceEpoch()); - - return QCryptographicHash::hash(cache_file.toUtf8(), QCryptographicHash::Md5).toHex(); -} - -QList get_language_paths() { - QList language_paths; - - // get current app working directory - QDir app_dir = get_app_dir(); - - // subfolder in program folder - best for Windows (or compiling+running from source dir) - language_paths.append(app_dir.filePath("ts")); - - // folder one level above the program's directory - best for Mac - language_paths.append(app_dir.filePath("../Translations")); - - // folder in share folder - best for Linux - language_paths.append(app_dir.filePath("../share/olive-editor/ts")); - - // Olive will also accept a manually provided folder with an environment variable - QString env_path(qgetenv("OLIVE_LANG_PATH")); - if (!env_path.isEmpty()) language_paths.append(env_path); - - return language_paths; -} diff --git a/global/path.h b/global/path.h deleted file mode 100644 index 764e5e150..000000000 --- a/global/path.h +++ /dev/null @@ -1,38 +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 PATH_H -#define PATH_H - -#include -#include - -QString get_app_path(); -QString get_data_path(); -QDir get_data_dir(); -QString get_config_path(); -QDir get_config_dir(); -QList get_effects_paths(); -QList get_language_paths(); - -// generate hash algorithm used to uniquely identify files -QString get_file_hash(const QString& filename); - -#endif // PATH_H diff --git a/global/rational.cpp b/global/rational.cpp deleted file mode 100644 index e6df7a871..000000000 --- a/global/rational.cpp +++ /dev/null @@ -1,377 +0,0 @@ -#include "rational.h" - -rational::rational(const int64_t &numerator) : - numerator_(numerator), - denominator_(1) -{ - if (numerator_ == 0) { - denominator_ = 0; - } -} - -rational::rational(const int64_t &numerator, const int64_t &denominator) : - numerator_(numerator), - denominator_(denominator) -{ - if (denominator_ != 0) { - - if (numerator_ != 0) { - FixSigns(); - Reduce(); - } else { - denominator_ = 0; - } - - } else { - numerator_ = 0; - } -} - -rational::rational(const AVRational &r) : - numerator_(r.num), - denominator_(r.den) -{ -} - -rational::rational(const rational &r) : - numerator_(r.numerator_), - denominator_(r.denominator_) -{ -} - -const rational &rational::operator=(const rational &r) -{ - if (this != &r) { - numerator_ = r.numerator_; - denominator_ = r.denominator_; - } - - return *this; -} - -const rational &rational::operator+=(const rational &r) -{ - if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - numerator_ = 0; - denominator_ = 0; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - // The other rational == 0, no addition needs to be done - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) - { - numerator_ = r.numerator_; - denominator_ = r.denominator_; - } - else - { - numerator_ = (numerator_ * r.denominator_) + (r.numerator_ * denominator_); - denominator_ = denominator_ * r.denominator_; - FixSigns(); - Reduce(); - } - } - } - return *this; -} - -const rational &rational::operator-=(const rational &r) -{ - if(numerator_ * denominator_ == 0 && r.numerator_ * r.numerator_ == 0) { - numerator_ = 0; - denominator_ = 0; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - numerator_ = -(r.numerator_); - denominator_ = r.denominator_; - } else { - numerator_ = (numerator_ * r.denominator_) - (r.numerator_ * denominator_); - numerator_ = denominator_ * r.denominator_; - FixSigns(); - Reduce(); - } - } - } - return *this; -} - -const rational &rational::operator/=(const rational &r) -{ - numerator_ = numerator_ * r.denominator_; - denominator_ = denominator_ * r.numerator_; - FixSigns(); - Reduce(); - return *this; -} - -const rational &rational::operator*=(const rational &r) -{ - numerator_ = numerator_ * r.numerator_; - denominator_ = denominator_ * r.denominator_; - FixSigns(); - Reduce(); - return *this; -} - -rational rational::operator+(const rational &r) const -{ - rational result(*this); - result += r; - return result; -} - -rational rational::operator-(const rational &r) const -{ - rational result(*this); - result -= r; - return result; -} - -rational rational::operator/(const rational &r) const -{ - rational result(*this); - result /= r; - return result; -} - -rational rational::operator*(const rational &r) const -{ - rational result(*this); - result *= r; - return result; -} - -bool rational::operator<(const rational &r) const -{ - if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - return false; - } else { - if (numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ < 0) - return true; - else - return false; - } - else { - if (numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if (r.numerator_ * r.denominator_ < 0) { - return false; - } else { - return true; - } - } else { - return ((numerator_ * r.denominator_) < (denominator_ * r.numerator_)); - } - } - } -} - -bool rational::operator<=(const rational &r) const -{ - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - return true; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ < 0) { - return true; - } else { - return false; - } - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if(r.numerator_ * r.denominator_ < 0) { - return false; - } else { - return true; - } - } else { - return ((numerator_ * r.denominator_) <= (denominator_ * r.numerator_)); - } - } - } -} - -bool rational::operator>(const rational &r) const -{ - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - return false; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ > 0) { - return true; - } else { - return false; - } - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if(r.numerator_ * r.denominator_ > 0) { - return false; - } else { - return true; - } - } else { - return ((numerator_ * r.denominator_) > (denominator_ * r.numerator_)); - } - } - } -} - -bool rational::operator>=(const rational &r) const -{ - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ == 0) { - return true; - } else { - if(numerator_ * denominator_ != 0 && r.numerator_ * r.denominator_ == 0) { - if(numerator_ * denominator_ > 0) { - return true; - } else { - return false; - } - } else { - if(numerator_ * denominator_ == 0 && r.numerator_ * r.denominator_ != 0) { - if(r.numerator_ * r.denominator_ > 0) { - return false; - } else { - return true; - } - } else { - return ((numerator_ * r.denominator_) >= (denominator_ * r.numerator_)); - } - } - } -} - -bool rational::operator==(const rational &r) const -{ - return (numerator_ == r.numerator_ && denominator_ == r.denominator_); -} - -bool rational::operator!=(const rational &r) const -{ - return (numerator_ != r.numerator_) || (denominator_ != r.denominator_); -} - -const rational &rational::operator++() -{ - numerator_ += denominator_; - return *this; -} - -rational rational::operator++(int) -{ - rational tmp = *this; - numerator_ += denominator_; - return tmp; -} - -const rational &rational::operator--() -{ - numerator_ -= denominator_; - return *this; -} - -rational rational::operator--(int) -{ - rational tmp; - numerator_ -= denominator_; - return tmp; -} - -const rational &rational::operator+() const -{ - return *this; -} - -rational rational::operator-() const -{ - return rational(numerator_, -denominator_); -} - -bool rational::operator!() const -{ - return !numerator_; -} - -double rational::ToDouble() const -{ - if (denominator_ == 0) { - return 0; - } else { - return static_cast(numerator_)/static_cast(denominator_); - } -} - -void rational::FixSigns() -{ - // Ensures denominator is always positive (while numerator can be positive or negative) - if(denominator_ < 0) { - denominator_ = -denominator_; - numerator_ = -numerator_; - } - - // Ensures if either are zero, they're both zero - if(numerator_ == 0 || denominator_ == 0) { - numerator_ = 0; - denominator_ = 0; - } -} - -void rational::Reduce() -{ - int64_t d = 1; - - if(denominator_ != 0 && numerator_ != 0) { - d = GreatestCommonDenominator(numerator_, denominator_); - } - - if(d > 1) { - numerator_ /= d; - denominator_ /= d; - } -} - -int64_t rational::GreatestCommonDenominator(const int64_t& x, const int64_t& y) -{ - if (y == 0) { - return x; - } else { - int64_t tmp = x % y; - return GreatestCommonDenominator(y, tmp); - } -} - -std::ostream &operator<<(std::ostream &out, const rational &value) -{ - out << value.numerator_; - if(value.denominator_ != 1) - { - out << '/' << value.denominator_; - return out; - } - return out; -} - -std::istream &operator>>(std::istream &in, rational &value) -{ - in >> value.numerator_; - value.denominator_ = 1; - - char ch; - in.get(ch); - - if(!in.eof()) - { - if(ch == '/') - { - in >> value.denominator_; - value.FixSigns(); - value.Reduce(); - } - else - in.putback(ch); - } - return in; -} diff --git a/global/rational.h b/global/rational.h deleted file mode 100644 index 4a314757c..000000000 --- a/global/rational.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef RATIONAL_H -#define RATIONAL_H - -// Adapted from https://github.com/angularadam/Qt-Class-rational used in compliance with the GNU General Public License - -#include - -extern "C" { - #include -} - -class rational { -public: - // Constructors - rational(const int64_t& numerator = 0); - rational(const int64_t& numerator, const int64_t& denominator); - rational(const AVRational& r); // Auto-convert from an FFmpeg AVRational - rational(const rational& r); - - // Assignment Operators - const rational& operator=(const rational& r); - const rational& operator+=(const rational& r); - const rational& operator-=(const rational& r); - const rational& operator/=(const rational& r); - const rational& operator*=(const rational& r); - - // Math Operators - rational operator+(const rational& r) const; - rational operator-(const rational& r) const; - rational operator/(const rational& r) const; - rational operator*(const rational& r) const; - - // Relational and Equality Operators - bool operator<(const rational &r) const; - bool operator<=(const rational &r) const; - bool operator>(const rational &r) const; - bool operator>=(const rational &r) const; - bool operator==(const rational &r) const; - bool operator!=(const rational &r) const; - - //Unary operators - const rational& operator++(); //prefix - rational operator++(int); //postfix - const rational& operator--(); //prefix - rational operator--(int); //postfix - const rational& operator+() const; - rational operator-() const; - bool operator!() const; - - // IO - friend std::ostream& operator<<(std::ostream &out, const rational& value); - friend std::istream& operator>>(std::istream &in, rational& value); - - // Convert to double - double ToDouble() const; -private: - int64_t numerator_; - int64_t denominator_; - - void FixSigns(); - void Reduce(); - int64_t GreatestCommonDenominator(const int64_t &x, const int64_t &y); -}; - -#endif // RATIONAL_H diff --git a/global/timing.cpp b/global/timing.cpp deleted file mode 100644 index 9d0ae84db..000000000 --- a/global/timing.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "timing.h" - -#include "timeline/sequence.h" -#include "timeline/clip.h" -#include "global/config.h" - -double get_timecode(Clip* c, long playhead) { - return double(playhead_to_clip_frame(c, playhead))/c->track()->sequence()->frame_rate(); -} - -long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) { - return qRound((double(framenumber)/source_frame_rate)*target_frame_rate); -} - -long playhead_to_clip_frame(Clip* c, long playhead) { - return (qMax(0L, playhead - c->timeline_in(true)) + c->clip_in(true)); -} - -double playhead_to_clip_seconds(Clip* c, long playhead) { - // returns time in seconds - long clip_frame = playhead_to_clip_frame(c, playhead); - - if (c->reversed()) { - clip_frame = c->media_length() - clip_frame - 1; - } - - double secs = (double(clip_frame)/c->track()->sequence()->frame_rate())*c->speed().value; - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - secs *= c->media()->to_footage()->speed; - } - - return secs; -} - -int64_t seconds_to_timestamp(Clip *c, double seconds) { - return qRound64(seconds * av_q2d(av_inv_q(c->time_base()))); -} - -int64_t playhead_to_timestamp(Clip* c, long playhead) { - return seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead)); -} - -bool frame_rate_is_droppable(double rate) { - return (qFuzzyCompare(rate, 23.976) - || qFuzzyCompare(rate, 29.97) - || qFuzzyCompare(rate, 59.94)); -} - -long timecode_to_frame(const QString& s, int view, double frame_rate) { - QList list = s.split(QRegExp("[:;]")); - - if (view == olive::kTimecodeFrames || (list.size() == 1 && view != olive::kTimecodeMilliseconds)) { - return s.toLong(); - } - - int frRound = qRound(frame_rate); - int hours, minutes, seconds, frames; - - if (view == olive::kTimecodeMilliseconds) { - long milliseconds = s.toLong(); - - hours = milliseconds/3600000; - milliseconds -= (hours*3600000); - minutes = milliseconds/60000; - milliseconds -= (minutes*60000); - seconds = milliseconds/1000; - milliseconds -= (seconds*1000); - frames = qRound64((milliseconds*0.001)*frame_rate); - - seconds = qRound64(seconds * frame_rate); - minutes = qRound64(minutes * frame_rate * 60); - hours = qRound64(hours * frame_rate * 3600); - } else { - hours = ((list.size() > 0) ? list.at(0).toInt() : 0) * frRound * 3600; - minutes = ((list.size() > 1) ? list.at(1).toInt() : 0) * frRound * 60; - seconds = ((list.size() > 2) ? list.at(2).toInt() : 0) * frRound; - frames = (list.size() > 3) ? list.at(3).toInt() : 0; - } - - int f = (frames + seconds + minutes + hours); - - if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) { - // return drop - int d; - int m; - - int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate - int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes - int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames - - d = f / framesPer10Minutes; - f -= dropFrames*9*d; - - m = f % framesPer10Minutes; - - if (m > dropFrames) { - f -= (dropFrames * ((m - dropFrames) / framesPerMinute)); - } - } - - // return non-drop - return f; -} - -QString frame_to_timecode(long f, int view, double frame_rate) { - if (view == olive::kTimecodeFrames) { - return QString::number(f); - } - - // return timecode - int hours = 0; - int mins = 0; - int secs = 0; - int frames = 0; - QString token = ":"; - - if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) { - //CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE - //Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team - //Given an int called framenumber and a double called framerate - //Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off. - - int d; - int m; - - int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate - int framesPerHour = qRound(frame_rate*60*60); //Number of frqRound64ames in an hour - int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours - int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes - int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames - - //If framenumber is greater than 24 hrs, next operation will rollover clock - f = f % framesPer24Hours; // % is the modulus operator, which returns a remainder. a % b = the remainder of a/b - - d = f / framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b) - m = f % framesPer10Minutes; - - //In the original post, the next line read m>1, which only worked for 29.97. Jean-Baptiste Mardelle correctly pointed out that m should be compared to dropFrames. - if (m > dropFrames) { - f = f + (dropFrames*9*d) + dropFrames * ((m - dropFrames) / framesPerMinute); - } else { - f = f + dropFrames*9*d; - } - - int frRound = qRound(frame_rate); - frames = f % frRound; - secs = (f / frRound) % 60; - mins = ((f / frRound) / 60) % 60; - hours = (((f / frRound) / 60) / 60); - - token = ";"; - } else { - // non-drop timecode - - int int_fps = qRound(frame_rate); - hours = f / (3600 * int_fps); - mins = f / (60*int_fps) % 60; - secs = f/int_fps % 60; - frames = f%int_fps; - } - if (view == olive::kTimecodeMilliseconds) { - return QString::number((hours*3600000)+(mins*60000)+(secs*1000)+qCeil(frames*1000/frame_rate)); - } - return QString(QString::number(hours).rightJustified(2, '0') + - ":" + QString::number(mins).rightJustified(2, '0') + - ":" + QString::number(secs).rightJustified(2, '0') + - token + QString::number(frames).rightJustified(2, '0') - ); -} diff --git a/global/timing.h b/global/timing.h deleted file mode 100644 index c42a45b5c..000000000 --- a/global/timing.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef TIMING_H -#define TIMING_H - -#include -#include - -class Clip; - -/** - * @brief Get timecode - * - * Get the current clip/media time from the Timeline playhead in seconds. For instance if the playhead was at the start - * of a clip (whose in point wasn't trimmed), this would be 0.0 as it's the start of the clip/media; - * - * @param c - * - * Clip to get the timecode of - * - * @param playhead - * - * Sequence playhead to convert to a clip/media timecode - * - * @return - * - * Timecode in seconds - */ -double get_timecode(Clip *c, long playhead); - -/** - * @brief Rescale a frame number between two frame rates - * - * Converts a frame number from one frame rate to its equivalent in another frame rate - * - * @param framenumber - * - * The frame number to convert - * - * @param source_frame_rate - * - * Frame rate that the frame number is currently in - * - * @param target_frame_rate - * - * Frame rate to convert to - * - * @return - * - * Rescaled frame number - */ -long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate); - -/** - * @brief Convert playhead frame number to a clip frame number - * - * Converts a Timeline playhead to a the current clip's frame. Equivalent to - * `PLAYHEAD - CLIP_TIMELINE_IN + CLIP_MEDIA_IN`. All keyframes are in clip frames. - * - * @param c - * - * The clip to get the current frame number of - * - * @param playhead - * - * The current Timeline frame number - * - * @return - * - * The curren frame number of the clip at `playhead` - */ -long playhead_to_clip_frame(Clip* c, long playhead); - -/** - * @brief Converts the playhead to clip seconds - * - * Get the current timecode at the playhead in terms of clip seconds. - * - * FIXME: Possible duplicate of get_timecode()? Will need to research this more. - * - * @param c - * - * Clip to return clip seconds of. - * - * @param playhead - * - * Current Timeline playhead to convert to clip seconds - * - * @return - * - * Clip time in seconds - */ -double playhead_to_clip_seconds(Clip *c, long playhead); - -/** - * @brief Convert seconds to FFmpeg timestamp - * - * Used for interaction with FFmpeg, converts seconds in a floating-point value to a timestamp in AVStream->time_base - * units. - * - * @param c - * - * Clip to get timestamp of - * - * @param seconds - * - * Clip time in seconds - * - * @return - * - * An FFmpeg-compatible timestamp in AVStream->time_base units. - */ -int64_t seconds_to_timestamp(Clip* c, double seconds); - -/** - * @brief Convert Timeline playhead to FFmpeg timestamp - * - * Used for interaction with FFmpeg, converts the Timeline playhead to a timestamp in AVStream->time_base - * units. - * - * @param c - * - * Clip to get timestamp of - * - * @param playhead - * - * Timeline playhead to convert to a timestamp - * - * @return - * - * An FFmpeg-compatible timestamp in AVStream->time_base units. - */ -int64_t playhead_to_timestamp(Clip *c, long playhead); - -bool frame_rate_is_droppable(double rate); -long timecode_to_frame(const QString& s, int view, double frame_rate); -QString frame_to_timecode(long f, int view, double frame_rate); - -#endif // TIMING_H diff --git a/nodes/inputs.h b/nodes/inputs.h deleted file mode 100644 index 796cbaffb..000000000 --- a/nodes/inputs.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef INPUTS_H -#define INPUTS_H - -#include "inputs/vecinput.h" -#include "inputs/boolinput.h" -#include "inputs/comboinput.h" -#include "inputs/colorinput.h" -#include "inputs/stringinput.h" -#include "inputs/fileinput.h" -#include "inputs/fontinput.h" - -#include "widgets/labelwidget.h" -#include "widgets/buttonwidget.h" - -#endif // INPUTS_H diff --git a/nodes/inputs/boolinput.cpp b/nodes/inputs/boolinput.cpp deleted file mode 100644 index e7be2f5a0..000000000 --- a/nodes/inputs/boolinput.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "boolinput.h" - -BoolInput::BoolInput(Node *parent, const QString& id, const QString& name, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable) -{ - BoolField* bool_field = new BoolField(this); - connect(bool_field, SIGNAL(Toggled(bool)), this, SIGNAL(Toggled(bool))); - AddField(bool_field); - - AddAcceptedNodeInput(olive::nodes::kBoolean); -} - -bool BoolInput::GetBoolAt(double timecode) -{ - return static_cast(Field(0))->GetBoolAt(timecode); -} diff --git a/nodes/inputs/boolinput.h b/nodes/inputs/boolinput.h deleted file mode 100644 index b49d9e36f..000000000 --- a/nodes/inputs/boolinput.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef BOOLINPUT_H -#define BOOLINPUT_H - -#include "nodes/nodeio.h" - -class BoolInput : public NodeIO -{ - Q_OBJECT -public: - BoolInput(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - /** - * @brief Get the boolean value at a given timecode - * - * A wrapper for BoolField::GetBoolAt(). - * - * @param timecode - * - * The timecode to retrieve the value at - * - * @return - * - * The boolean value at this timecode - */ - bool GetBoolAt(double timecode); - -signals: - /** - * @brief Emitted whenever the UI widget's boolean value has changed - * - * Wrapper for BoolField::Toggled(). - */ - void Toggled(bool); -}; - -#endif // BOOLINPUT_H diff --git a/nodes/inputs/colorinput.cpp b/nodes/inputs/colorinput.cpp deleted file mode 100644 index f7a57670d..000000000 --- a/nodes/inputs/colorinput.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "colorinput.h" - -ColorInput::ColorInput(Node *parent, const QString& id, const QString& name, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable) -{ - AddField(new ColorField(this)); - - AddAcceptedNodeInput(olive::nodes::kColor); -} - -QColor ColorInput::GetColorAt(double timecode) -{ - return static_cast(Field(0))->GetColorAt(timecode); -} diff --git a/nodes/inputs/colorinput.h b/nodes/inputs/colorinput.h deleted file mode 100644 index 2475ed7fe..000000000 --- a/nodes/inputs/colorinput.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef COLORINPUT_H -#define COLORINPUT_H - -#include "nodes/nodeio.h" - -class ColorInput : public NodeIO -{ - Q_OBJECT -public: - ColorInput(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - /** - * @brief Get the color value at a given timecode - * - * Wrapper for ColorField::GetColorAt(). - * - * @param timecode - * - * The timecode to retrieve the color at - * - * @return - * - * The color value at this timecode - */ - QColor GetColorAt(double timecode); -}; - -#endif // COLORINPUT_H diff --git a/nodes/inputs/comboinput.cpp b/nodes/inputs/comboinput.cpp deleted file mode 100644 index 3bc7798fb..000000000 --- a/nodes/inputs/comboinput.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "comboinput.h" - -ComboInput::ComboInput(Node *parent, const QString& id, const QString& name, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable) -{ - ComboField* combo_field = new ComboField(this); - connect(combo_field, SIGNAL(DataChanged(const QVariant&)), this, SIGNAL(DataChanged(const QVariant&))); - AddField(combo_field); - - AddAcceptedNodeInput(olive::nodes::kCombo); -} - -void ComboInput::AddItem(const QString &text, const QVariant &data) -{ - static_cast(Field(0))->AddItem(text, data); -} diff --git a/nodes/inputs/comboinput.h b/nodes/inputs/comboinput.h deleted file mode 100644 index c4417d49d..000000000 --- a/nodes/inputs/comboinput.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef COMBOINPUT_H -#define COMBOINPUT_H - -#include "nodes/nodeio.h" - -class ComboInput : public NodeIO -{ - Q_OBJECT -public: - ComboInput(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - /** - * @brief Add an item to this ComboInput - * - * Wrapper for ComboField::AddItem. - * - * @param text - * - * The text to show at this index. - * - * @param data - * - * The data to be retrieved at this index. - */ - void AddItem(const QString& text, const QVariant& data); - -signals: - /** - * @brief Signal emitted whenever a connected widget's data gets changed - * - * Wrapper for ComboField::DataChanged. - */ - void DataChanged(const QVariant&); -}; - -#endif // COMBOINPUT_H diff --git a/nodes/inputs/fileinput.cpp b/nodes/inputs/fileinput.cpp deleted file mode 100644 index 1974289ae..000000000 --- a/nodes/inputs/fileinput.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "fileinput.h" - -FileInput::FileInput(Node *parent, const QString& id, const QString& name, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable) -{ - AddField(new FileField(this)); - - AddAcceptedNodeInput(olive::nodes::kFile); -} - -QString FileInput::GetFileAt(double timecode) -{ - return static_cast(Field(0))->GetFileAt(timecode); -} diff --git a/nodes/inputs/fileinput.h b/nodes/inputs/fileinput.h deleted file mode 100644 index e7182b84d..000000000 --- a/nodes/inputs/fileinput.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FILEINPUT_H -#define FILEINPUT_H - -#include "nodes/nodeio.h" - -class FileInput : public NodeIO -{ - Q_OBJECT -public: - FileInput(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - /** - * @brief Get the filename at the given timecode - * - * A convenience function, equivalent to GetValueAt(timecode).toString() - * - * @param timecode - * - * The timecode to retrieve the filename at - * - * @return - * - * The filename at this timecode - */ - QString GetFileAt(double timecode); -}; - -#endif // FILEINPUT_H diff --git a/nodes/inputs/fontinput.cpp b/nodes/inputs/fontinput.cpp deleted file mode 100644 index fe1bd7b3c..000000000 --- a/nodes/inputs/fontinput.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "fontinput.h" - -FontInput::FontInput(Node *parent, const QString& id, const QString& name, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable) -{ - AddField(new FontField(this)); - - AddAcceptedNodeInput(olive::nodes::kFont); -} - -QString FontInput::GetFontAt(double timecode) -{ - return static_cast(Field(0))->GetFontAt(timecode); -} diff --git a/nodes/inputs/fontinput.h b/nodes/inputs/fontinput.h deleted file mode 100644 index d238eefef..000000000 --- a/nodes/inputs/fontinput.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FONTINPUT_H -#define FONTINPUT_H - -#include "nodes/nodeio.h" - -class FontInput : public NodeIO -{ - Q_OBJECT -public: - FontInput(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - /** - * @brief Get the font family name at the given timecode - * - * Wrapper for FontField::GetFontAt(). - * - * @param timecode - * - * The timecode to retrieve the font family name at - * - * @return - * - * The font family name at this timecode - */ - QString GetFontAt(double timecode); -}; - -#endif // FONTINPUT_H diff --git a/nodes/inputs/stringinput.cpp b/nodes/inputs/stringinput.cpp deleted file mode 100644 index 1989276b8..000000000 --- a/nodes/inputs/stringinput.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "stringinput.h" - -StringInput::StringInput(Node *parent, const QString& id, const QString& name, bool rich_text, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable) -{ - AddField(new StringField(this, rich_text)); - - AddAcceptedNodeInput(olive::nodes::kString); -} - -QString StringInput::GetStringAt(double timecode) -{ - return static_cast(Field(0))->GetStringAt(timecode); -} diff --git a/nodes/inputs/stringinput.h b/nodes/inputs/stringinput.h deleted file mode 100644 index 0f7d4c854..000000000 --- a/nodes/inputs/stringinput.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef STRINGINPUT_H -#define STRINGINPUT_H - -#include "nodes/nodeio.h" - -class StringInput : public NodeIO -{ - Q_OBJECT -public: - StringInput(Node* parent, - const QString& id, - const QString& name, - bool rich_text = true, - bool savable = true, - bool keyframable = true); - - /** - * @brief Get the string at the given timecode - * - * Wrappre for StringField::GetStringAt(). - * - * @param timecode - * - * The timecode to retrieve the string at - * - * @return - * - * The string at this timecode - */ - QString GetStringAt(double timecode); -}; - -#endif // STRINGINPUT_H diff --git a/nodes/inputs/vecinput.cpp b/nodes/inputs/vecinput.cpp deleted file mode 100644 index f9415fe87..000000000 --- a/nodes/inputs/vecinput.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "vecinput.h" - -#include -#include -#include - -VecInput::VecInput(Node *parent, const QString& id, const QString& name, int values, bool savable, bool keyframable) : - NodeIO(parent, id, name, savable, keyframable), - single_value_mode_(false), - values_(values) -{ - Q_ASSERT(values_ >= 1 && values_ <= 4); - - for (int i=0;i 1) { - AddAcceptedNodeInput(olive::nodes::kVec2); - } - if (values > 2) { - AddAcceptedNodeInput(olive::nodes::kVec3); - } - if (values > 3) { - AddAcceptedNodeInput(olive::nodes::kVec4); - } -} - -void VecInput::SetMinimum(double minimum) -{ - for (int i=0;i(Field(i))->SetMinimum(minimum); - } -} - -void VecInput::SetMaximum(double maximum) -{ - for (int i=0;i(Field(i))->SetMaximum(maximum); - } -} - -void VecInput::SetDefault(double def) -{ - for (int i=0;i(Field(i))->SetDefault(def); - } -} - -void VecInput::SetDefault(const QVector &def) -{ - for (int i=0;i(Field(i))->SetDefault(def.at(i)); - } -} - -void VecInput::SetDisplayType(LabelSlider::DisplayType type) -{ - for (int i=0;i(Field(i))->SetDisplayType(type); - } -} - -void VecInput::SetFrameRate(const double &rate) -{ - for (int i=0;i(Field(i))->SetFrameRate(rate); - } -} - -void VecInput::SetSingleValueMode(bool on) -{ - single_value_mode_ = on; - - // Disable all fields except the first - for (int i=1;iSetEnabled(!single_value_mode_); - } -} - -DoubleInput::DoubleInput(Node *parent, const QString &id, const QString &name, bool savable, bool keyframable) : - VecInput(parent, id, name, 1, savable, keyframable) -{ -} - -double DoubleInput::GetDoubleAt(double timecode) -{ - return static_cast(Field(0))->GetDoubleAt(timecode); -} - -Vec2Input::Vec2Input(Node *parent, const QString &id, const QString &name, bool savable, bool keyframable) : - VecInput(parent, id, name, 2, savable, keyframable) -{ -} - -QVector2D Vec2Input::GetVector2DAt(double timecode) -{ - return GetValueAt(timecode).value(); -} - -QVariant Vec2Input::GetValueAt(double timecode) -{ - QVector2D vec2; - vec2.setX(static_cast(Field(0))->GetDoubleAt(timecode)); - - if (single_value_mode_) { - vec2.setY(static_cast(Field(0))->GetDoubleAt(timecode)); - } else { - vec2.setY(static_cast(Field(1))->GetDoubleAt(timecode)); - } - - return vec2; -} - -void Vec2Input::SetValueAt(double timecode, const QVariant &value) -{ - QVector2D vec2 = value.value(); - - static_cast(Field(0))->SetValueAt(timecode, vec2.x()); - static_cast(Field(1))->SetValueAt(timecode, vec2.y()); -} - -Vec3Input::Vec3Input(Node *parent, const QString &id, const QString &name, bool savable, bool keyframable) : - VecInput(parent, id, name, 3, savable, keyframable) -{ -} - -QVector3D Vec3Input::GetVector3DAt(double timecode) -{ - return GetValueAt(timecode).value(); -} - -QVariant Vec3Input::GetValueAt(double timecode) -{ - QVector3D vec3; - vec3.setX(static_cast(Field(0))->GetDoubleAt(timecode)); - - if (single_value_mode_) { - vec3.setY(static_cast(Field(0))->GetDoubleAt(timecode)); - vec3.setZ(static_cast(Field(0))->GetDoubleAt(timecode)); - } else { - vec3.setY(static_cast(Field(1))->GetDoubleAt(timecode)); - vec3.setZ(static_cast(Field(2))->GetDoubleAt(timecode)); - } - - return vec3; -} - -void Vec3Input::SetValueAt(double timecode, const QVariant &value) -{ - QVector3D vec3 = value.value(); - - static_cast(Field(0))->SetValueAt(timecode, vec3.x()); - static_cast(Field(1))->SetValueAt(timecode, vec3.y()); - static_cast(Field(2))->SetValueAt(timecode, vec3.z()); -} - -Vec4Input::Vec4Input(Node *parent, const QString &id, const QString &name, bool savable, bool keyframable) : - VecInput(parent, id, name, 4, savable, keyframable) -{ -} - -QVector4D Vec4Input::GetVector4DAt(double timecode) -{ - return GetValueAt(timecode).value(); -} - -QVariant Vec4Input::GetValueAt(double timecode) -{ - QVector4D vec4; - vec4.setX(static_cast(Field(0))->GetDoubleAt(timecode)); - - if (single_value_mode_) { - vec4.setY(static_cast(Field(0))->GetDoubleAt(timecode)); - vec4.setZ(static_cast(Field(0))->GetDoubleAt(timecode)); - vec4.setZ(static_cast(Field(0))->GetDoubleAt(timecode)); - } else { - vec4.setY(static_cast(Field(1))->GetDoubleAt(timecode)); - vec4.setZ(static_cast(Field(2))->GetDoubleAt(timecode)); - vec4.setW(static_cast(Field(3))->GetDoubleAt(timecode)); - } - - return vec4; -} - -void Vec4Input::SetValueAt(double timecode, const QVariant &value) -{ - QVector4D vec4 = value.value(); - - static_cast(Field(0))->SetValueAt(timecode, vec4.x()); - static_cast(Field(1))->SetValueAt(timecode, vec4.y()); - static_cast(Field(2))->SetValueAt(timecode, vec4.z()); - static_cast(Field(3))->SetValueAt(timecode, vec4.w()); -} diff --git a/nodes/inputs/vecinput.h b/nodes/inputs/vecinput.h deleted file mode 100644 index 598e0872e..000000000 --- a/nodes/inputs/vecinput.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef VEC2INPUT_H -#define VEC2INPUT_H - -#include - -#include "nodes/nodeio.h" - -class VecInput : public NodeIO -{ - Q_OBJECT -public: - VecInput(Node* parent, const QString& id, const QString& name, int values, bool savable = true, bool keyframable = true); - - void SetMinimum(double minimum); - void SetMaximum(double maximum); - void SetDefault(double def); - - void SetDefault(const QVector &def); - - /** - * @brief Sets the UI display type to a member of LabelSlider::DisplayType. - */ - void SetDisplayType(LabelSlider::DisplayType type); - - /** - * @brief For a timecode-based display type, sets the frame rate to be used for the displayed timecode - * - * \see SetDisplayType() and LabelSlider::SetFrameRate(). - */ - void SetFrameRate(const double& rate); - -protected: - bool single_value_mode_; - -public slots: - void SetSingleValueMode(bool on); - -private: - - int values_; -}; - -class DoubleInput : public VecInput -{ -public: - DoubleInput(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - double GetDoubleAt(double timecode); -}; - -class Vec2Input : public VecInput { -public: - Vec2Input(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - QVector2D GetVector2DAt(double timecode); - virtual QVariant GetValueAt(double timecode) override; - virtual void SetValueAt(double timecode, const QVariant &value) override; -}; - -class Vec3Input : public VecInput { -public: - Vec3Input(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - QVector3D GetVector3DAt(double timecode); - virtual QVariant GetValueAt(double timecode) override; - virtual void SetValueAt(double timecode, const QVariant &value) override; -}; - -class Vec4Input : public VecInput { -public: - Vec4Input(Node* parent, const QString& id, const QString& name, bool savable = true, bool keyframable = true); - - QVector4D GetVector4DAt(double timecode); - virtual QVariant GetValueAt(double timecode) override; - virtual void SetValueAt(double timecode, const QVariant &value) override; -}; - -#endif // VEC2INPUT_H diff --git a/nodes/node.cpp b/nodes/node.cpp deleted file mode 100644 index 2a28b1e37..000000000 --- a/nodes/node.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "node.h" - -#include "nodegraph.h" - -Node::Node(NodeGraph *graph) : - QObject(graph) -{ -} - -QString Node::name() -{ - return tr("Node"); -} - -QString Node::id() -{ - return "node"; -} - -void Node::AddParameter(NodeIO *param) -{ - param->setParent(this); - parameters_.append(param); -} - -int Node::IndexOfParameter(NodeIO *param) -{ - return parameters_.indexOf(param); -} - -NodeIO *Node::Parameter(int i) -{ - return parameters_.at(i); -} - -int Node::ParameterCount() -{ - return parameters_.size(); -} - -double Node::Time() -{ - return 0; -} - -void Node::Process(const rational &time) -{ - Q_UNUSED(time) -} - -NodeGraph *Node::ParentGraph() -{ - return static_cast(parent()); -} - -const QPointF &Node::pos() -{ - return pos_; -} - -void Node::SetPos(const QPointF &pos) -{ - pos_ = pos; -} diff --git a/nodes/node.h b/nodes/node.h deleted file mode 100644 index 7fdbfc79d..000000000 --- a/nodes/node.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef NODE_H -#define NODE_H - -#include "nodes/nodeio.h" -#include "global/rational.h" - -class NodeGraph; - -class Node : public QObject -{ - Q_OBJECT -public: - Node(NodeGraph* parent); - - virtual QString name(); - virtual QString id(); - - virtual void Process(const rational& time); - - void AddParameter(NodeIO* row); - int IndexOfParameter(NodeIO* row); - NodeIO* Parameter(int i); - int ParameterCount(); - - double Time(); - - NodeGraph* ParentGraph(); - - const QPointF& pos(); - -public slots: - void SetPos(const QPointF& pos); - -private: - QVector parameters_; - QPointF pos_; -}; - -#endif // NODE_H diff --git a/nodes/nodedatatypes.cpp b/nodes/nodedatatypes.cpp deleted file mode 100644 index 18022f9fe..000000000 --- a/nodes/nodedatatypes.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "nodedatatypes.h" - -QString olive::nodes::DataTypeToString(DataType type) { - switch (type) { - case kFloat: - return "DOUBLE"; - case kVec2: - return "VEC2"; - case kVec3: - return "VEC3"; - case kVec4: - return "VEC4"; - case kArray: - return "ARRAY"; - case kColor: - return "COLOR"; - case kString: - return "STRING"; - case kBoolean: - return "BOOL"; - case kCombo: - return "COMBO"; - case kFont: - return "FONT"; - case kFile: - return "FILE"; - case kInteger: - return "INTEGER"; - case kTexture: - return "TEXTURE"; - case kMatrix: - return "MATRIX"; - case kBlock: - return "CLIP"; - default: - return QString(); - } -} - -olive::nodes::DataType olive::nodes::StringToDataType(const QString &s) -{ - if (s == "DOUBLE") { - return kFloat; - } else if (s == "VEC2") { - return kVec2; - } else if (s == "VEC3") { - return kVec3; - } else if (s == "VEC4") { - return kVec4; - } else if (s == "ARRAY") { - return kArray; - } else if (s == "COLOR") { - return kColor; - } else if (s == "STRING") { - return kString; - } else if (s == "BOOL") { - return kBoolean; - } else if (s == "COMBO") { - return kCombo; - } else if (s == "FONT") { - return kFont; - } else if (s == "FILE") { - return kFile; - } else if (s == "INTEGER") { - return kInteger; - } else if (s == "TEXTURE") { - return kTexture; - } else if (s == "MATRIX") { - return kMatrix; - } else if (s == "CLIP") { - return kBlock; - } - return kInvalid; -} diff --git a/nodes/nodedatatypes.h b/nodes/nodedatatypes.h deleted file mode 100644 index 8d542d659..000000000 --- a/nodes/nodedatatypes.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef NODEDATATYPES_H -#define NODEDATATYPES_H - -#include - -namespace olive { -namespace nodes { - -/** - * @brief The EffectFieldType enum - * - * Predetermined types of fields. Used throughout Olive to identify what kind of data to expect from GetValueAt(). - * - * This enum is also currently used to match an external XML effect's fields with the correct derived class (e.g. - * EFFECT_FIELD_DOUBLE matches to DoubleInput). - */ -enum DataType { - /** Invalid data type. Used only for error handling. */ - kInvalid, - - /** Values are doubles. Also corresponds to DoubleInput. */ - kFloat, - - /** Value is an 2-component vector of floats. */ - kVec2, - - /** Value is an 3-component vector of floats. */ - kVec3, - - /** Value is an 4-component vector of floats. */ - kVec4, - - /** Value is an array of floats. This cannot be an input field, and can only be passed between nodes. */ - kArray, - - /** Values are colors. Equivalent to kVec4 but represents as a color. Corresponds to ColorInput. */ - kColor, - - /** Values are strings. Also corresponds to StringInput. */ - kString, - - /** Values are booleans. Also corresponds to BoolInput. */ - kBoolean, - - /** Values are arbitrary data. Also corresponds to ComboInput. */ - kCombo, - - /** Values are font family names (in string). Also corresponds to FontInput. */ - kFont, - - /** Values are filenames (in string). Also corresponds to FileInput. */ - kFile, - - /** Values are integers. */ - kInteger, - - /** Value is a texture. This cannot be an input field, and can only be passed between nodes. */ - kTexture, - - /** Value is a 4x4 matrix. This cannot be an input field, and can only be passed between nodes. */ - kMatrix, - - /** Value is a Clip node */ - kBlock, - - /** Total count of valid node data types. Never use this as an actual data type. */ - kDataTypeCount -}; - -/** - * @brief Convert a node data type to a unique string that can be saved to an XML file - * - * @param type - * - * The data type to convert to string - * - * @return - * - * The unique string identifier for this data type. - */ -QString DataTypeToString(DataType type); - -/** - * @brief Convert a string to a node data type. - * - * Generally this string should be a string that was received from DataTypeToString() to ensure compatibility and - * correctness. - * - * @param s - * - * The string to convert to a data type - * - * @return - * - * The data type that this string represents - */ -DataType StringToDataType(const QString& s); - -} -} - -#endif // NODEDATATYPES_H diff --git a/nodes/nodeedge.cpp b/nodes/nodeedge.cpp deleted file mode 100644 index 83f597a21..000000000 --- a/nodes/nodeedge.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "nodeedge.h" - -#include - -#include "nodes/nodeio.h" - -NodeEdge::NodeEdge(NodeIO *output, NodeIO *input) : - output_(output), - input_(input) -{ -} - -NodeIO *NodeEdge::output() -{ - return output_; -} - -NodeIO *NodeEdge::input() -{ - return input_; -} diff --git a/nodes/nodeedge.h b/nodes/nodeedge.h deleted file mode 100644 index fb18b8326..000000000 --- a/nodes/nodeedge.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef NODEEDGE_H -#define NODEEDGE_H - -#include - -class NodeIO; - -class NodeEdge; -using NodeEdgePtr = std::shared_ptr; - -class NodeEdge -{ -public: - /** - * @brief NodeEdge Constructor - * - * Creates a node edge and stores its two connections. - * - * This should not be used directly. Use the static function EffectRow::ConnectEdge instead. - * - * @param output - * - * Output/from EffectRow that this edge "starts" at - * - * @param input - * - * Input/to EffectRow that this edge "ends" at - */ - NodeEdge(NodeIO* output, NodeIO* input); - - NodeIO* output(); - NodeIO* input(); - -private: - NodeIO* output_; - NodeIO* input_; -}; - -#endif // NODEEDGE_H diff --git a/nodes/nodegraph.cpp b/nodes/nodegraph.cpp deleted file mode 100644 index e65be0639..000000000 --- a/nodes/nodegraph.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "nodegraph.h" - -#include -#include - -NodeGraph::NodeGraph() : - output_node_(nullptr), - ctx_(nullptr) -{ - -} - -void NodeGraph::Process() -{ - if (output_node_ != nullptr) { - output_node_->Process(Time()); - } -} - -void NodeGraph::childEvent(QChildEvent *event) -{ - if (event->type() == QEvent::ChildAdded || event->type() == QEvent::ChildRemoved) { - emit NodeGraphChanged(); - } -} - -void NodeGraph::SetOutputNode(Node *node) -{ - output_node_ = node; -} - -Node *NodeGraph::OutputNode() -{ - return output_node_; -} - -const rational& NodeGraph::Time() -{ - return time_; -} - -void NodeGraph::SetTime(const rational &d) -{ - time_ = d; - emit TimeChanged(); -} - -ImageCache *NodeGraph::memory_cache() -{ - return &memory_cache_; -} - -QOpenGLContext *NodeGraph::GLContext() -{ - return ctx_; -} - -const int &NodeGraph::width() -{ - return width_; -} - -const int &NodeGraph::height() -{ - return height_; -} - -void NodeGraph::set_width(const int& w) -{ - width_ = w; - emit ParametersChanged(); -} - -void NodeGraph::set_height(const int& h) -{ - height_ = h; - emit ParametersChanged(); -} - -void NodeGraph::SetGLContext(QOpenGLContext *ctx) -{ - if (ctx_ != ctx) { - ctx_ = ctx; - memory_cache_.SetParameters(ctx, width_, height_); - } -} diff --git a/nodes/nodegraph.h b/nodes/nodegraph.h deleted file mode 100644 index d0506400a..000000000 --- a/nodes/nodegraph.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef NODEGRAPH_H -#define NODEGRAPH_H - -#include -#include - -#include "nodes/node.h" -#include "rendering/imagecache.h" - -class NodeGraph : public QObject -{ - Q_OBJECT -public: - NodeGraph(); - - const int& width(); - void set_width(const int& w); - - const int& height(); - void set_height(const int& h); - - /** - * @brief Process the graph - * - * Using the output node set by SetOutputNode(), this function will work backwards and perform every action in the - * node hierarchy necessary to eventually process the output node. After this function returns, the output node should - * contain valid values ready for accessing. - * - * Each node will cache its output for optimized playback and rendering. This will happen transparently and under most - * circumstances, this function will be able to return immediately. - */ - void Process(); - - /** - * @brief Set the output node for this node graph - * - * This node will be presented as the final node that all other nodes converge on. This node can be used to retrieve - * the result of the graph. - * - * @param node - * - * The node to set as the output node. The graph takes ownership of the node and the user cannot delete it. - */ - void SetOutputNode(Node* node); - - /** - * @brief Returns the currently set output node - */ - Node* OutputNode(); - - const rational &Time(); - void SetTime(const rational& d); - - ImageCache* memory_cache(); - - QOpenGLContext* GLContext(); - void SetGLContext(QOpenGLContext* ctx); - -signals: - void NodeGraphChanged(); - void TimeChanged(); - void ParametersChanged(); - -protected: - virtual void childEvent(QChildEvent *event) override; - -private: - Node* output_node_; - - ImageCache memory_cache_; - QOpenGLContext* ctx_; - - int width_; - int height_; - - rational time_; -}; - -#endif // NODEGRAPH_H diff --git a/nodes/nodeio.cpp b/nodes/nodeio.cpp deleted file mode 100644 index 7bfd63083..000000000 --- a/nodes/nodeio.cpp +++ /dev/null @@ -1,414 +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 "nodeio.h" - -#include -#include -#include - -#include "undo/undo.h" -#include "undo/undostack.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "panels/panels.h" -#include "panels/effectcontrols.h" -#include "panels/viewer.h" -#include "panels/grapheditor.h" -#include "nodes/oldeffectnode.h" -#include "ui/viewerwidget.h" -#include "ui/keyframenavigator.h" -#include "ui/clickablelabel.h" - -NodeIO::NodeIO(Node *parent, - const QString &id, - const QString &name, - bool savable, - bool keyframable) : - QObject(parent), - id_(id), - name_(name), - keyframable_(keyframable), - keyframing_(false), - savable_(savable), - output_type_(olive::nodes::kInvalid) -{ - Q_ASSERT(parent != nullptr); - - parent->AddParameter(this); -} - -void NodeIO::AddField(EffectField *field) -{ - field->setParent(this); - - connect(field, SIGNAL(Clicked()), this, SIGNAL(Clicked())); - connect(field, SIGNAL(Changed()), this, SIGNAL(Changed())); - - fields_.append(field); -} - -void NodeIO::AddAcceptedNodeInput(olive::nodes::DataType type) -{ - Q_ASSERT(output_type_ == olive::nodes::kInvalid); - - accepted_inputs_.append(type); -} - -void NodeIO::ConnectEdge(NodeIO *output, NodeIO *input) -{ - // Make sure one is an output and one is an input - Q_ASSERT(output->IsNodeInput() != input->IsNodeInput()); - - // Swap them if necessary - if (input->IsNodeOutput()) { - NodeIO* temp = output; - output = input; - input = temp; - } - - // Inputs can only have one edge, so we disconnect it here if there is one - if (!input->node_edges_.isEmpty()) { - DisconnectEdge(input->node_edges_.first()); - } - - NodeEdgePtr edge = std::make_shared(output, input); - - output->node_edges_.append(edge); - input->node_edges_.append(edge); - - emit output->EdgesChanged(); -} - -void NodeIO::DisconnectEdge(NodeEdgePtr edge) -{ - NodeIO* output = edge->output(); - NodeIO* input = edge->input(); - - output->node_edges_.removeAll(edge); - input->node_edges_.removeAll(edge); - - emit output->EdgesChanged(); -} - -QVector NodeIO::edges() -{ - return node_edges_; -} - -bool NodeIO::IsKeyframing() { - return keyframing_; -} - -void NodeIO::SetKeyframingInternal(bool b) { - /* FIXME - if (GetParentEffect()->type() != EFFECT_TYPE_TRANSITION) { - keyframing_ = b; - emit KeyframingSetChanged(keyframing_); - } - */ -} - -bool NodeIO::IsSavable() -{ - return savable_; -} - -bool NodeIO::IsKeyframable() -{ - return keyframable_; -} - -QVariant NodeIO::GetValue() -{ - return GetValueAt(0); -} - -QVariant NodeIO::GetValueAt(double timecode) -{ - if (FieldCount() == 0) { - return data_; - } - - Q_ASSERT(FieldCount() == 1); - - return Field(0)->GetValueAt(timecode); -} - -void NodeIO::SetValue(const QVariant &value) -{ - SetValueAt(0, value); -} - -void NodeIO::SetValueAt(double timecode, const QVariant &value) -{ - if (FieldCount() == 0) { - data_ = value; - return; - } - - Q_ASSERT(FieldCount() == 1); - - Field(0)->SetValueAt(timecode, value); -} - -void NodeIO::SetEnabled(bool enabled) -{ - for (int i=0;iSetEnabled(enabled); - } -} - -void NodeIO::SetOutputDataType(olive::nodes::DataType type) -{ - Q_ASSERT(accepted_inputs_.isEmpty()); - - output_type_ = type; -} - -bool NodeIO::CanAcceptDataType(olive::nodes::DataType type) -{ - if (!IsNodeInput()) { - return false; - } - - return accepted_inputs_.contains(type); -} - -olive::nodes::DataType NodeIO::OutputDataType() -{ - return output_type_; -} - -bool NodeIO::IsNodeInput() -{ - return !accepted_inputs_.isEmpty(); -} - -bool NodeIO::IsNodeOutput() -{ - return output_type_ != olive::nodes::kInvalid; -} - -void NodeIO::SetKeyframingEnabled(bool enabled) { - if (enabled == keyframing_) { - return; - } - - if (enabled) { - - ComboAction* ca = new ComboAction(); - - // Enable keyframing setting on this row - ca->append(new SetIsKeyframing(this, true)); - - // Prepare each field's data to start keyframing - for (int i=0;iPrepareDataForKeyframing(true, ca); - } - - olive::undo_stack.push(ca); - - update_ui(false); - - } else { - - // Confirm with the user whether they really want to disable keyframing - if (QMessageBox::question(panel_effect_controls, - tr("Disable Keyframes"), - tr("Disabling keyframes will delete all current keyframes. " - "Are you sure you want to do this?"), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - - ComboAction* ca = new ComboAction(); - - // Prepare each field's data to stop keyframing - for (int i=0;iPrepareDataForKeyframing(false, ca); - } - - // Disable keyframing setting on this row - ca->append(new SetIsKeyframing(this, false)); - - olive::undo_stack.push(ca); - - update_ui(false); - - } else { - - SetKeyframingInternal(true); - - } - } -} - -void NodeIO::GoToPreviousKeyframe() { - /* FIXME - long key = LONG_MIN; - Clip* c = GetParentEffect()->parent_clip; - long sequence_playhead = c->track()->sequence()->playhead; - - // Used to convert clip frame number to sequence frame number - long time_adjustment = c->timeline_in() - c->clip_in(); - - // Loop through all of this row's fields - for (int i=0;ikeyframes.size();j++) { - long comp = f->keyframes.at(j).time + time_adjustment; - - // Get the closest keyframe - if (comp < sequence_playhead) { - key = qMax(comp, key); - } - } - } - - // If we found a keyframe less than the playhead, jump to it - if (key != LONG_MIN) panel_sequence_viewer->seek(key); - */ -} - -void NodeIO::ToggleKeyframe() { - /* FIXME - Clip* c = GetParentEffect()->parent_clip; - long sequence_playhead = c->track()->sequence()->playhead; - - // Used to convert clip frame number to sequence frame number - long time_adjustment = c->timeline_in() - c->clip_in(); - - QVector key_fields; - QVector key_field_index; - - // See if any keyframes on any fields are at the current time - for (int j=0;jkeyframes.size();i++) { - long comp = f->keyframes.at(i).time + time_adjustment; - - if (comp == sequence_playhead) { - - // Cache the keyframes if they are at the current time - key_fields.append(f); - key_field_index.append(i); - - } - } - } - - ComboAction* ca = new ComboAction(); - - if (key_fields.isEmpty()) { - - // If we didn't find any current keyframes, create one for each field - SetKeyframeOnAllFields(ca); - - } else { - - // If we DID find keyframes at this time, delete them - - QVector sorted_key_fields; - QVector sorted_key_field_index; - - // Since QVectors shift themselves when removing items, we need to sort these in reverse order - for (int i=0;iappend(new KeyframeDelete(sorted_key_fields.at(i), sorted_key_field_index.at(i))); - } - - } - - olive::undo_stack.push(ca); - update_ui(false); - */ -} - -void NodeIO::GoToNextKeyframe() { - /* FIXME - long key = LONG_MAX; - Clip* c = GetParentEffect()->parent_clip; - for (int i=0;ikeyframes.size();j++) { - long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp > c->track()->sequence()->playhead) { - key = qMin(comp, key); - } - } - } - if (key != LONG_MAX) panel_sequence_viewer->seek(key); - */ -} - -void NodeIO::FocusRow() { - panel_graph_editor->set_row(this); -} - -Node* NodeIO::ParentNode() { - return static_cast(parent()); -} - -void NodeIO::SetKeyframeOnAllFields(ComboAction* ca) { - for (int i=0;iSetValueAt(ParentNode()->Time(), field->GetValueAt(ParentNode()->Time())); - - kdc->SetNewKeyframes(); - ca->append(kdc); - } - - panel_effect_controls->update_keyframes(); -} - -const QString &NodeIO::name() { - return name_; -} - -EffectField* NodeIO::Field(int i) { - return fields_.at(i); -} - -int NodeIO::FieldCount() { - return fields_.size(); -} diff --git a/nodes/nodeio.h b/nodes/nodeio.h deleted file mode 100644 index 68240a1f8..000000000 --- a/nodes/nodeio.h +++ /dev/null @@ -1,491 +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 EFFECTROW_H -#define EFFECTROW_H - -#include -#include - -class Node; -class QGridLayout; -class EffectField; -class QLabel; -class QPushButton; -class ComboAction; -class QHBoxLayout; -class KeyframeNavigator; -class ClickableLabel; - -#include "effects/effectfields.h" -#include "nodes/nodeedge.h" - -/** - * @brief The EffectRow class - * - * Primarily a way of grouping EffectField objects together. As UI objects, Effects are largely formatted as a table - * and you can think of EffectRows as the rows of the table and EffectFields as the columns. - * - * Within Olive, keyframing is enabled on the EffectRow (rather than individual EffectFields) so all attached fields - * will be keyframed together. - * - * Unlike EffectField, there's no reason to derive from EffectRow as it's simply a container of fields and a few - * keyframe functions. - */ -class NodeIO : public QObject { - Q_OBJECT -public: - - /** - * @brief EffectRow Constructor - * - * @param parent - * - * Every EffectRow object must be attached to a valid Effect object. The Effect object takes ownership of the - * EffectRow and automatically frees it through the QObject parent/child system. EffectRows are never intended to - * change parents throughout their lifetimes. - * - * @param id - * - * Field ID. Must be non-empty. Must also be unique within this Effect. Used for saving/loading values into project - * files so that if ordering of fields are changed, or fields are added/removed from Effects later in development, - * saved values in project files will still link with the correct field. Also used as the uniform variable name - * in GLSL shaders. - * - * @param name - * - * Row name. This is not used as an internal identifier, it's just for the user interface, so it can be translated - * with no issue. - * - * @param savable - * - * Whether the fields in this row should be saved to the project file. This is true by default. If the row contains - * non-value UI widgets, setting this to false is recommended. - * - * @param keyframable - * - * Whether keyframing can be enabled on this row or not. This is true by default. Some values you may want to prevent - * the user from keyframing (e.g. the filename of a VST plugin), which can be done by setting this to false. - */ - NodeIO(Node* parent, - const QString& id, - const QString& name, - bool savable = true, - bool keyframable = true); - - /** - * @brief Retrieve the EffectField at this index. Must be less than FieldCount(). - * - * @param i - * - * Index to retrieve the EffectField at. - * - * @return - * - * EffectField at the provided index. - */ - EffectField* Field(int i); - - /** - * @brief Number of fields currently contained in this row. - * - * @return The number of fields currently contained in this row as an integer. Any field index (retrieved with - * Field()) is guaranteed to be valid >= 0 and < FieldCount(). - */ - int FieldCount(); - - /** - * @brief Set a keyframe at the current playhead on all fields contained within this row - * - * @param ca - * - * The ComboAction to add this action to. This may not be nullptr. - */ - void SetKeyframeOnAllFields(ComboAction *ca); - - /** - * @brief Get parent Effect - * - * Equivalent to `static_cast(parent())`. - * - * @return The parent Effect object that this row is attached to. - */ - Node* ParentNode(); - - /** - * @brief Return the row's name - * - * @return The name specified in the constructor as a QString - */ - const QString& name(); - - /** - * @brief Get the unique identifier of this field set in the constructor - * - * Mostly used for saving/loading or interacting with GLSL-based shader effects (see EffectField() for more details). - * - * @return - */ - const QString& id(); - - /** - * @brief Get whether this row is keyframing or not - * - * @return True if this row is keyframing. - */ - bool IsKeyframing(); - - /** - * @brief Set whether this row is keyframing or not. - * - * It's not recommended to use this function for any user-initiated keyframe setting change as it doesn't create any - * undoable actions. Use SetKeyframingEnabled() instead for a user-friendly variant. - */ - void SetKeyframingInternal(bool); - - /** - * @brief Get whether this row should be saved into a project file or not - * - * @return True if this row should be saved. This value is set in the constructor. - */ - bool IsSavable(); - - /** - * @brief Get whether this row can be keyframed or not. - * - * @return True if this row can be keyframed. This value is set in the constructor. - */ - bool IsKeyframable(); - - /** - * @brief Get value - * - * A convenience value for a parameters that doesn't keyframe. Equivalent to GetValueAt(0) where the parameter - * doesn't keyframe so the 0 is ignored. - * - * @param value - */ - QVariant GetValue(); - - /** - * @brief Get value at a given timecode - * - * Functions as a wrapper for EffectField::GetValueAt(). - * - * The default function is to return the result of the first EffectField on this EffectRow which should be sufficient - * for most input types. If this EffectRow has more or less than one EffectField, you must override this function in a - * derived class to provide the correct field <-> row coordination or else it will trigger an abort. - * - * @param timecode - * - * Timecode to get the value at - * - * @return - * - * The value of the first EffectField at the given timecode - */ - virtual QVariant GetValueAt(double timecode); - - /** - * @brief Set value - * - * A convenience value for a parameters that doesn't keyframe. Equivalent to SetValueAt(0, value) where the parameter - * doesn't keyframe so the 0 is ignored. - * - * @param value - */ - void SetValue(const QVariant& value); - - /** - * @brief SetValueAt - * - * Functions as a wrapper for EffectField::SetValueAt(). - * - * The default function is to call the function of the first EffectField on this EffectRow which should be sufficient - * for most input types. If this EffectRow has more or less than one EffectField, you must override this function in a - * derived class to provide the correct field <-> row coordination or else it will trigger an abort. - * - * @param timecode - * - * Timecode to set the value at - * - * @param value - * - * Value to set at this timecode - */ - virtual void SetValueAt(double timecode, const QVariant& value); - - /** - * @brief Sets the enabled state on all EffectField objects on this row to enabled - */ - void SetEnabled(bool enabled); - - /** - * @brief Check if nodes can be connected to this as an input. - * - * Connecting is enabled by adding an accepted node input using AddNodeInput(). - * - * @return - * - * TRUE if nodes can be connected as an input. - */ - bool IsNodeInput(); - - /** - * @brief Check if nodes can be connected to this as an output - * - * Connecting is enabled by setting an output data type in SetOutputDataType(). - * - * @return - * - * TRUE if nodes can be connected as an output - */ - bool IsNodeOutput(); - - /** - * @brief Set output data type - * - * Set the type of data this row outputs to type - */ - void SetOutputDataType(olive::nodes::DataType type); - - /** - * @brief Check if this row can accept the data type specified in type - * - * @return - * - * TRUE if this row can accept this data type. If this row is not an input, this function will always return FALSE. - */ - bool CanAcceptDataType(olive::nodes::DataType type); - - /** - * @brief Get this row's output data type - * - * @return - * - * If this is not an output, this will always return olive::nodes::kInvalid - */ - olive::nodes::DataType OutputDataType(); - - /** - * @brief Adds a node data type that can be accepted by this input - * - * Allows this input to take a node connection from a data type specified by type. An input can take several data - * types. - * - * @param type - * - * The data type to add - */ - void AddAcceptedNodeInput(olive::nodes::DataType type); - - /** - * @brief Connect two node sockets together - * - * For outputs, the maximum amount of edges is unlimited and this will continually add to a list of edges. For inputs, - * there can only be one edge and adding a second will destroy the first. - * - * @param edge - * - * The edge to add (output) or replace the current edge (input). - */ - static void ConnectEdge(NodeIO* output, NodeIO* input); - - /** - * @brief Disconnect an edge - * - * Disconnects two nodes and destroys the edge object connecting them together - * - * @param edge - * - * Edge to be removed - */ - static void DisconnectEdge(NodeEdgePtr edge); - - /** - * @brief Get a list of references to all edges currently connected to this row - */ - QVector edges(); - -protected: - /** - * @brief Add a field to this row - * - * Ownership of the EffectField is transferred to this row and the row will free its memory. In the Effect's UI, this - * will add the field to an additional column. - * - * @param Field - * - * The field to add to this row. - */ - void AddField(EffectField* Field); - -public slots: - /** - * @brief Go to previous keyframe - * - * Gets the closest keyframe prior to the current playhead and seeks to it. - * - * Attach to KeyframeNavigator::goto_previous_key() signal. - */ - void GoToPreviousKeyframe(); - - /** - * @brief Toggle a keyframe at this point in time - * - * Either deletes (if any child EffectFields have any keyframes here) or creates (if none do) a keyframe on all - * EffectField children at the current time. - * - * Attach to KeyframeNavigator::toggle_key() signal. - */ - void ToggleKeyframe(); - - /** - * @brief Go to next keyframe - * - * Gets the closest keyframe after the current playhead and seeks to it. - * - * Attach to KeyframeNavigator::goto_next_key() signal. - */ - void GoToNextKeyframe(); - - /** - * @brief Slot for whenever this EffectRow is focused. - * - * Connect UI objects gaining focus to this slot. Automatically updates the Graph Editor to attach to this row. - */ - void FocusRow(); -signals: - - /** - * @brief Keyframing setting changed signal - * - * Emitted whenever keyframing is enabled or disabled. - * - * @param - * - * True if keyframing was enabled, false if keyframing was disabled. - */ - void KeyframingSetChanged(bool); - - /** - * @brief Changed signal - * - * Wrapper for EffectField::Changed(). - */ - void Changed(); - - /** - * @brief Clicked signal - * - * Wrapper for EffectField::Clicked(). - */ - void Clicked(); - - /** - * @brief Edges changed signal - * - * Signal emitted any time an edge is connected or disconnected from this row - */ - void EdgesChanged(); - -private slots: - /** - * @brief Set keyframing enabled state - * - * A user-friendly function for enabling or disabling keyframes on this row. Preferred to SetKeyframingInternal() - * for any user-initiated change. Automatically creates an undoable action so users can undo the enabling/disabling. - * Also confirms with the user when disabling keyframing whether they wish to continue and remove all the current - * keyframes. - * - * Attach to KeyframeNavigator::keyframe_enabled_changed() signal. - */ - void SetKeyframingEnabled(bool); -private: - - /** - * @brief Internal unique identifier for this field set in the constructor. Access with id(). - */ - QString id_; - - /** - * @brief Internal variable for the row's name - * - * Set in the constructor, retrieved with name(). - */ - QString name_; - - /** - * @brief Internal variable for whether this row can be keyframed. - * - * Set in the constructor, retrieved with IsKeyframable(). - */ - bool keyframable_; - - /** - * @brief Internal variable for whether this row is currently keyframing. - * - * Set by SetKeyframingInternal() and retrieved with IsKeyframing(). - */ - bool keyframing_; - - /** - * @brief Internal variable for whether this row should be saved. - * - * Set in the constructor, retrieved with IsSavable(). - */ - bool savable_; - - /** - * @brief Internal array of EffectField objects. - * - * It is not necessary to delete the elements in this array as they're already children of this QObject, so they'll - * get freed automatically. - */ - QVector fields_; - - /** - * @brief Internal array of accepted node data types. - * - * Is mutally-exclusive with accepted_outputs_, i.e. you cannot have values added to this and also a value set in - * accepted_outputs_. - */ - QVector accepted_inputs_; - - /** - * @brief Internal value for what kind of data this row outputs - * - * Is mutally-exclusive with accepted_inputs_, i.e. you cannot have values added to it and also a value set in - * this. - */ - olive::nodes::DataType output_type_; - - /** - * @brief Internal array of node edges. Access with AddEdge() and RemoveEdge(). - */ - QVector node_edges_; - - /** - * @brief Internal data object for rows without fields - */ - QVariant data_; -}; - -#endif // EFFECTROW_H diff --git a/nodes/nodes.h b/nodes/nodes.h deleted file mode 100644 index 998fd900d..000000000 --- a/nodes/nodes.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef NODES_H -#define NODES_H - -#include "nodes/nodemedia.h" -#include "nodes/nodetexturepassthru.h" -#include "nodes/nodeshader.h" - -#endif // NODES_H diff --git a/nodes/nodes/nodeblock.cpp b/nodes/nodes/nodeblock.cpp deleted file mode 100644 index d22875463..000000000 --- a/nodes/nodes/nodeblock.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "nodeblock.h" - -NodeBlock::NodeBlock(NodeGraph *graph) : - Node(graph) -{ - previous_block_ = new NodeIO(this, "prev_block", tr("Previous"), true, false); - previous_block_->AddAcceptedNodeInput(olive::nodes::kBlock); - previous_block_->SetValue(0); - AddParameter(previous_block_); - - next_block_ = new NodeIO(this, "next_block", tr("Next"), true, false); - next_block_->SetOutputDataType(olive::nodes::kBlock); - next_block_->SetValue(0); - AddParameter(next_block_); -} - -rational NodeBlock::track_in() -{ - rational in_point; - - NodeBlock* previous = previous_block(); - while (previous != nullptr) { - in_point += previous->length(); - } - - return in_point; -} - -rational NodeBlock::track_out() -{ - return track_in() + length(); -} - -const rational &NodeBlock::length() -{ - return length_; -} - -void NodeBlock::set_length(const rational &l) -{ - length_ = l; -} - -QString NodeBlock::name() -{ - return tr("Block"); -} - -QString NodeBlock::id() -{ - return "block"; -} - -NodeBlock *NodeBlock::previous_block() -{ - return reinterpret_cast(previous_block_->GetValue().value()); -} - -void NodeBlock::set_previous_block(NodeBlock *p) -{ - previous_block_->SetValue(reinterpret_cast(p)); -} - -NodeBlock *NodeBlock::next_block() -{ - return reinterpret_cast(next_block_->GetValue().value()); -} - -void NodeBlock::set_next_block(NodeBlock *p) -{ - next_block_->SetValue(reinterpret_cast(p)); -} diff --git a/nodes/nodes/nodeblock.h b/nodes/nodes/nodeblock.h deleted file mode 100644 index db67861f1..000000000 --- a/nodes/nodes/nodeblock.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef NODEBLOCK_H -#define NODEBLOCK_H - -#include "global/rational.h" -#include "nodes/node.h" - -/** - * @brief The NodeBlock class - * - * A "Block" node is a node with a timed in-point and out-point that can appear on the Timeline. - */ -class NodeBlock : public Node -{ - Q_OBJECT -public: - NodeBlock(NodeGraph* graph); - - rational track_in(); - rational track_out(); - - const rational& length(); - void set_length(const rational& l); - - virtual QString name() override; - virtual QString id() override; - - /** - * @brief Retrieves the NodeBlock connected to the "Previous" parameter - */ - NodeBlock* previous_block(); - void set_previous_block(NodeBlock* p); - - /** - * @brief Retrieves the NodeBlock connected to the "Next" parameter - */ - NodeBlock* next_block(); - void set_next_block(NodeBlock* p); - - - -private: - rational length_; - - NodeIO* previous_block_; - NodeIO* next_block_; -}; - -#endif // NODEBLOCK_H diff --git a/nodes/nodes/nodeclip.cpp b/nodes/nodes/nodeclip.cpp deleted file mode 100644 index b68d4edd6..000000000 --- a/nodes/nodes/nodeclip.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "nodeclip.h" - -NodeClip::NodeClip(NodeGraph *graph) : - Node(graph) -{ - -} diff --git a/nodes/nodes/nodeclip.h b/nodes/nodes/nodeclip.h deleted file mode 100644 index 242cb88b2..000000000 --- a/nodes/nodes/nodeclip.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef NODECLIP_H -#define NODECLIP_H - -#include "nodes/node.h" - -class NodeClip : public Node -{ -public: - NodeClip(NodeGraph* graph); - - long in(); - long out(); - long clip_in(); - - void set_in(long in); - void set_out(long out); - void set_clip_in(long clip_in); - -private: - long in_; - long out_; - long clip_in_; -}; - -#endif // NODECLIP_H diff --git a/nodes/nodes/nodemedia.cpp b/nodes/nodes/nodemedia.cpp deleted file mode 100644 index 8b1458d99..000000000 --- a/nodes/nodes/nodemedia.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "nodemedia.h" - -#include - -#include "nodes/nodegraph.h" -#include "decoders/ffmpegvideodecoder.h" -#include "decoders/pixelformatconverter.h" -#include "global/config.h" -#include "global/global.h" - -NodeMedia::NodeMedia(NodeGraph* c) : - Node(c), - media_(nullptr), - img_buffer_(c->memory_cache()), - tex_buffer_(c->memory_cache()), - decoder_(nullptr) -{ - matrix_input_ = new NodeIO(this, "matrix", tr("Matrix"), true, false); - matrix_input_->AddAcceptedNodeInput(olive::nodes::kMatrix); - - texture_output_ = new NodeIO(this, "texture", tr("Texture"), true, false); - texture_output_->SetOutputDataType(olive::nodes::kTexture); -} - -QString NodeMedia::name() -{ - return tr("Media"); -} - -QString NodeMedia::id() -{ - return "org.olivevideoeditor.Olive.media"; -} - -void NodeMedia::Process(const rational &time) -{ - QOpenGLFunctions* f = ParentGraph()->GLContext()->functions(); - - tex_buffer_.buffer()->BindBuffer(); - - f->glClearColor(0.0, 0.5, 0.0, 0.0); - f->glClear(GL_COLOR_BUFFER_BIT); - - tex_buffer_.buffer()->ReleaseBuffer(); - - FramePtr frame = decoder_->Retrieve(time); - - olive::pix_fmt_conv->AVFrameToPipeline(frame->data(), - frame->linesize(), - frame->width(), - frame->height(), - static_cast(frame->format()), - img_buffer_.buffer()->data(), - olive::Global->effective_bit_depth()); - - const olive::PixelFormatInfo& pix_fmt_info = olive::pixel_formats.at(olive::Global->effective_bit_depth()); - - tex_buffer_.buffer()->BindTexture(); - - f->glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - frame->width(), - frame->height(), - pix_fmt_info.pixel_format, - pix_fmt_info.pixel_type, - img_buffer_.buffer()->data() - ); - - tex_buffer_.buffer()->ReleaseTexture(); - - qDebug() << "Uploaded to texture" << tex_buffer_.buffer()->texture(); - - texture_output_->SetValue(tex_buffer_.buffer()->texture()); -} - -void NodeMedia::SetMedia(FootageStream *f) -{ - // TODO method of finding the decoder we need - - decoder_ = std::make_shared(); - - media_ = f; - - decoder_->set_stream(media_); - - img_buffer_.SetSize(f->video_width, f->video_height); -} - -NodeIO *NodeMedia::matrix_input() -{ - return matrix_input_; -} - -NodeIO *NodeMedia::texture_output() -{ - return texture_output_; -} - - diff --git a/nodes/nodes/nodemedia.h b/nodes/nodes/nodemedia.h deleted file mode 100644 index 36f218333..000000000 --- a/nodes/nodes/nodemedia.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef MEDIANODE_H -#define MEDIANODE_H - -#include "nodes/node.h" -#include "rendering/imagecache.h" -#include "project/media.h" -#include "decoders/decoder.h" - -/** - * @brief The NodeMedia class - * - * The NodeMedia node is the main entry point for external video/audio files into the Olive pipeline. Its - * responsibilities are as follows: - * - * * Use a Decoder to retrieve the correct raw frame data - * * Convert the frame data to the pipeline format (usually RGBA16F or RGBA32F) - * * Convert the frame to scene linear colorspace with OpenColorIO - * - * Naturally this Node is resource intensive and effort should be spent here to make this as performant as possible. - */ -class NodeMedia : public Node -{ - Q_OBJECT -public: - NodeMedia(NodeGraph *c); - - virtual QString name() override; - virtual QString id() override; - - virtual void Process(const rational& time) override; - - void SetMedia(FootageStream* f); - - NodeIO* matrix_input(); - NodeIO* texture_output(); - -private: - // Matrix input for the transformation to apply to this media (if any) - NodeIO* matrix_input_; - - // Texture output - NodeIO* texture_output_; - - // Media object to display - FootageStream* media_; - - // Texture buffer - // TODO Probable cache point - ImageCache::ImgRef img_buffer_; - ImageCache::TexRef tex_buffer_; - - // Decoder - DecoderPtr decoder_; -}; - -#endif // MEDIANODE_H diff --git a/nodes/nodes/nodeshader.cpp b/nodes/nodes/nodeshader.cpp deleted file mode 100644 index b68f41b01..000000000 --- a/nodes/nodes/nodeshader.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "nodeshader.h" - -NodeShader::NodeShader(Clip* c, - const QString &name, - const QString &id, - const QString &category, - const QString &filename) : - OldEffectNode(c), - name_(name), - id_(id), - category_(category), - filename_(filename) -{ - if (!filename_.isEmpty()) { - QFile effect_file(filename_); - if (effect_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&effect_file); - - while (!reader.atEnd()) { - if (reader.name() == "field" && reader.isStartElement()) { - int type = olive::nodes::kInvalid; - QString id; - QString name; - - // get field type - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;iSetDefault(attr.value().toDouble()); - } else if (attr.name() == "min") { - double_field->SetMinimum(attr.value().toDouble()); - } else if (attr.name() == "max") { - double_field->SetMaximum(attr.value().toDouble()); - } - } - - field = double_field; - } - break; - case olive::nodes::kColor: - { - QColor color; - - field = new ColorInput(this, id, name); - - for (int i=0;iSetValueAt(0, color); - } - break; - case olive::nodes::kString: - field = new StringInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - case olive::nodes::kBoolean: - field = new BoolInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value() == "1"); - } - } - break; - case olive::nodes::kCombo: - { - ComboInput* combo_field = new ComboInput(this, id, name); - int combo_default_index = 0; - for (int i=0;iAddItem(reader.text().toString(), combo_item_count); - combo_item_count++; - } - } - combo_field->SetValueAt(0, combo_default_index); - field = combo_field; - } - break; - case olive::nodes::kFont: - field = new FontInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - case olive::nodes::kFile: - field = new FileInput(this, id, name); - for (int i=0;iSetValueAt(0, attr.value().toString()); - } - } - break; - } - } - } else if (reader.name() == "shader" && reader.isStartElement()) { - SetFlags(Flags() | ShaderFlag); - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;iAddAcceptedNodeInput(olive::nodes::kTexture); - - texture_output_ = new NodeIO(this, "tex_out", tr("Texture"), true, false); - texture_output_->SetOutputDataType(olive::nodes::kTexture); -} - -QString NodeTexturePassthru::name() -{ - return tr("Image Output"); -} - -QString NodeTexturePassthru::id() -{ - return "org.olivevideoeditor.Olive.imageoutput"; -} - -void NodeTexturePassthru::Process(const rational &time) -{ - Q_UNUSED(time) - - texture_output_->SetValue(texture_input_->GetValue()); -} - -NodeIO *NodeTexturePassthru::texture_input() -{ - return texture_input_; -} - -NodeIO *NodeTexturePassthru::texture_output() -{ - return texture_output_; -} diff --git a/nodes/nodes/nodetexturepassthru.h b/nodes/nodes/nodetexturepassthru.h deleted file mode 100644 index 41d1797bc..000000000 --- a/nodes/nodes/nodetexturepassthru.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef NODEIMAGEOUTPUT_H -#define NODEIMAGEOUTPUT_H - -#include "nodes/node.h" - -class NodeTexturePassthru : public Node -{ -public: - NodeTexturePassthru(NodeGraph* c); - - virtual QString name() override; - virtual QString id() override; - - virtual void Process(const rational& time) override; - - NodeIO* texture_input(); - NodeIO* texture_output(); - -private: - NodeIO* texture_input_; - NodeIO* texture_output_; -}; - -#endif // NODEIMAGEOUTPUT_H diff --git a/nodes/nodes/nodevideoclip.cpp b/nodes/nodes/nodevideoclip.cpp deleted file mode 100644 index 1de6a659d..000000000 --- a/nodes/nodes/nodevideoclip.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "nodevideoclip.h" - -NodeVideoClip::NodeVideoClip(NodeGraph *parent) : - NodeBlock(parent) -{ - texture_input_ = new NodeIO(this, "texture", tr("Texture"), true, false); - texture_input_->AddAcceptedNodeInput(olive::nodes::kTexture); - - texture_output_ = new NodeIO(this, "texture", tr("Texture"), true, false); - texture_output_->SetOutputDataType(olive::nodes::kTexture); -} - -NodeIO *NodeVideoClip::texture_output() -{ - return texture_output_; -} diff --git a/nodes/nodes/nodevideoclip.h b/nodes/nodes/nodevideoclip.h deleted file mode 100644 index 874922581..000000000 --- a/nodes/nodes/nodevideoclip.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef NODEVIDEOCLIP_H -#define NODEVIDEOCLIP_H - -#include "nodeblock.h" - -class NodeVideoClip : public NodeBlock -{ -public: - NodeVideoClip(NodeGraph* parent); - - NodeIO* texture_input(); - NodeIO* texture_output(); - -private: - NodeIO* texture_input_; - NodeIO* texture_output_; -}; - -#endif // NODEVIDEOCLIP_H diff --git a/nodes/oldeffectnode.cpp b/nodes/oldeffectnode.cpp deleted file mode 100644 index e561e3381..000000000 --- a/nodes/oldeffectnode.cpp +++ /dev/null @@ -1,920 +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 "oldeffectnode.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "panels/panels.h" -#include "panels/viewer.h" -#include "ui/viewerwidget.h" -#include "ui/collapsiblewidget.h" -#include "panels/project.h" -#include "undo/undo.h" -#include "timeline/sequence.h" -#include "timeline/clip.h" -#include "panels/timeline.h" -#include "panels/effectcontrols.h" -#include "panels/grapheditor.h" -#include "global/debug.h" -#include "global/path.h" -#include "ui/mainwindow.h" -#include "ui/menu.h" -#include "global/math.h" -#include "global/clipboard.h" -#include "global/config.h" -#include "effects/transition.h" -#include "undo/undostack.h" -#include "rendering/shadergenerators.h" -#include "global/timing.h" -#include "nodes/nodes.h" -#include "effects/effectloaders.h" - -QVector olive::node_library; - -OldEffectNode::OldEffectNode(Clip *c) : - Node(nullptr), - parent_clip(c), - flags_(0), - shader_program_(nullptr), - texture(0), - tex_width_(0), - tex_height_(0), - isOpen(false), - bound(false), - iterations(1), - enabled_(true), - expanded_(true), - texture_ctx(nullptr) -{ -} - -OldEffectNode::~OldEffectNode() { - if (isOpen) { - close(); - } - - // Clear graph editor if it's using one of these rows - if (panel_graph_editor != nullptr) { - for (int i=0;iget_row()) { - panel_graph_editor->set_row(nullptr); - break; - } - } - } -} - -QString OldEffectNode::category() -{ - return QString(); -} - -QString OldEffectNode::description() -{ - return QString(); -} - -bool OldEffectNode::IsCreatable() -{ - return true; -} - -void OldEffectNode::copy_field_keyframes(OldEffectNodePtr e) { - for (int i=0;iParameter(i); - copy_row->SetKeyframingInternal(row->IsKeyframing()); - for (int j=0;jFieldCount();j++) { - // Get field from this (the source) effect - EffectField* field = row->Field(j); - - // Get field from the destination effect - EffectField* copy_field = copy_row->Field(j); - - // Copy keyframes between effects - copy_field->keyframes = field->keyframes; - - // Copy persistet data between effects - copy_field->persistent_data_ = field->persistent_data_; - } - } -} - -EffectGizmo *OldEffectNode::add_gizmo(int type) { - EffectGizmo* gizmo = new EffectGizmo(this, type); - gizmos.append(gizmo); - return gizmo; -} - -EffectGizmo *OldEffectNode::gizmo(int i) { - return gizmos.at(i); -} - -int OldEffectNode::gizmo_count() { - return gizmos.size(); -} - -QVector OldEffectNode::GetAllEdges() -{ - QVector edges; - - for (int i=0;iedges()); - } - - return edges; -} - -void OldEffectNode::refresh() {} - -void OldEffectNode::FieldChanged() { - // Update the UI if a field has been modified, but don't both if this effect is inactive - if (parent_clip != nullptr) { - update_ui(false); - } -} - -void OldEffectNode::delete_self() { - olive::undo_stack.push(new EffectDeleteCommand(this)); - update_ui(true); -} - -void OldEffectNode::move_up() { - int index_of_effect = parent_clip->IndexOfEffect(this); - if (index_of_effect == 0) { - return; - } - - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = index_of_effect; - command->to = command->from - 1; - olive::undo_stack.push(command); - panel_effect_controls->Reload(); - panel_sequence_viewer->viewer_widget()->frame_update(); -} - -void OldEffectNode::move_down() { - int index_of_effect = parent_clip->IndexOfEffect(this); - if (index_of_effect == parent_clip->effects.size()-1) { - return; - } - - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = index_of_effect; - command->to = command->from + 1; - olive::undo_stack.push(command); - panel_effect_controls->Reload(); - panel_sequence_viewer->viewer_widget()->frame_update(); -} - -void OldEffectNode::save_to_file() { - // save effect settings to file - QString file = QFileDialog::getSaveFileName(olive::MainWindow, - tr("Save Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); - - // if the user picked a file - if (!file.isEmpty()) { - - // ensure file ends with .xml extension - if (!file.endsWith(".xml", Qt::CaseInsensitive)) { - file.append(".xml"); - } - - QFile file_handle(file); - if (file_handle.open(QFile::WriteOnly)) { - - file_handle.write(save_to_string()); - - file_handle.close(); - } else { - QMessageBox::critical(olive::MainWindow, - tr("Save Settings Failed"), - tr("Failed to open \"%1\" for writing.").arg(file), - QMessageBox::Ok); - } - } -} - -void OldEffectNode::load_from_file() { - // load effect settings from file - QString file = QFileDialog::getOpenFileName(olive::MainWindow, - tr("Load Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); - - // if the user picked a file - if (!file.isEmpty()) { - QFile file_handle(file); - if (file_handle.open(QFile::ReadOnly)) { - - olive::undo_stack.push(new SetEffectData(this, file_handle.readAll())); - - file_handle.close(); - - update_ui(false); - } else { - QMessageBox::critical(olive::MainWindow, - tr("Load Settings Failed"), - tr("Failed to open \"%1\" for reading.").arg(file), - QMessageBox::Ok); - } - } -} - -bool OldEffectNode::AlwaysUpdate() -{ - return false; -} - -bool OldEffectNode::IsEnabled() { - return enabled_; -} - -bool OldEffectNode::IsExpanded() -{ - return expanded_; -} - -void OldEffectNode::SetExpanded(bool e) -{ - expanded_ = e; -} - -void OldEffectNode::SetEnabled(bool b) { - enabled_ = b; - emit EnabledChanged(b); -} - -void OldEffectNode::load(QXmlStreamReader& stream) { - /* - int row_count = 0; - - QString tag = stream.name().toString(); - - while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { - stream.readNext(); - if (stream.name() == "row" && stream.isStartElement()) { - if (row_count < rows.size()) { - EffectRow* row = rows.at(row_count); - - while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { - stream.readNext(); - - // read field - if (stream.name() == "field" && stream.isStartElement()) { - int field_number = -1; - - // match field using ID - for (int k=0;kFieldCount();l++) { - if (row->Field(l)->id() == attr.value()) { - field_number = l; - break; - } - } - break; - } - } - - if (field_number > -1) { - EffectField* field = row->Field(field_number); - - // get current field value - for (int k=0;kpersistent_data_ = field->ConvertStringToValue(attr.value().toString()); - break; - } - } - - while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { - stream.readNext(); - - // read keyframes - if (stream.name() == "key" && stream.isStartElement()) { - row->SetKeyframingInternal(true); - - EffectKeyframe key; - for (int k=0;kConvertStringToValue(attr.value().toString()); - } else if (attr.name() == "frame") { - key.time = attr.value().toLong(); - } else if (attr.name() == "type") { - key.type = attr.value().toInt(); - } else if (attr.name() == "prehx") { - key.pre_handle_x = attr.value().toDouble(); - } else if (attr.name() == "prehy") { - key.pre_handle_y = attr.value().toDouble(); - } else if (attr.name() == "posthx") { - key.post_handle_x = attr.value().toDouble(); - } else if (attr.name() == "posthy") { - key.post_handle_y = attr.value().toDouble(); - } - } - field->keyframes.append(key); - } - } - - field->Changed(); - - } - } - } - - } else { - qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; - } - row_count++; - } else if (stream.isStartElement()) { - custom_load(stream); - } - } - */ -} - -void OldEffectNode::custom_load(QXmlStreamReader &) {} - -void OldEffectNode::save(QXmlStreamWriter& stream) { - /* - stream.writeAttribute("name", meta->category + "/" + meta->name); - stream.writeAttribute("enabled", QString::number(IsEnabled())); - - for (int i=0;iIsSavable()) { - stream.writeStartElement("row"); // row - for (int j=0;jFieldCount();j++) { - EffectField* field = row->Field(j); - - if (!field->id().isEmpty()) { - stream.writeStartElement("field"); // field - stream.writeAttribute("id", field->id()); - stream.writeAttribute("value", field->ConvertValueToString(field->persistent_data_)); - for (int k=0;kkeyframes.size();k++) { - const EffectKeyframe& key = field->keyframes.at(k); - stream.writeStartElement("key"); - stream.writeAttribute("value", field->ConvertValueToString(key.data)); - stream.writeAttribute("frame", QString::number(key.time)); - stream.writeAttribute("type", QString::number(key.type)); - stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); - stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); - stream.writeAttribute("posthx", QString::number(key.post_handle_x)); - stream.writeAttribute("posthy", QString::number(key.post_handle_y)); - stream.writeEndElement(); // key - } - stream.writeEndElement(); // field - } - } - stream.writeEndElement(); // row - } - } - */ -} - -void OldEffectNode::load_from_string(const QByteArray &s) { - // clear existing keyframe data - for (int i=0;iSetKeyframingInternal(false); - for (int j=0;jFieldCount();j++) { - EffectField* field = row->Field(j); - field->keyframes.clear(); - } - } - - // write settings with xml writer - QXmlStreamReader stream(s); - - bool found_id = false; - - while (!stream.atEnd()) { - stream.readNext(); - - // find the effect opening tag - if (stream.name() == "effect" && stream.isStartElement()) { - - // check the name to see if it matches this effect - const QXmlStreamAttributes& attributes = stream.attributes(); - for (int i=0;ipath.isEmpty() || (shader_vert_path_.isEmpty() && shader_frag_path_.isEmpty())) return; - QList effects_paths = get_effects_paths(); - const QString& test_fn = shader_vert_path_.isEmpty() ? shader_frag_path_ : shader_vert_path_; - for (int i=0;iisLinked(); -} - -QOpenGLShaderProgram *OldEffectNode::GetShaderPipeline() -{ - return shader_program_.get(); -} - -int OldEffectNode::Flags() -{ - return flags_; -} - -void OldEffectNode::SetFlags(int flags) -{ - flags_ = flags; -} - -int OldEffectNode::getIterations() { - return iterations; -} - -void OldEffectNode::setIterations(int i) { - iterations = i; -} - -void OldEffectNode::process_image(double, uint8_t *, uint8_t *, int){} - -OldEffectNodePtr OldEffectNode::copy(Clip *c) { - OldEffectNodePtr copy = Create(c); - copy->SetEnabled(IsEnabled()); - copy_field_keyframes(copy); - return copy; -} - -void OldEffectNode::process_shader(double timecode, GLTextureCoords&, int iteration) { - /* - shader_program_->bind(); - - shader_program_->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); - shader_program_->setUniformValue("time", GLfloat(timecode)); - shader_program_->setUniformValue("iteration", iteration); - - for (int i=0;iFieldCount();j++) { - EffectField* field = row->Field(j); - if (!field->id().isEmpty()) { - switch (field->type()) { - case EffectField::EFFECT_FIELD_DOUBLE: - { - DoubleField* double_field = static_cast(field); - shader_program_->setUniformValue(double_field->id().toUtf8().constData(), - GLfloat(double_field->GetDoubleAt(timecode))); - } - break; - case EffectField::EFFECT_FIELD_COLOR: - { - ColorField* color_field = static_cast(field); - shader_program_->setUniformValue( - color_field->id().toUtf8().constData(), - GLfloat(color_field->GetColorAt(timecode).redF()), - GLfloat(color_field->GetColorAt(timecode).greenF()), - GLfloat(color_field->GetColorAt(timecode).blueF()) - ); - } - break; - case EffectField::EFFECT_FIELD_BOOL: - shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool()); - break; - case EffectField::EFFECT_FIELD_COMBO: - shader_program_->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); - break; - - // can you even send a string to a uniform value? - case EffectField::EFFECT_FIELD_STRING: - case EffectField::EFFECT_FIELD_FONT: - case EffectField::EFFECT_FIELD_FILE: - case EffectField::EFFECT_FIELD_UI: - break; - } - } - } - } - - shader_program_->release(); - */ -} - -void OldEffectNode::process_coords(double, GLTextureCoords&, int) {} - -GLuint OldEffectNode::process_superimpose(QOpenGLContext* ctx, double timecode) { - bool dimensions_changed = false; - bool redrew_image = false; - - int width = parent_clip->media_width(); - int height = parent_clip->media_height(); - - if (width != img.width() || height != img.height()) { - img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); - dimensions_changed = true; - } - - if (valueHasChanged(timecode) || dimensions_changed || AlwaysUpdate()) { - redraw(timecode); - redrew_image = true; - } - - QOpenGLFunctions* f = ctx->functions(); - - if (texture == 0 || tex_width_ != img.width() || tex_height_ != img.height()) { - delete_texture(); - - tex_width_ = img.width(); - tex_height_ = img.height(); - - // create texture object - f->glGenTextures(1, &texture); - - f->glBindTexture(GL_TEXTURE_2D, texture); - - // set texture filtering to bilinear - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - f->glTexImage2D( - GL_TEXTURE_2D, 0, GL_RGBA8, tex_width_, tex_height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits() - ); - - f->glBindTexture(GL_TEXTURE_2D, 0); - - redrew_image = false; - } - - if (redrew_image) { - f->glBindTexture(GL_TEXTURE_2D, texture); - - f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_width_, tex_height_, GL_RGBA, GL_UNSIGNED_BYTE, img.constBits()); - - f->glBindTexture(GL_TEXTURE_2D, 0); - } - - return texture; -} - -void OldEffectNode::process_audio(double, double, float **, int, int, int) {} - -void OldEffectNode::gizmo_draw(double, GLTextureCoords &) {} - -void OldEffectNode::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) { - // Loop through each gizmo to find `gizmo` - for (int i=0;ix_field1 != nullptr) { - gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->x_field1)); - } - if (gizmo->y_field1 != nullptr) { - gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->y_field1)); - } - if (gizmo->x_field2 != nullptr) { - gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->x_field2)); - } - if (gizmo->y_field2 != nullptr) { - gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->y_field2)); - } - } - - // Update the field values - if (gizmo->x_field1 != nullptr) { - gizmo->x_field1->SetValueAt(timecode, - gizmo->x_field1->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi1); - } - if (gizmo->y_field1 != nullptr) { - gizmo->y_field1->SetValueAt(timecode, - gizmo->y_field1->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi1); - } - if (gizmo->x_field2 != nullptr) { - gizmo->x_field2->SetValueAt(timecode, - gizmo->x_field2->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi2); - } - if (gizmo->y_field2 != nullptr) { - gizmo->y_field2->SetValueAt(timecode, - gizmo->y_field2->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi2); - } - - // If (done && !gizmo_dragging_actions_.isEmpty()), that means the drag just ended and we're going to save - // the new state of the attach fields' keyframes in KeyframeDataChange objects to make the changes undoable - // by the user later. - if (done && !gizmo_dragging_actions_.isEmpty()) { - - // Store all the KeyframeDataChange objects into a ComboAction to send to the undo stack (makes them all - // undoable together rather than having to be undone individually). - ComboAction* ca = new ComboAction(); - - for (int j=0;jSetNewKeyframes(); - - // Add this KeyframeDataChange object to the ComboAction - ca->append(gizmo_dragging_actions_.at(j)); - } - - olive::undo_stack.push(ca); - - gizmo_dragging_actions_.clear(); - } - break; - } - } -} - -void OldEffectNode::gizmo_world_to_screen(const QMatrix4x4& matrix, const QMatrix4x4& projection) { - for (int i=0;iget_point_count();j++) { - - // Convert the world point from the gizmo into a screen point relative to the sequence's dimensions - - QVector3D screen_pos = g->world_pos.at(j).project(matrix, - projection, - QRect(0, - 0, - parent_clip->track()->sequence()->width(), - parent_clip->track()->sequence()->height())); - - g->screen_pos[j] = QPoint(screen_pos.x(), parent_clip->track()->sequence()->height() - screen_pos.y()); - - } - } -} - -bool OldEffectNode::are_gizmos_enabled() { - return (gizmos.size() > 0); -} - -double OldEffectNode::Now() -{ - return playhead_to_clip_seconds(parent_clip, parent_clip->track()->sequence()->playhead); -} - -long OldEffectNode::NowInFrames() -{ - return playhead_to_clip_frame(parent_clip, parent_clip->track()->sequence()->playhead); -} - -void OldEffectNode::redraw(double) { - /* - // run javascript - QPainter p(&img); - painter_wrapper.img = &img; - painter_wrapper.painter = &p; - - jsEngine.globalObject().setProperty("painter", wrapper_obj); - jsEngine.globalObject().setProperty("width", parent_clip->media_width()); - jsEngine.globalObject().setProperty("height", parent_clip->media_height()); - - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EffectField::EFFECT_FIELD_DOUBLE: - jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); - break; - case EffectField::EFFECT_FIELD_COLOR: - jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); - break; - case EffectField::EFFECT_FIELD_STRING: - jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); - break; - case EffectField::EFFECT_FIELD_BOOL: - jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); - break; - case EffectField::EFFECT_FIELD_COMBO: - jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); - break; - case EffectField::EFFECT_FIELD_FONT: - jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); - break; - } - } - } - } - - jsEngine.evaluate(script); - */ -} - -bool OldEffectNode::valueHasChanged(double timecode) { - if (cachedValues.isEmpty()) { - - for (int i=0;iFieldCount();j++) { - cachedValues.append(crow->Field(j)->GetValueAt(timecode)); - } - } - return true; - - } else { - - bool changed = false; - int index = 0; - for (int i=0;iFieldCount();j++) { - EffectField* field = crow->Field(j); - if (cachedValues.at(index) != field->GetValueAt(timecode)) { - changed = true; - } - cachedValues[index] = field->GetValueAt(timecode); - index++; - } - } - return changed; - - } -} - -void OldEffectNode::delete_texture() { - if (texture_ctx != nullptr) { - texture_ctx->functions()->glDeleteTextures(1, &texture); - texture = 0; - texture_ctx = nullptr; - } -} - -int GetNodeLibraryIndexFromId(const QString& id) { - for (int i=0;iid() == id) { - return i; - } - } - - return -1; -} - -/* -const EffectMeta* Node::GetMetaFromName(const QString& input) { - int split_index = input.indexOf('/'); - QString category; - if (split_index > -1) { - category = input.left(split_index); - } - QString name = input.mid(split_index + 1); - - for (int j=0;j. - -***/ - -#ifndef EFFECT_H -#define EFFECT_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "timeline/tracktypes.h" -#include "rendering/qopenglshaderprogramptr.h" -#include "inputs.h" -#include "effects/effectgizmo.h" -#include "node.h" - -class EffectGizmo; -class KeyframeDataChange; - -class Clip; -using ClipPtr = std::shared_ptr; - -class OldEffectNode; -using OldEffectNodePtr = std::shared_ptr; - -enum NodeType { - kTransformEffect, - kTextInput, - kSolidInput, - kNoiseInput, - kVolumeEffect, - kPanEffect, - kToneInput, - kShakeEffect, - kTimecodeEffect, - kMaskEffect, - kFillLeftRightEffect, - kVstEffect, - kCornerPinEffect, - kRichTextInput, - kMediaInput, - kShaderEffect, - kImageOutput, - kCrossDissolveTransition, - kLinearFadeTransition, - kExponentialFadeTransition, - kLogarithmicFadeTransition, - kInvalidNode -}; - -double log_volume(double linear); - -enum EffectType { - EFFECT_TYPE_INVALID, - EFFECT_TYPE_EFFECT, - EFFECT_TYPE_TRANSITION -}; - -enum EffectKeyframeType { - EFFECT_KEYFRAME_LINEAR, - EFFECT_KEYFRAME_BEZIER, - EFFECT_KEYFRAME_HOLD -}; - -struct GLTextureCoords { - QMatrix4x4 matrix; - - QVector3D vertex_top_left; - QVector3D vertex_top_right; - QVector3D vertex_bottom_left; - QVector3D vertex_bottom_right; - - QVector2D texture_top_left; - QVector2D texture_top_right; - QVector2D texture_bottom_left; - QVector2D texture_bottom_right; - - float opacity; -}; - -class OldEffectNode : public Node { - Q_OBJECT -public: - OldEffectNode(Clip *c); - ~OldEffectNode(); - - Clip* parent_clip; - - virtual QString name() = 0; - virtual QString id() = 0; - virtual QString category(); - virtual QString description(); - virtual EffectType type() = 0; - virtual olive::TrackType subtype() = 0; - virtual bool IsCreatable(); - virtual OldEffectNodePtr Create(Clip *c) = 0; - - EffectGizmo* add_gizmo(int type); - EffectGizmo* gizmo(int i); - int gizmo_count(); - - QVector GetAllEdges(); - - bool IsEnabled(); - bool IsExpanded(); - - virtual void refresh(); - - virtual OldEffectNodePtr copy(Clip* c); - void copy_field_keyframes(OldEffectNodePtr e); - - virtual void load(QXmlStreamReader& stream); - virtual void custom_load(QXmlStreamReader& stream); - virtual void save(QXmlStreamWriter& stream); - - void load_from_string(const QByteArray &s); - QByteArray save_to_string(); - - // glsl handling - bool is_open(); - void open(); - void close(); - bool is_shader_linked(); - QOpenGLShaderProgram* GetShaderPipeline(); - - enum VideoEffectFlags { - ShaderFlag = 0x1, - CoordsFlag = 0x2, - SuperimposeFlag = 0x4 - }; - int Flags(); - void SetFlags(int flags); - - int getIterations(); - void setIterations(int i); - - - - virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size); - virtual void process_shader(double timecode, GLTextureCoords&, int iteration); - virtual void process_coords(double timecode, GLTextureCoords& coords, int data); - virtual GLuint process_superimpose(QOpenGLContext *ctx, double timecode); - virtual void process_audio(double timecode_start, double timecode_end, float **samples, int nb_samples, int nb_channels, int type); - - virtual void gizmo_draw(double timecode, GLTextureCoords& coords); - void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done); - void gizmo_world_to_screen(const QMatrix4x4 &matrix, const QMatrix4x4 &projection); - bool are_gizmos_enabled(); - - /** - * @brief Get the current clip/media time - * - * A convenience function that can be plugged into GetValueAt() to get the value wherever the appropriate Sequence's - * playhead it. - * - * @return - * - * Current clip/media time in seconds. - */ - double Now(); - - /** - * @brief Retrieve the current clip as a frame number - * - * Same as Now() but retrieves the value as a frame number (in the appropriate Sequence's frame rate) instead of - * seconds. - * - * @return - * - * The current clip time in frames - */ - long NowInFrames(); - - template - T randomNumber() - { - static std::random_device device; - static std::mt19937 generator(device()); - static std::uniform_int_distribution<> distribution(std::numeric_limits::min(), std::numeric_limits::max()); - return distribution(generator); - } - - template - T randomFloat() - { - static std::random_device device; - static std::mt19937 generator(device()); - static std::uniform_int_distribution<> distribution(-1.0, 1.0); - return distribution(generator); - } - -public slots: - void FieldChanged(); - void SetEnabled(bool b); - void SetExpanded(bool e); - -signals: - void EnabledChanged(bool); -private slots: - void delete_self(); - void move_up(); - void move_down(); - void save_to_file(); - void load_from_file(); -protected: - // glsl effect - QOpenGLShaderProgramPtr shader_program_; - QString shader_vert_path_; - QString shader_frag_path_; - QString shader_function_name_; - - // superimpose effect - QImage img; - GLuint texture; - QOpenGLContext* texture_ctx; - int tex_width_; - int tex_height_; - - // enable effect to update constantly - virtual bool AlwaysUpdate(); - -private: - bool isOpen; - QVector gizmos; - bool bound; - int iterations; - - bool enabled_; - bool expanded_; - - int flags_; - - QVector gizmo_dragging_actions_; - - - - // superimpose functions - virtual void redraw(double timecode); - bool valueHasChanged(double timecode); - QVector cachedValues; - void delete_texture(); - void validate_meta_path(); -}; - -namespace olive { - extern QVector node_library; -} - -#endif // EFFECT_H diff --git a/nodes/widgets/buttonwidget.cpp b/nodes/widgets/buttonwidget.cpp deleted file mode 100644 index df4cf7711..000000000 --- a/nodes/widgets/buttonwidget.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "buttonwidget.h" - -ButtonWidget::ButtonWidget(Node* parent, const QString& name, const QString& text) : - NodeIO(parent, nullptr, name, false, false) -{ - ButtonField* button_field = new ButtonField(this, text); - - connect(button_field, SIGNAL(CheckedChanged(bool)), this, SIGNAL(CheckedChanged(bool))); - connect(button_field, SIGNAL(Toggled(bool)), this, SIGNAL(Toggled(bool))); - connect(this, SLOT(SetChecked(bool)), button_field, SLOT(SetChecked(bool))); - - AddField(button_field); -} - -void ButtonWidget::SetCheckable(bool c) -{ - static_cast(Field(0))->SetCheckable(c); -} - -void ButtonWidget::SetChecked(bool c) -{ - static_cast(Field(0))->SetChecked(c); -} diff --git a/nodes/widgets/buttonwidget.h b/nodes/widgets/buttonwidget.h deleted file mode 100644 index 59474548c..000000000 --- a/nodes/widgets/buttonwidget.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef BUTTONWIDGET_H -#define BUTTONWIDGET_H - -#include "nodes/nodeio.h" - -class ButtonWidget : public NodeIO -{ -public: - ButtonWidget(Node* parent, const QString& name, const QString& text); - - /** - * @brief Wrapper for ButtonField::SetCheckable. - */ - void SetCheckable(bool c); - -public slots: - /** - * @brief Wrapper for ButtonField::SetChecked() - */ - void SetChecked(bool c); - -signals: - /** - * @brief Wrapper for ButtonField::CheckedChanged() - */ - void CheckedChanged(bool); - - /** - * @brief Wrapper for ButtonField::Toggled() - */ - void Toggled(bool); - -}; - -#endif // BUTTONWIDGET_H diff --git a/nodes/widgets/labelwidget.cpp b/nodes/widgets/labelwidget.cpp deleted file mode 100644 index ac0da1625..000000000 --- a/nodes/widgets/labelwidget.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "labelwidget.h" - -LabelWidget::LabelWidget(Node *parent, const QString &name, const QString &text) : - NodeIO(parent, nullptr, name, false, false) -{ - AddField(new LabelField(this, text)); -} diff --git a/nodes/widgets/labelwidget.h b/nodes/widgets/labelwidget.h deleted file mode 100644 index 36983ef82..000000000 --- a/nodes/widgets/labelwidget.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef LABELWIDGET_H -#define LABELWIDGET_H - -#include "nodes/nodeio.h" - -class LabelWidget : public NodeIO -{ -public: - LabelWidget(Node* parent, const QString& name, const QString& text); -}; - -#endif // LABELWIDGET_H diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp deleted file mode 100644 index 92c19a9f1..000000000 --- a/panels/effectcontrols.cpp +++ /dev/null @@ -1,425 +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 "effectcontrols.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "panels/panels.h" -#include "nodes/oldeffectnode.h" -#include "effects/effectloaders.h" -#include "effects/transition.h" -#include "timeline/clip.h" -#include "ui/collapsiblewidget.h" -#include "timeline/sequence.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "panels/project.h" -#include "panels/timeline.h" -#include "panels/viewer.h" -#include "panels/grapheditor.h" -#include "ui/viewerwidget.h" -#include "ui/menuhelper.h" -#include "ui/icons.h" -#include "global/clipboard.h" -#include "global/config.h" -#include "global/global.h" -#include "ui/timelineheader.h" -#include "ui/keyframeview.h" -#include "ui/resizablescrollbar.h" -#include "global/debug.h" -#include "ui/menu.h" - -EffectControls::EffectControls(QWidget *parent) : - EffectsPanel(parent), - zoom(1) -{ - setup_ui(); - Retranslate(); - - Clear(false); - - headers->viewer = panel_sequence_viewer; - headers->snapping = false; - - effects_area->parent_widget = scrollArea; - effects_area->keyframe_area = keyframeView; - effects_area->header = headers; - keyframeView->header = headers; - - connect(keyframeView, SIGNAL(wheel_event_signal(QWheelEvent*)), effects_area, SLOT(receive_wheel_event(QWheelEvent*))); - connect(horizontalScrollBar, SIGNAL(valueChanged(int)), headers, SLOT(set_scroll(int))); - connect(horizontalScrollBar, SIGNAL(resize_move(double)), keyframeView, SLOT(resize_move(double))); - connect(horizontalScrollBar, SIGNAL(valueChanged(int)), keyframeView, SLOT(set_x_scroll(int))); - connect(verticalScrollBar, SIGNAL(valueChanged(int)), keyframeView, SLOT(set_y_scroll(int))); - connect(verticalScrollBar, SIGNAL(valueChanged(int)), scrollArea->verticalScrollBar(), SLOT(setValue(int))); - connect(scrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), verticalScrollBar, SLOT(setValue(int))); -} - -void EffectControls::set_zoom(bool in) { - zoom *= (in) ? 2 : 0.5; - update_keyframes(); - - if (!selected_clips_.isEmpty()) { - scroll_to_frame(selected_clips_.first()->track()->sequence()->playhead); - } -} - -void EffectControls::update_keyframes() { - for (int i=0;iUpdateFromEffect(); - } - - headers->update_zoom(zoom); - keyframeView->update(); -} - -void EffectControls::delete_selected_keyframes() { - keyframeView->delete_selected_keyframes(); -} - -void EffectControls::scroll_to_frame(long frame) { - scroll_to_frame_internal(horizontalScrollBar, frame - keyframeView->visible_in, zoom, keyframeView->width()); -} - -void EffectControls::UpdateTitle() { - if (selected_clips_.isEmpty()) { - setWindowTitle(panel_name + tr("(none)")); - } else { - setWindowTitle(panel_name + selected_clips_.first()->name()); - } -} - -void EffectControls::setup_ui() { - QWidget* contents = new QWidget(this); - - QHBoxLayout* hlayout = new QHBoxLayout(contents); - hlayout->setSpacing(0); - hlayout->setMargin(0); - - splitter = new QSplitter(); - splitter->setOrientation(Qt::Horizontal); - splitter->setChildrenCollapsible(false); - - scrollArea = new QScrollArea(); - scrollArea->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); - scrollArea->setFrameShape(QFrame::NoFrame); - scrollArea->setFrameShadow(QFrame::Plain); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - scrollArea->setWidgetResizable(true); - - QWidget* scrollAreaWidgetContents = new QWidget(); - - QHBoxLayout* scrollAreaLayout = new QHBoxLayout(scrollAreaWidgetContents); - scrollAreaLayout->setSpacing(0); - scrollAreaLayout->setMargin(0); - - effects_area = new EffectsArea(); - effects_area->setContextMenuPolicy(Qt::CustomContextMenu); - connect(effects_area, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(effects_area_context_menu())); - - QVBoxLayout* effects_area_layout = new QVBoxLayout(effects_area); - effects_area_layout->setSpacing(0); - effects_area_layout->setMargin(0); - - vcontainer = new QWidget(); - QVBoxLayout* vcontainerLayout = new QVBoxLayout(vcontainer); - vcontainerLayout->setSpacing(0); - vcontainerLayout->setMargin(0); - - QWidget* veHeader = new QWidget(); - veHeader->setObjectName(QStringLiteral("veHeader")); - veHeader->setStyleSheet(QLatin1String("#veHeader { background: rgba(0, 0, 0, 0.25); }")); - - QHBoxLayout* veHeaderLayout = new QHBoxLayout(veHeader); - veHeaderLayout->setSpacing(0); - veHeaderLayout->setMargin(0); - - QIcon add_effect_icon = olive::icon::CreateIconFromSVG(":/icons/add-effect.svg", false); - QIcon add_transition_icon = olive::icon::CreateIconFromSVG(":/icons/add-transition.svg", false); - - btnAddVideoEffect = new QPushButton(); - btnAddVideoEffect->setIcon(add_effect_icon); - veHeaderLayout->addWidget(btnAddVideoEffect); - connect(btnAddVideoEffect, SIGNAL(clicked(bool)), this, SLOT(video_effect_click())); - - veHeaderLayout->addStretch(); - - lblVideoEffects = new QLabel(); - QFont font; - font.setPointSize(9); - lblVideoEffects->setFont(font); - lblVideoEffects->setAlignment(Qt::AlignCenter); - veHeaderLayout->addWidget(lblVideoEffects); - - veHeaderLayout->addStretch(); - - btnAddVideoTransition = new QPushButton(); - btnAddVideoTransition->setIcon(add_transition_icon); - connect(btnAddVideoTransition, SIGNAL(clicked(bool)), this, SLOT(video_transition_click())); - veHeaderLayout->addWidget(btnAddVideoTransition); - - vcontainerLayout->addWidget(veHeader); - - video_effect_area = new QWidget(); - video_effect_layout = new QVBoxLayout(video_effect_area); - video_effect_layout->setSpacing(0); - video_effect_layout->setMargin(0); - - vcontainerLayout->addWidget(video_effect_area); - - effects_area_layout->addWidget(vcontainer); - - acontainer = new QWidget(); - QVBoxLayout* acontainerLayout = new QVBoxLayout(acontainer); - acontainerLayout->setSpacing(0); - acontainerLayout->setMargin(0); - QWidget* aeHeader = new QWidget(); - aeHeader->setObjectName(QStringLiteral("aeHeader")); - aeHeader->setStyleSheet(QLatin1String("#aeHeader { background: rgba(0, 0, 0, 0.25); }")); - - QHBoxLayout* aeHeaderLayout = new QHBoxLayout(aeHeader); - aeHeaderLayout->setSpacing(0); - aeHeaderLayout->setMargin(0); - - btnAddAudioEffect = new QPushButton(); - btnAddAudioEffect->setIcon(add_effect_icon); - connect(btnAddAudioEffect, SIGNAL(clicked(bool)), this, SLOT(audio_effect_click())); - aeHeaderLayout->addWidget(btnAddAudioEffect); - - aeHeaderLayout->addStretch(); - - lblAudioEffects = new QLabel(); - lblAudioEffects->setFont(font); - lblAudioEffects->setAlignment(Qt::AlignCenter); - aeHeaderLayout->addWidget(lblAudioEffects); - - aeHeaderLayout->addStretch(); - - btnAddAudioTransition = new QPushButton(); - btnAddAudioTransition->setIcon(add_transition_icon); - connect(btnAddAudioTransition, SIGNAL(clicked(bool)), this, SLOT(audio_transition_click())); - aeHeaderLayout->addWidget(btnAddAudioTransition); - - acontainerLayout->addWidget(aeHeader); - - audio_effect_area = new QWidget(); - audio_effect_layout = new QVBoxLayout(audio_effect_area); - audio_effect_layout->setSpacing(0); - audio_effect_layout->setMargin(0); - - acontainerLayout->addWidget(audio_effect_area); - - effects_area_layout->addWidget(acontainer); - - effects_area_layout->addStretch(); - - scrollAreaLayout->addWidget(effects_area); - - scrollArea->setWidget(scrollAreaWidgetContents); - splitter->addWidget(scrollArea); - - QWidget* keyframeArea = new QWidget(); - - QSizePolicy keyframe_sp; - keyframe_sp.setHorizontalPolicy(QSizePolicy::Minimum); - keyframe_sp.setVerticalPolicy(QSizePolicy::Preferred); - keyframe_sp.setHorizontalStretch(1); - keyframeArea->setSizePolicy(keyframe_sp); - - QVBoxLayout* keyframeAreaLayout = new QVBoxLayout(keyframeArea); - keyframeAreaLayout->setSpacing(0); - keyframeAreaLayout->setMargin(0); - - headers = new TimelineHeader(); - keyframeAreaLayout->addWidget(headers); - - QWidget* keyframeCenterWidget = new QWidget(); - - QHBoxLayout* keyframeCenterLayout = new QHBoxLayout(keyframeCenterWidget); - keyframeCenterLayout->setSpacing(0); - keyframeCenterLayout->setMargin(0); - - keyframeView = new KeyframeView(); - - keyframeCenterLayout->addWidget(keyframeView); - - verticalScrollBar = new QScrollBar(); - verticalScrollBar->setOrientation(Qt::Vertical); - - keyframeCenterLayout->addWidget(verticalScrollBar); - - - keyframeAreaLayout->addWidget(keyframeCenterWidget); - - horizontalScrollBar = new ResizableScrollBar(); - horizontalScrollBar->setOrientation(Qt::Horizontal); - - keyframeAreaLayout->addWidget(horizontalScrollBar); - - splitter->addWidget(keyframeArea); - - hlayout->addWidget(splitter); - - setWidget(contents); -} - -void EffectControls::Retranslate() { - panel_name = tr("Effects: "); - - btnAddVideoEffect->setToolTip(tr("Add Video Effect")); - lblVideoEffects->setText(tr("VIDEO EFFECTS")); - btnAddVideoTransition->setToolTip(tr("Add Video Transition")); - btnAddAudioEffect->setToolTip(tr("Add Audio Effect")); - lblAudioEffects->setText(tr("AUDIO EFFECTS")); - btnAddAudioTransition->setToolTip(tr("Add Audio Transition")); - - UpdateTitle(); -} - -void EffectControls::LoadLayoutState(const QByteArray &data) -{ - splitter->restoreState(data); -} - -QByteArray EffectControls::SaveLayoutState() -{ - return splitter->saveState(); -} - -void EffectControls::update_scrollbar() { - verticalScrollBar->setMaximum(qMax(0, effects_area->height() - keyframeView->height() - headers->height())); - verticalScrollBar->setPageStep(verticalScrollBar->height()); -} - -void EffectControls::queue_post_update() { - keyframeView->update(); - update_scrollbar(); -} - -void EffectControls::effects_area_context_menu() { - Menu menu(this); - - olive::MenuHelper.create_effect_paste_action(&menu); - - menu.exec(QCursor::pos()); -} - -bool EffectControls::focused() -{ - if (this->hasFocus() - || headers->hasFocus() - || keyframeView->hasFocus()) { - return true; - } - - return EffectsPanel::focused(); -} - -void EffectControls::video_effect_click() { - olive::Global->ShowEffectMenu(EFFECT_TYPE_EFFECT, olive::kTypeVideo, selected_clips_); -} - -void EffectControls::audio_effect_click() { - olive::Global->ShowEffectMenu(EFFECT_TYPE_EFFECT, olive::kTypeAudio, selected_clips_); -} - -void EffectControls::video_transition_click() { - olive::Global->ShowEffectMenu(EFFECT_TYPE_TRANSITION, olive::kTypeVideo, selected_clips_); -} - -void EffectControls::audio_transition_click() { - olive::Global->ShowEffectMenu(EFFECT_TYPE_TRANSITION, olive::kTypeAudio, selected_clips_); -} - -void EffectControls::resizeEvent(QResizeEvent*) { - update_scrollbar(); -} - -void EffectControls::ClearEvent() -{ - keyframeView->SetEffects(open_effects_); - - vcontainer->setVisible(false); - acontainer->setVisible(false); - headers->setVisible(false); - keyframeView->setEnabled(false); - - UpdateTitle(); -} - -void EffectControls::LoadEvent() -{ - keyframeView->SetEffects(open_effects_); - - if (selected_clips_.size() > 0) { - keyframeView->setEnabled(true); - - headers->setVisible(true); - - QTimer::singleShot(50, this, SLOT(queue_post_update())); - } - - for (int i=0;iGetEffect(); - - if (e->subtype() == olive::kTypeVideo) { - vcontainer->setVisible(true); - layout = video_effect_layout; - } else if (e->subtype() == olive::kTypeAudio) { - acontainer->setVisible(true); - layout = audio_effect_layout; - } - - if (layout != nullptr) { - layout->addWidget(container); - } - } - - UpdateTitle(); - update_keyframes(); -} - -EffectsArea::EffectsArea(QWidget* parent) : - QWidget(parent) -{} - -void EffectsArea::resizeEvent(QResizeEvent *) -{ - parent_widget->setMinimumWidth(sizeHint().width()); -} - -void EffectsArea::receive_wheel_event(QWheelEvent *e) { - QApplication::sendEvent(this, e); -} diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h deleted file mode 100644 index 78ac1c3f3..000000000 --- a/panels/effectcontrols.h +++ /dev/null @@ -1,122 +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 EFFECTCONTROLS_H -#define EFFECTCONTROLS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "project/projectelements.h" -#include "timeline/track.h" -#include "ui/timelineheader.h" -#include "ui/keyframeview.h" -#include "ui/resizablescrollbar.h" -#include "ui/keyframeview.h" -#include "effectspanel.h" -#include "ui/effectui.h" - -class EffectsArea : public QWidget { - Q_OBJECT -public: - EffectsArea(QWidget* parent = nullptr); - QScrollArea* parent_widget; - KeyframeView* keyframe_area; - TimelineHeader* header; -protected: - void resizeEvent(QResizeEvent*); -public slots: - void receive_wheel_event(QWheelEvent* e); -}; - -class EffectControls : public EffectsPanel -{ - Q_OBJECT -public: - explicit EffectControls(QWidget *parent = nullptr); - - virtual bool focused() override; - void set_zoom(bool in); - void delete_selected_keyframes(); - void scroll_to_frame(long frame); - - double zoom; - - ResizableScrollBar* horizontalScrollBar; - QScrollBar* verticalScrollBar; - - virtual void Retranslate() override; - - virtual void LoadLayoutState(const QByteArray& data) override; - virtual QByteArray SaveLayoutState() override; -public slots: - void update_keyframes(); -private slots: - void video_effect_click(); - void audio_effect_click(); - void video_transition_click(); - void audio_transition_click(); - - - - void update_scrollbar(); - void queue_post_update(); - - void effects_area_context_menu(); -protected: - virtual void resizeEvent(QResizeEvent *event) override; - virtual void ClearEvent() override; - virtual void LoadEvent() override; -private: - void load_keyframes(); - void UpdateTitle(); - - void setup_ui(); - - QString panel_name; - - QWidget* video_effect_area; - QWidget* audio_effect_area; - QVBoxLayout* video_effect_layout; - QVBoxLayout* audio_effect_layout; - - QSplitter* splitter; - QPushButton* btnAddVideoEffect; - QLabel* lblVideoEffects; - QLabel* lblAudioEffects; - QPushButton* btnAddVideoTransition; - QPushButton* btnAddAudioEffect; - QPushButton* btnAddAudioTransition; - TimelineHeader* headers; - EffectsArea* effects_area; - QScrollArea* scrollArea; - KeyframeView* keyframeView; - QWidget* vcontainer; - QWidget* acontainer; -}; - -#endif // EFFECTCONTROLS_H diff --git a/panels/effectspanel.cpp b/panels/effectspanel.cpp deleted file mode 100644 index 3eb81c55b..000000000 --- a/panels/effectspanel.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "effectspanel.h" - -#include "timeline.h" -#include "global/clipboard.h" -#include "panels.h" - -EffectsPanel::EffectsPanel(QWidget *parent) : - Panel(parent) -{ - -} - -EffectsPanel::~EffectsPanel() -{ - Clear(true); -} - -void EffectsPanel::Clear(bool clear_cache) { - AboutToClearEvent(); - - // clear existing clips - deselect_all_effects(nullptr); - - for (int i=0;iIsFocused()) { - return true; - } - } - - return Panel::focused(); -} - -void EffectsPanel::ClearEvent() {} - -void EffectsPanel::LoadEvent() {} - -void EffectsPanel::Reload() { - Clear(false); - Load(); -} - -void EffectsPanel::SetClips() -{ - Clear(true); - - Sequence* top_sequence = Timeline::GetTopSequence().get(); - - if (top_sequence == nullptr) { - selected_clips_.clear(); - } else { - // replace clip vector - selected_clips_ = top_sequence->SelectedClips(false); - - Load(); - } -} - -void EffectsPanel::Load() { - bool graph_editor_row_is_still_active = false; - - // load in new clips - for (int i=0;i effects_to_open; - - // Determine based on the current selections whether to load all effects or just the transitions - bool whole_clip_is_selected = c->IsSelected(); - - if (whole_clip_is_selected) { - for (int j=0;jeffects.size();j++) { - effects_to_open.append(c->effects.at(j).get()); - } - } - if (c->opening_transition != nullptr - && (whole_clip_is_selected || c->track()->IsTransitionSelected(c->opening_transition.get()))) { - effects_to_open.append(c->opening_transition.get()); - } - if (c->closing_transition != nullptr - && (whole_clip_is_selected || c->track()->IsTransitionSelected(c->closing_transition.get()))) { - effects_to_open.append(c->closing_transition.get()); - } - - for (int j=0;jGetEffect()->id() == effects_to_open.at(j)->id() - && !open_effects_.at(k)->IsAttachedToClip(c)) { - - open_effects_.at(k)->AddAdditionalEffect(effects_to_open.at(j)); - - already_opened = true; - - break; - } - } - - if (!already_opened) { - open_effect(effects_to_open.at(j)); - } - - // Check if one of the open effects contains the row currently active in the graph editor. If not, we'll have - // to clear the graph editor later. - if (!graph_editor_row_is_still_active) { - for (int k=0;kParameterCount();k++) { - NodeIO* row = effects_to_open.at(j)->Parameter(k); - if (row == panel_graph_editor->get_row()) { - graph_editor_row_is_still_active = true; - break; - } - } - } - } - } - - // If the graph editor's currently active row is not part of the current effects, clear it - if (!graph_editor_row_is_still_active) { - panel_graph_editor->set_row(nullptr); - } - - LoadEvent(); -} - -bool EffectsPanel::IsEffectSelected(OldEffectNode *e) -{ - for (int i=0;iGetEffect() == e && open_effects_.at(i)->IsSelected()) { - return true; - } - } - return false; -} - -void EffectsPanel::deselect_all_effects(QWidget* sender) { - - for (int i=0;iDeselect(); - } - } - - if (panel_sequence_viewer != nullptr) { - panel_sequence_viewer->viewer_widget()->update(); - } -} - -void EffectsPanel::cut() { - copy(true); -} - -void EffectsPanel::copy(bool del) { - bool cleared = false; - - ComboAction* ca = nullptr; - if (del) { - ca = new ComboAction(); - } - - for (int i=0;iIsSelected()) { - OldEffectNode* e = open_effects_.at(i)->GetEffect(); - - if (e->type() == EFFECT_TYPE_EFFECT) { - - if (!cleared) { - olive::clipboard.Clear(); - cleared = true; - olive::clipboard.SetType(Clipboard::CLIPBOARD_TYPE_EFFECT); - } - - olive::clipboard.Append(e->copy(nullptr)); - - if (del) { - - DeleteEffect(ca, e); - - } - - } - } - } - - if (del) { - if (ca->hasActions()) { - olive::undo_stack.push(ca); - } else { - delete ca; - } - } -} - -void EffectsPanel::AboutToClearEvent() -{ -} - -void EffectsPanel::DeleteEffect(ComboAction* ca, OldEffectNode* effect_ref) { - if (effect_ref->type() == EFFECT_TYPE_EFFECT) { - - ca->append(new EffectDeleteCommand(effect_ref)); - - } else if (effect_ref->type() == EFFECT_TYPE_TRANSITION) { - - // Retrieve shared ptr for this transition - - Clip* attached_clip = effect_ref->parent_clip; - - TransitionPtr t = nullptr; - - if (attached_clip->opening_transition.get() == effect_ref) { - - t = attached_clip->opening_transition; - - } else if (attached_clip->closing_transition.get() == effect_ref) { - - t = attached_clip->closing_transition; - - } - - if (t == nullptr) { - - qWarning() << "Failed to delete transition, couldn't find clip link."; - - } else { - - ca->append(new DeleteTransitionCommand(t)); - - } - - } -} - -void EffectsPanel::DeleteSelectedEffects() { - ComboAction* ca = new ComboAction(); - - for (int i=0;iIsSelected()) { - DeleteEffect(ca, open_effects_.at(i)->GetEffect()); - } - } - - if (ca->hasActions()) { - olive::undo_stack.push(ca); - update_ui(true); - } else { - delete ca; - } -} - -void EffectsPanel::open_effect(OldEffectNode* e) { - EffectUI* container = new EffectUI(e); - - connect(container, SIGNAL(CutRequested()), this, SLOT(cut())); - connect(container, SIGNAL(CopyRequested()), this, SLOT(copy())); - connect(container, SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*))); - - open_effects_.append(container); -} diff --git a/panels/effectspanel.h b/panels/effectspanel.h deleted file mode 100644 index ce1105541..000000000 --- a/panels/effectspanel.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef EFFECTSPANEL_H -#define EFFECTSPANEL_H - -#include "ui/panel.h" -#include "ui/effectui.h" -#include "timeline/clip.h" - -class EffectsPanel : public Panel -{ - Q_OBJECT -public: - explicit EffectsPanel(QWidget *parent = nullptr); - virtual ~EffectsPanel() override; - - void Reload(); - void SetClips(); - void Clear(bool clear_cache = true); - - virtual bool focused() override; - - bool IsEffectSelected(OldEffectNode* e); - void DeleteSelectedEffects(); - -public slots: - void cut(); - void copy(bool del = false); -protected: - virtual void AboutToClearEvent(); - virtual void ClearEvent(); - virtual void LoadEvent(); - - QVector selected_clips_; - QVector open_effects_; -private: - void Load(); - void open_effect(OldEffectNode *e); - void DeleteEffect(ComboAction* ca, OldEffectNode* effect_ref); -private slots: - void deselect_all_effects(QWidget*); -}; - -#endif // EFFECTSPANEL_H diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp deleted file mode 100644 index 644999cd9..000000000 --- a/panels/grapheditor.cpp +++ /dev/null @@ -1,256 +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 "grapheditor.h" - -#include -#include -#include -#include - -#include "ui/keyframenavigator.h" -#include "ui/timelineheader.h" -#include "timeline/timelinetools.h" -#include "ui/labelslider.h" -#include "ui/graphview.h" -#include "nodes/oldeffectnode.h" -#include "effects/effectfields.h" -#include "nodes/nodeio.h" -#include "timeline/clip.h" -#include "rendering/renderfunctions.h" -#include "panels.h" -#include "ui/icons.h" -#include "global/debug.h" - -GraphEditor::GraphEditor(QWidget* parent) : Panel(parent), row(nullptr) { - resize(720, 480); - - QWidget* main_widget = new QWidget(this); - QVBoxLayout* layout = new QVBoxLayout(main_widget); - setWidget(main_widget); - - QWidget* tool_widget = new QWidget(); - tool_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - QHBoxLayout* tools = new QHBoxLayout(tool_widget); - - QWidget* left_tool_widget = new QWidget(); - QHBoxLayout* left_tool_layout = new QHBoxLayout(left_tool_widget); - left_tool_layout->setSpacing(0); - left_tool_layout->setMargin(0); - tools->addWidget(left_tool_widget); - QWidget* center_tool_widget = new QWidget(); - QHBoxLayout* center_tool_layout = new QHBoxLayout(center_tool_widget); - center_tool_layout->setSpacing(0); - center_tool_layout->setMargin(0); - tools->addWidget(center_tool_widget); - QWidget* right_tool_widget = new QWidget(); - QHBoxLayout* right_tool_layout = new QHBoxLayout(right_tool_widget); - right_tool_layout->setSpacing(0); - right_tool_layout->setMargin(0); - tools->addWidget(right_tool_widget); - - keyframe_nav = new KeyframeNavigator(nullptr, false); - keyframe_nav->enable_keyframes(true); - keyframe_nav->enable_keyframe_toggle(false); - left_tool_layout->addWidget(keyframe_nav); - left_tool_layout->addStretch(); - - linear_button = new QPushButton(); - linear_button->setProperty("type", EFFECT_KEYFRAME_LINEAR); - linear_button->setCheckable(true); - bezier_button = new QPushButton(); - bezier_button->setProperty("type", EFFECT_KEYFRAME_BEZIER); - bezier_button->setCheckable(true); - hold_button = new QPushButton(); - hold_button->setProperty("type", EFFECT_KEYFRAME_HOLD); - hold_button->setCheckable(true); - - center_tool_layout->addStretch(); - center_tool_layout->addWidget(linear_button); - center_tool_layout->addWidget(bezier_button); - center_tool_layout->addWidget(hold_button); - - layout->addWidget(tool_widget); - - QWidget* central_widget = new QWidget(); - QVBoxLayout* central_layout = new QVBoxLayout(central_widget); - central_layout->setSpacing(0); - central_layout->setMargin(0); - header = new TimelineHeader(); - header->viewer = panel_sequence_viewer; - central_layout->addWidget(header); - view = new GraphView(); - central_layout->addWidget(view); - - layout->addWidget(central_widget); - - QWidget* value_widget = new QWidget(); - value_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - QHBoxLayout* values = new QHBoxLayout(value_widget); - values->addStretch(); - - QWidget* central_value_widget = new QWidget(); - value_layout = new QHBoxLayout(central_value_widget); - value_layout->setMargin(0); - value_layout->addWidget(new QLabel("")); // a spacer so the layout doesn't jump - values->addWidget(central_value_widget); - - values->addStretch(); - layout->addWidget(value_widget); - - current_row_desc = new QLabel(); - current_row_desc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - current_row_desc->setAlignment(Qt::AlignCenter); - layout->addWidget(current_row_desc); - - connect(view, SIGNAL(zoom_changed(double, double)), header, SLOT(update_zoom(double))); - connect(view, SIGNAL(x_scroll_changed(int)), header, SLOT(set_scroll(int))); - connect(view, SIGNAL(selection_changed(bool, int)), this, SLOT(set_key_button_enabled(bool, int))); - - connect(linear_button, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_type())); - connect(bezier_button, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_type())); - connect(hold_button, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_type())); - - Retranslate(); -} - -NodeIO *GraphEditor::get_row() -{ - return row; -} - -void GraphEditor::Retranslate() { - setWindowTitle(tr("Graph Editor")); - linear_button->setText(tr("Linear")); - bezier_button->setText(tr("Bezier")); - hold_button->setText(tr("Hold")); -} - -void GraphEditor::update_panel() { - if (isVisible()) { - if (row != nullptr) { - int slider_index = 0; - for (int i=0;iFieldCount();i++) { - EffectField* field = row->Field(i); - if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { - field->UpdateWidgetValue(field_sliders_.at(slider_index), row->ParentNode()->Time()); - slider_index++; - } - } - } - - header->update(); - view->update(); - } -} - -bool GraphEditor::focused() -{ - return hasFocus() || view->hasFocus() || header->hasFocus(); -} - -void GraphEditor::set_row(NodeIO *r) { - for (int i=0;iIsKeyframing()) { - for (int i=0;iFieldCount();i++) { - EffectField* field = r->Field(i); - if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { - QPushButton* slider_button = new QPushButton(); - slider_button->setCheckable(true); - slider_button->setChecked(field->IsEnabled()); - slider_button->setIcon(olive::icon::CreateIconFromSVG(":/icons/record.svg", false)); - slider_button->setProperty("field", i); - slider_button->setIconSize(slider_button->iconSize()*0.5); - connect(slider_button, SIGNAL(toggled(bool)), this, SLOT(set_field_visibility(bool))); - field_enable_buttons.append(slider_button); - value_layout->addWidget(slider_button); - - LabelSlider* slider = static_cast(field->CreateWidget()); - slider->SetColor(get_curve_color(i, r->FieldCount()).name()); - field_sliders_.append(slider); - value_layout->addWidget(slider); - - found_vals = true; - } - } - } - - if (found_vals) { - row = r; - /* FIXME - current_row_desc->setText(row->ParentNode()->parent_clip->name() - + " :: " + row->GetParentEffect()->name() - + " :: " + row->name()); - header->set_visible_in(r->ParentNode()->parent_clip->timeline_in()); - */ - - connect(keyframe_nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); - connect(keyframe_nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); - connect(keyframe_nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); - } else { - row = nullptr; - current_row_desc->setText(nullptr); - } - view->set_row(row); - update_panel(); -} - -void GraphEditor::delete_selected_keys() { - view->delete_selected_keys(); -} - -void GraphEditor::select_all() { - view->select_all(); -} - -void GraphEditor::set_key_button_enabled(bool e, int type) { - linear_button->setEnabled(e); - linear_button->setChecked(type == EFFECT_KEYFRAME_LINEAR); - bezier_button->setEnabled(e); - bezier_button->setChecked(type == EFFECT_KEYFRAME_BEZIER); - hold_button->setEnabled(e); - hold_button->setChecked(type == EFFECT_KEYFRAME_HOLD); -} - -void GraphEditor::set_keyframe_type() { - linear_button->setChecked(linear_button == sender()); - bezier_button->setChecked(bezier_button == sender()); - hold_button->setChecked(hold_button == sender()); - view->set_selected_keyframe_type(sender()->property("type").toInt()); -} - -void GraphEditor::set_field_visibility(bool b) { - view->set_field_visibility(sender()->property("field").toInt(), b); -} diff --git a/panels/grapheditor.h b/panels/grapheditor.h deleted file mode 100644 index b1f392a9a..000000000 --- a/panels/grapheditor.h +++ /dev/null @@ -1,68 +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 GRAPHEDITOR_H -#define GRAPHEDITOR_H - -#include -#include -#include - -#include "ui/panel.h" -#include "ui/graphview.h" -#include "ui/timelineheader.h" -#include "ui/labelslider.h" -#include "ui/keyframenavigator.h" -#include "nodes/nodeio.h" - -class GraphEditor : public Panel { - Q_OBJECT -public: - GraphEditor(QWidget* parent = nullptr); - - NodeIO* get_row(); - void set_row(NodeIO* r); - - void update_panel(); - virtual bool focused() override; - void delete_selected_keys(); - void select_all(); - - virtual void Retranslate() override; -protected: -private: - GraphView* view; - TimelineHeader* header; - QHBoxLayout* value_layout; - QVector field_sliders_; - QVector field_enable_buttons; - QLabel* current_row_desc; - NodeIO* row; - KeyframeNavigator* keyframe_nav; - QPushButton* linear_button; - QPushButton* bezier_button; - QPushButton* hold_button; -private slots: - void set_key_button_enabled(bool e, int type); - void set_keyframe_type(); - void set_field_visibility(bool b); -}; - -#endif // GRAPHEDITOR_H diff --git a/panels/nodeeditor.cpp b/panels/nodeeditor.cpp deleted file mode 100644 index 1727e3b9e..000000000 --- a/panels/nodeeditor.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "nodeeditor.h" - -#include -#include -#include -#include -#include -#include - -#include "global/global.h" - -NodeEditor::NodeEditor(QWidget *parent) : - EffectsPanel(parent), - view_(&scene_) -{ - setWindowTitle(tr("Node Editor")); - resize(720, 480); - - QWidget* central_widget = new QWidget(); - setWidget(central_widget); - - QSplitter* splitter = new QSplitter(); - splitter->setOrientation(Qt::Horizontal); - splitter->setChildrenCollapsible(false); - - splitter->addWidget(&view_); - - QSizePolicy view_policy; - view_policy.setHorizontalStretch(1); - view_.setSizePolicy(view_policy); - view_.setInteractive(true); - view_.setDragMode(QGraphicsView::RubberBandDrag); - - prop_layout_ = new QVBoxLayout(&props_); - prop_layout_->setMargin(0); - prop_layout_->setSpacing(0); - prop_layout_->addStretch(); - splitter->addWidget(&props_); - - QVBoxLayout* layout = new QVBoxLayout(central_widget); - layout->setSpacing(0); - layout->setMargin(0); - - layout->addWidget(splitter); - - connect(&scene_, SIGNAL(changed(const QList&)), this, SLOT(ItemsChanged())); - connect(&scene_, SIGNAL(selectionChanged()), this, SLOT(UpdateNodeProperties())); - connect(&view_, SIGNAL(RequestContextMenu()), this, SLOT(ContextMenu())); -} - -NodeEditor::~NodeEditor() -{ - Clear(true); -} - -void NodeEditor::Retranslate() -{ -} - -void NodeEditor::LoadEvent() -{ - if (!open_effects_.isEmpty()) { - QVector added_edges; - - Clip* first_clip = open_effects_.first()->GetEffect()->parent_clip; - - for (int i=0;iGetEffect(); - - if (node->parent_clip == first_clip) { - NodeUI* node_ui = new NodeUI(); - - effect_ui->SetSelectable(false); - - node_ui->SetNode(node); - node_ui->AddToScene(&scene_); - node_ui->setPos(effect_ui->GetEffect()->pos()); - - nodes_.append(node_ui); - - effect_ui->setVisible(false); - prop_layout_->insertWidget(prop_layout_->count()-1, effect_ui); - } - } - } - - LoadEdges(); -} - -void NodeEditor::AboutToClearEvent() -{ - foreach (NodeUI* node, nodes_) { - delete node; - } - - nodes_.clear(); - - ClearEdges(); -} - -void NodeEditor::ClearEdges() -{ - foreach (NodeEdgeUI* edge, edges_) { - scene_.removeItem(edge); - delete edge; - } - - edges_.clear(); - - DisconnectAllRows(); -} - -void NodeEditor::LoadEdges() -{ - if (!open_effects_.isEmpty()) { - QVector added_edges; - - Clip* first_clip = open_effects_.first()->GetEffect()->parent_clip; - - for (int i=0;iGetEffect(); - - if (n->parent_clip == first_clip) { - - // Connect all rows to this - for (int j=0;jParameterCount();j++) { - ConnectRow(n->Parameter(j)); - } - - // Get node edges - QVector edges = n->GetAllEdges(); - for (int j=0;jadjust(); - } - - foreach (NodeUI* node, nodes_) { - node->GetNode()->SetPos(node->pos()); - } -} - -void NodeEditor::ReloadEdges() -{ - ClearEdges(); - LoadEdges(); -} - -void NodeEditor::ContextMenu() -{ - if (!open_effects_.isEmpty()) { - Clip* c = open_effects_.first()->GetEffect()->parent_clip; - olive::Global->ShowEffectMenu(EFFECT_TYPE_EFFECT, c->type(), {c}); - } -} - -void NodeEditor::UpdateNodeProperties() -{ - // Find matching widget - for (int j=0;jsetVisible(false); - } - - QList sel = scene_.selectedItems(); - for (int i=0;i(sel.at(i)); - - if (node_ui != nullptr) { - for (int j=0;jGetEffect() == node_ui->GetNode()) { - open_effects_.at(j)->setVisible(true); - break; - } - } - } - } -} diff --git a/panels/nodeeditor.h b/panels/nodeeditor.h deleted file mode 100644 index 6742dccaa..000000000 --- a/panels/nodeeditor.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef NODEEDITOR_H -#define NODEEDITOR_H - -#include - -#include "effectspanel.h" -#include "ui/nodeview.h" -#include "ui/nodeui.h" -#include "ui/nodeedgeui.h" - -class NodeEditor : public EffectsPanel { - Q_OBJECT -public: - NodeEditor(QWidget* parent = nullptr); - virtual ~NodeEditor() override; - - virtual void Retranslate() override; - -protected: - virtual void LoadEvent() override; - virtual void AboutToClearEvent() override; - -private: - QGraphicsScene scene_; - NodeView view_; - QWidget props_; - QVector nodes_; - QVector edges_; - QVector connected_rows_; - QVBoxLayout* prop_layout_; - QVector nodes_open_in_props_; - - void ClearEdges(); - void LoadEdges(); - - void ConnectRow(NodeIO* row); - void DisconnectAllRows(); - -private slots: - void ItemsChanged(); - void ReloadEdges(); - void ContextMenu(); - void UpdateNodeProperties(); -}; - -#endif // NODEEDITOR_H diff --git a/panels/panels.cpp b/panels/panels.cpp deleted file mode 100644 index 06af4b80b..000000000 --- a/panels/panels.cpp +++ /dev/null @@ -1,128 +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 "panels.h" - -#include "timeline/sequence.h" -#include "timeline/clip.h" -#include "effects/transition.h" -#include "global/config.h" -#include "global/debug.h" -#include "global/math.h" - -#include -#include - -QVector panel_project; -EffectControls* panel_effect_controls = nullptr; -Viewer* panel_sequence_viewer = nullptr; -Viewer* panel_footage_viewer = nullptr; -QVector panel_timeline; -GraphEditor* panel_graph_editor = nullptr; -NodeEditor* panel_node_editor = nullptr; - -void update_ui(bool modified) { - if (modified) { - panel_effect_controls->SetClips(); - panel_node_editor->SetClips(); - } - panel_effect_controls->update_keyframes(); - for (int i=0;irepaint_timeline(); - } - panel_sequence_viewer->update_viewer(); - panel_graph_editor->update_panel(); -} - -QDockWidget *get_focused_panel(bool force_hover) { - QDockWidget* w = nullptr; - if (olive::config.hover_focus || force_hover) { - for (int i=0;iunderMouse()) { - w = olive::panels.at(i); - break; - } - } - } - if (w == nullptr) { - for (int i=0;ifocused()) { - w = olive::panels.at(i); - break; - } - } - } - return w; -} - -void alloc_panels(QWidget* parent) { - panel_sequence_viewer = new Viewer(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); - Project* first_project_panel = new Project(parent); - first_project_panel->setObjectName("proj_root"); - panel_project.append(first_project_panel); - panel_effect_controls = new EffectControls(parent); - panel_effect_controls->setObjectName("fx_controls"); - Timeline* first_timeline_panel = new Timeline(parent); - first_timeline_panel->setObjectName("timeline"); - panel_timeline.append(first_timeline_panel); - panel_graph_editor = new GraphEditor(parent); - panel_graph_editor->setObjectName("graph_editor"); - panel_node_editor = new NodeEditor(parent); - panel_node_editor->setObjectName("node_editor"); -} - -void free_panels() { - delete panel_sequence_viewer; - panel_sequence_viewer = nullptr; - delete panel_footage_viewer; - panel_footage_viewer = nullptr; - - for (int i=0;ivalue() == bar->minimum() || bar->value() == bar->maximum()) { - return; - } - - int screen_point = getScreenPointFromFrame(zoom, frame) - bar->value(); - int min_x = area_width*0.1; - int max_x = area_width-min_x; - if (screen_point < min_x) { - bar->setValue(getScreenPointFromFrame(zoom, frame) - min_x); - } else if (screen_point > max_x) { - bar->setValue(getScreenPointFromFrame(zoom, frame) - max_x); - } -} diff --git a/panels/panels.h b/panels/panels.h deleted file mode 100644 index cbce80272..000000000 --- a/panels/panels.h +++ /dev/null @@ -1,45 +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 PANELS_H -#define PANELS_H - -#include "timeline.h" -#include "effectcontrols.h" -#include "viewer.h" -#include "grapheditor.h" -#include "project.h" -#include "nodeeditor.h" - -extern QVector panel_project; -extern EffectControls* panel_effect_controls; -extern Viewer* panel_sequence_viewer; -extern Viewer* panel_footage_viewer; -extern QVector panel_timeline; -extern GraphEditor* panel_graph_editor; -extern NodeEditor* panel_node_editor; - -void update_ui(bool modified); -QDockWidget* get_focused_panel(bool force_hover = false); -void alloc_panels(QWidget *parent); -void free_panels(); -void scroll_to_frame_internal(QScrollBar* bar, long frame, double zoom, int area_width); - -#endif // PANELS_H diff --git a/panels/project.cpp b/panels/project.cpp deleted file mode 100644 index 2796aca77..000000000 --- a/panels/project.cpp +++ /dev/null @@ -1,658 +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 "project.h" - -extern "C" { -#include -#include -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "panels.h" -#include "rendering/renderfunctions.h" -#include "project/previewgenerator.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "ui/mainwindow.h" -#include "global/config.h" -#include "rendering/cacher.h" -#include "dialogs/replaceclipmediadialog.h" -#include "panels/effectcontrols.h" -#include "dialogs/mediapropertiesdialog.h" -#include "dialogs/newsequencedialog.h" -#include "dialogs/loaddialog.h" -#include "global/clipboard.h" -#include "ui/sourcetable.h" -#include "ui/sourceiconview.h" -#include "ui/icons.h" -#include "ui/menuhelper.h" -#include "ui/mediaiconservice.h" -#include "project/sourcescommon.h" -#include "project/projectfilter.h" -#include "project/projectfunctions.h" -#include "global/debug.h" -#include "ui/menu.h" - -Project::Project(QWidget *parent) : - Panel(parent), - sorter(this), - sources_common(this, sorter) -{ - QWidget* dockWidgetContents = new QWidget(this); - - QVBoxLayout* verticalLayout = new QVBoxLayout(dockWidgetContents); - verticalLayout->setMargin(0); - verticalLayout->setSpacing(0); - - setWidget(dockWidgetContents); - - ConnectFilterToModel(); - - // optional toolbar - toolbar_widget = new QWidget(); - toolbar_widget->setVisible(olive::config.show_project_toolbar); - toolbar_widget->setObjectName("project_toolbar"); - - QHBoxLayout* toolbar = new QHBoxLayout(toolbar_widget); - toolbar->setMargin(0); - toolbar->setSpacing(0); - - QPushButton* toolbar_new = new QPushButton(); - toolbar_new->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/add-button.svg"))); - 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(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(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(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(tr("Redo")); - connect(toolbar_redo, SIGNAL(clicked(bool)), olive::Global.get(), SLOT(redo())); - toolbar->addWidget(toolbar_redo); - - toolbar_search = new QLineEdit(); - toolbar_search->setClearButtonEnabled(true); - connect(toolbar_search, SIGNAL(textChanged(QString)), &sorter, SLOT(update_search_filter(const QString&))); - toolbar->addWidget(toolbar_search); - - QPushButton* toolbar_tree_view = new QPushButton(); - toolbar_tree_view->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/treeview.svg"))); - 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(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 - tree_view = new SourceTable(sources_common); - tree_view->project_parent = this; - tree_view->setModel(&sorter); - verticalLayout->addWidget(tree_view); - - // Set the first column width - // I'm not sure if there's a better way to do this, default behavior seems to have all columns fixed width - // and let the last column fill up the remainder when really the opposite would be preferable (having the - // first column fill up the majority of the space). Anyway, this will probably do for now. - tree_view->setColumnWidth(0, tree_view->width()/2); - - // icon view - icon_view_container = new QWidget(); - - QVBoxLayout* icon_view_container_layout = new QVBoxLayout(icon_view_container); - icon_view_container_layout->setMargin(0); - icon_view_container_layout->setSpacing(0); - - QHBoxLayout* icon_view_controls = new QHBoxLayout(); - icon_view_controls->setMargin(0); - icon_view_controls->setSpacing(0); - - directory_up = new QPushButton(); - directory_up->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/dirup.svg"))); - directory_up->setEnabled(false); - icon_view_controls->addWidget(directory_up); - - icon_view_controls->addStretch(); - - icon_size_slider = new QSlider(Qt::Horizontal); - icon_size_slider->setMinimum(16); - 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))); - - icon_view_container_layout->addLayout(icon_view_controls); - - icon_view = new SourceIconView(sources_common); - icon_view->project_parent = this; - icon_view->setModel(&sorter); - 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->gridSize().height()); - - verticalLayout->addWidget(icon_view_container); - - connect(directory_up, SIGNAL(clicked(bool)), this, SLOT(go_up_dir())); - connect(icon_view, SIGNAL(changed_root()), this, SLOT(set_up_dir_enabled())); - - connect(olive::media_icon_service.get(), SIGNAL(IconChanged()), icon_view->viewport(), SLOT(update())); - connect(olive::media_icon_service.get(), SIGNAL(IconChanged()), tree_view->viewport(), SLOT(update())); - - update_view_type(); - - Retranslate(); -} - -void Project::ConnectFilterToModel() -{ - sorter.setSourceModel(&olive::project_model); -} - -void Project::DisconnectFilterToModel() -{ - sorter.setSourceModel(nullptr); -} - -void Project::Retranslate() { - toolbar_search->setPlaceholderText(tr("Search media, markers, etc.")); - setWindowTitle(tr("Project")); -} - -void Project::duplicate_selected() { - QModelIndexList items = get_current_selected(); - bool duped = false; - ComboAction* ca = new ComboAction(); - for (int j=0;jget_type() == MEDIA_TYPE_SEQUENCE) { - olive::project_model.CreateSequence(ca, i->to_sequence()->copy(), false, item_to_media(items.at(j).parent())); - duped = true; - } - } - if (duped) { - olive::undo_stack.push(ca); - } else { - delete ca; - } -} - -void Project::replace_selected_file() { - QModelIndexList selected_items = get_current_selected(); - if (selected_items.size() == 1) { - MediaPtr item = item_to_media_ptr(selected_items.at(0)); - if (item->get_type() == MEDIA_TYPE_FOOTAGE) { - sources_common.replace_media(item, nullptr); - } - } -} - -void Project::replace_clip_media() { - Sequence* top_sequence = Timeline::GetTopSequence().get(); - - if (top_sequence == nullptr) { - QMessageBox::critical(this, - tr("No active sequence"), - tr("No sequence is active, please open the sequence you want to replace clips from."), - QMessageBox::Ok); - } else { - QModelIndexList selected_items = get_current_selected(); - if (selected_items.size() == 1) { - Media* item = item_to_media(selected_items.at(0)); - if (item->get_type() == MEDIA_TYPE_SEQUENCE && top_sequence == item->to_sequence().get()) { - QMessageBox::critical(this, - tr("Active sequence selected"), - tr("You cannot insert a sequence into itself, so no clips of this media would be in this sequence."), - QMessageBox::Ok); - } else { - ReplaceClipMediaDialog dialog(this, item); - dialog.exec(); - } - } - } -} - -void Project::open_properties() { - QModelIndexList selected_items = get_current_selected(); - if (selected_items.size() == 1) { - Media* item = item_to_media(selected_items.at(0)); - switch (item->get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - MediaPropertiesDialog mpd(this, item); - mpd.exec(); - } - break; - case MEDIA_TYPE_SEQUENCE: - { - NewSequenceDialog nsd(this, item); - nsd.exec(); - } - break; - default: - { - // fall back to renaming - QString new_name = QInputDialog::getText(this, - tr("Rename '%1'").arg(item->get_name()), - tr("Enter new name:"), - QLineEdit::Normal, - item->get_name()); - if (!new_name.isEmpty()) { - MediaRename* mr = new MediaRename(item, new_name); - olive::undo_stack.push(mr); - } - } - } - } -} - -void Project::new_folder() { - MediaPtr m = olive::project::CreateFolder(nullptr); - olive::undo_stack.push(new AddMediaCommand(m, get_selected_folder())); - - QModelIndex index = olive::project_model.create_index(m->row(), 0, m.get()); - switch (olive::config.project_view_type) { - case olive::PROJECT_VIEW_TREE: - tree_view->edit(sorter.mapFromSource(index)); - break; - case olive::PROJECT_VIEW_ICON: - icon_view->edit(sorter.mapFromSource(index)); - break; - } -} - -bool Project::focused() { - return tree_view->hasFocus() || icon_view->hasFocus(); -} - -Media* Project::item_to_media(const QModelIndex &index) { - return static_cast(sorter.mapToSource(index).internalPointer()); -} - -MediaPtr Project::item_to_media_ptr(const QModelIndex &index) { - Media* raw_ptr = item_to_media(index); - - if (raw_ptr == nullptr) { - return nullptr; - } - - return raw_ptr->parentItem()->get_shared_ptr(raw_ptr); -} - -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); -} - -void Project::delete_selected_media() { - ComboAction* ca = new ComboAction(); - QModelIndexList selected_items = get_current_selected(); - - QList items; - for (int i=0;i parents; - QVector all_sequences = olive::project_model.GetAllSequences(); - if (all_sequences.size() > 0) { - - QVector all_footage = olive::project_model.GetAllFootage(); - - for (int i=0;ito_footage(); - bool confirm_delete = false; - for (int j=0;jto_sequence().get(); - QVector sequence_clips = s->GetAllClips(); - - for (int k=0;kmedia() == item) { - if (!confirm_delete) { - // we found a reference, so we know we'll need to ask if the user wants to delete it - QMessageBox confirm(this); - confirm.setWindowTitle(tr("Delete media in use?")); - confirm.setText(tr("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?").arg(media->name, s->name())); - QAbstractButton* yes_button = confirm.addButton(QMessageBox::Yes); - QAbstractButton* skip_button = nullptr; - if (items.size() > 1) skip_button = confirm.addButton(tr("Skip"), QMessageBox::NoRole); - QAbstractButton* abort_button = confirm.addButton(QMessageBox::Cancel); - confirm.exec(); - if (confirm.clickedButton() == yes_button) { - // remove all clips referencing this media - confirm_delete = true; - redraw = true; - } else if (confirm.clickedButton() == skip_button) { - // remove media item and any folders containing it from the remove list - Media* parent = item; - while (parent != nullptr) { - parents.append(parent); - - // re-add item's siblings - for (int m=0;mchildCount();m++) { - Media* child = parent->child(m); - bool found = false; - for (int n=0;nparentItem(); - } - - j = all_sequences.size(); - k = sequence_clips.size(); - } else if (confirm.clickedButton() == abort_button) { - // break out of loop - i = all_footage.size(); - j = all_sequences.size(); - k = sequence_clips.size(); - - remove = false; - } - } - if (confirm_delete) { - ca->append(new DeleteClipAction(c)); - } - } - } - } - if (confirm_delete) { - olive::clipboard.DeleteClipsWithMedia(ca, item); - } - } - } - - // remove - if (remove) { - panel_graph_editor->set_row(nullptr); - panel_effect_controls->Clear(true); - - Sequence* top_sequence = Timeline::GetTopSequence().get(); - if (top_sequence != nullptr) { - top_sequence->ClearSelections(); - } - - // remove media and parents - for (int m=0;mappend(new DeleteMediaCommand(items.at(i)->parentItem()->get_shared_ptr(items.at(i)))); - - if (items.at(i)->get_type() == MEDIA_TYPE_SEQUENCE) { - redraw = true; - - Sequence* s = items.at(i)->to_sequence().get(); - - Timeline::CloseSequence(s); - - if (s == panel_footage_viewer->seq.get()) { - panel_footage_viewer->set_media(nullptr); - } - } else if (items.at(i)->get_type() == MEDIA_TYPE_FOOTAGE) { - if (panel_footage_viewer->media == items.at(i)) { - panel_footage_viewer->set_media(nullptr); - } - } - } - olive::undo_stack.push(ca); - - // redraw clips - if (redraw) { - update_ui(true); - } - } else { - delete ca; - } -} - -Media* Project::get_selected_folder() { - // if one item is selected and it's a folder, return it - QModelIndexList selected_items = get_current_selected(); - if (selected_items.size() == 1) { - Media* m = item_to_media(selected_items.at(0)); - if (m->get_type() == MEDIA_TYPE_FOLDER) return m; - } - return nullptr; -} - -bool Project::reveal_media(Media *media, QModelIndex parent) { - for (int i=0;iget_type() == MEDIA_TYPE_FOLDER) { - - // if this item is a folder, recursively run this function to search it too - if (reveal_media(media, item)) return true; - - } else if (m == media) { - // 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); - - // retrieve its parent item - QModelIndex hierarchy = sorted_index.parent(); - - if (olive::config.project_view_type == olive::PROJECT_VIEW_TREE) { - - // if we're in tree view, expand every folder in the hierarchy containing the media - while (hierarchy.isValid()) { - tree_view->setExpanded(hierarchy, true); - hierarchy = hierarchy.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()) - ); - - tree_view->selectionModel()->select(row_select, QItemSelectionModel::Select); - } else if (olive::config.project_view_type == olive::PROJECT_VIEW_ICON) { - - // if we're in icon view, we just "browse" to the parent folder - icon_view->setRootIndex(hierarchy); - - // select item in this folder - icon_view->selectionModel()->select(sorted_index, QItemSelectionModel::Select); - - // update the "up" button state - set_up_dir_enabled(); - - } - - return true; - } - } - - return false; -} - -void Project::delete_clips_using_selected_media() { - Sequence* top_sequence = Timeline::GetTopSequence().get(); - - if (top_sequence == nullptr) { - QMessageBox::critical(this, - tr("No active sequence"), - tr("No sequence is active, please open the sequence you want to delete clips from."), - QMessageBox::Ok); - } else { - - QModelIndexList items = get_current_selected(); - QVector media; - - media.resize(items.size()); - - for (int i=0;iDeleteClipsUsingMedia(media); - - } -} - -void Project::update_view_type() { - tree_view->setVisible(olive::config.project_view_type == olive::PROJECT_VIEW_TREE); - icon_view_container->setVisible(olive::config.project_view_type == olive::PROJECT_VIEW_ICON - || olive::config.project_view_type == olive::PROJECT_VIEW_LIST); - - - switch (olive::config.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::config.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; - } -} - -void Project::set_icon_view() { - olive::config.project_view_type = olive::PROJECT_VIEW_ICON; - update_view_type(); -} - -void Project::set_list_view() -{ - olive::config.project_view_type = olive::PROJECT_VIEW_LIST; - update_view_type(); -} - -void Project::set_tree_view() { - olive::config.project_view_type = olive::PROJECT_VIEW_TREE; - update_view_type(); -} - -void Project::set_icon_view_size(int 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() { - directory_up->setEnabled(icon_view->rootIndex().isValid()); -} - -void Project::go_up_dir() { - icon_view->setRootIndex(icon_view->rootIndex().parent()); - set_up_dir_enabled(); -} - -void Project::make_new_menu() { - Menu new_menu(this); - olive::MenuHelper.make_new_menu(&new_menu); - new_menu.exec(QCursor::pos()); -} - -QModelIndexList Project::get_current_selected() { - if (olive::config.project_view_type == olive::PROJECT_VIEW_TREE) { - return tree_view->selectionModel()->selectedRows(); - } - return icon_view->selectionModel()->selectedIndexes(); -} diff --git a/panels/project.h b/panels/project.h deleted file mode 100644 index 973c902b2..000000000 --- a/panels/project.h +++ /dev/null @@ -1,97 +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 PROJECT_H -#define PROJECT_H - -#include -#include -#include -#include -#include -#include -#include - -#include "project/projectmodel.h" -#include "project/projectfilter.h" -#include "project/projectelements.h" -#include "project/sourcescommon.h" -#include "ui/panel.h" -#include "ui/sourceiconview.h" -#include "timeline/mediaimportdata.h" -#include "undo/undo.h" -#include "ui/sourcetable.h" - -class Project : public Panel { - Q_OBJECT -public: - explicit Project(QWidget *parent = nullptr); - - void ConnectFilterToModel(); - void DisconnectFilterToModel(); - - virtual bool focused() override; - - Media* get_selected_folder(); - bool reveal_media(Media *media, QModelIndex parent = QModelIndex()); - - Media* item_to_media(const QModelIndex& index); - MediaPtr item_to_media_ptr(const QModelIndex &index); - - QModelIndexList get_current_selected(); - - bool IsToolbarVisible(); - bool IsProjectWidget(QObject *child); - - virtual void Retranslate() override; -protected: -public slots: - void delete_selected_media(); - void duplicate_selected(); - void delete_clips_using_selected_media(); - void replace_selected_file(); - void replace_clip_media(); - void open_properties(); - void new_folder(); - void SetToolbarVisible(bool visible); -private: - QWidget* icon_view_container; - QSlider* icon_size_slider; - 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(); - void set_list_view(); - void set_tree_view(); - void set_icon_view_size(int); - void set_up_dir_enabled(); - void go_up_dir(); - void make_new_menu(); -}; - -#endif // PROJECT_H diff --git a/panels/timeline.cpp b/panels/timeline.cpp deleted file mode 100644 index d13e78f1d..000000000 --- a/panels/timeline.cpp +++ /dev/null @@ -1,1126 +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 "timeline.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "panels/panels.h" -#include "project/projectelements.h" -#include "ui/timelineview.h" -#include "ui/icons.h" -#include "ui/viewerwidget.h" -#include "rendering/audio.h" -#include "rendering/cacher.h" -#include "rendering/renderfunctions.h" -#include "global/config.h" -#include "global/clipboard.h" -#include "global/math.h" -#include "ui/timelineheader.h" -#include "ui/resizablescrollbar.h" -#include "ui/audiomonitor.h" -#include "ui/flowlayout.h" -#include "ui/cursors.h" -#include "ui/mainwindow.h" -#include "undo/undostack.h" -#include "global/debug.h" -#include "global/timing.h" -#include "ui/menu.h" - -Timeline::Timeline(QWidget *parent) : - Panel(parent), - cursor_frame(0), - cursor_track(nullptr), - zoom(1.0), - zoom_just_changed(false), - showing_all(false), - selecting(false), - rect_select_init(false), - rect_select_proc(false), - moving_init(false), - moving_proc(false), - move_insert(false), - trim_target(nullptr), - trim_type(olive::timeline::TRIM_NONE), - splitting(false), - importing(false), - importing_files(false), - creating(false), - transition_tool_init(false), - transition_tool_proc(false), - transition_tool_open_clip(nullptr), - transition_tool_close_clip(nullptr), - hand_moving(false), - block_repaints(false), - scroll(0), - sequence_(nullptr) -{ - setup_ui(); - - headers->viewer = panel_sequence_viewer; - - video_area->SetAlignment(olive::timeline::kAlignmentBottom); - - tool_buttons.append(toolArrowButton); - tool_buttons.append(toolEditButton); - tool_buttons.append(toolRippleButton); - tool_buttons.append(toolRazorButton); - tool_buttons.append(toolSlipButton); - tool_buttons.append(toolSlideButton); - tool_buttons.append(toolTransitionButton); - tool_buttons.append(toolHandButton); - - tool_button_group = new QButtonGroup(this); - tool_button_group->addButton(toolArrowButton); - tool_button_group->addButton(toolEditButton); - tool_button_group->addButton(toolRippleButton); - tool_button_group->addButton(toolRazorButton); - tool_button_group->addButton(toolSlipButton); - tool_button_group->addButton(toolSlideButton); - tool_button_group->addButton(toolTransitionButton); - tool_button_group->addButton(toolHandButton); - - toolArrowButton->click(); - - connect(horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(setScroll(int))); - connect(horizontalScrollBar, SIGNAL(resize_move(double)), this, SLOT(resize_move(double))); - connect(this, SIGNAL(SequenceChanged(SequencePtr)), panel_sequence_viewer, SLOT(set_sequence(SequencePtr))); - connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(visibility_changed_slot(bool))); - - update_sequence(); - - Retranslate(); -} - -Timeline *Timeline::GetTopTimeline() -{ - for (int i=0;iisVisible()) { - return panel_timeline.at(i); - } - } - - return nullptr; -} - -SequencePtr Timeline::GetTopSequence() -{ - Timeline* top_timeline = GetTopTimeline(); - - if (top_timeline != nullptr) { - return top_timeline->sequence_; - } - - return nullptr; -} - -void Timeline::OpenSequence(SequencePtr s) -{ - Q_ASSERT(s != nullptr); - - for (int i=0;isequence_ == s) { - t->raise(); - return; - } else if (t->sequence_ == nullptr) { - t->SetSequence(s); - t->raise(); - return; - } - } - - Timeline* t = new Timeline(olive::MainWindow); - olive::MainWindow->tabifyDockWidget(panel_timeline.last(), t); - t->SetSequence(s); - t->show(); - t->raise(); - panel_timeline.append(t); -} - -void Timeline::CloseSequence(Sequence *s) -{ - Q_ASSERT(s != nullptr); - - // Don't respond to a null sequence - if (s == nullptr) { - return; - } - - // If there's only one Timeline object left, just set it to nullptr without destroying it - if (panel_timeline.size() == 1) { - panel_timeline.first()->SetSequence(nullptr); - return; - } - - // If there are multiple, kill the Timeline object that has the specified sequence - for (int i=0;isequence_.get() == s) { - delete t; - panel_timeline.removeAt(i); - i--; - } - } -} - -void Timeline::CloseAll() -{ - while (panel_timeline.size() > 1) { - delete panel_timeline.last(); - panel_timeline.removeLast(); - } - panel_timeline.first()->SetSequence(nullptr); -} - -bool Timeline::IsImporting() -{ - for (int i=0;iimporting) { - return true; - } - } - return false; -} - -void Timeline::SetSequence(SequencePtr sequence) -{ - if (sequence_ == sequence) { - return; - } - - if (sequence_ != nullptr) { - sequence_->SetGLContext(nullptr); - } - - sequence_ = sequence; - - if (sequence_ != nullptr) { - sequence_->SetGLContext(QOpenGLContext::globalShareContext()); - } - - update_sequence(); - video_area->SetTrackType(sequence_.get(), olive::kTypeVideo); - audio_area->SetTrackType(sequence_.get(), olive::kTypeAudio); - repaint_timeline(); - - emit SequenceChanged(sequence_); -} - -void Timeline::Retranslate() { - toolArrowButton->setToolTip(tr("Pointer Tool") + " (V)"); - toolEditButton->setToolTip(tr("Edit Tool") + " (X)"); - toolRippleButton->setToolTip(tr("Ripple Tool") + " (B)"); - toolRazorButton->setToolTip(tr("Razor Tool") + " (C)"); - toolSlipButton->setToolTip(tr("Slip Tool") + " (Y)"); - toolSlideButton->setToolTip(tr("Slide Tool") + " (U)"); - toolHandButton->setToolTip(tr("Hand Tool") + " (H)"); - toolTransitionButton->setToolTip(tr("Transition Tool") + " (T)"); - snappingButton->setToolTip(tr("Snapping") + " (S)"); - zoomInButton->setToolTip(tr("Zoom In") + " (=)"); - zoomOutButton->setToolTip(tr("Zoom Out") + " (-)"); - recordButton->setToolTip(tr("Record audio")); - addButton->setToolTip(tr("Add title, solid, bars, etc.")); - - UpdateTitle(); -} - -void Timeline::toggle_show_all() { - if (sequence_ != nullptr) { - showing_all = !showing_all; - if (showing_all) { - old_zoom = zoom; - set_zoom_value(double(timeline_area->width() - 200) / double(sequence_->GetEndFrame())); - } else { - set_zoom_value(old_zoom); - } - } -} - -void Timeline::toggle_links() -{ - if (sequence_ != nullptr) { - sequence_->ToggleLinksOnSelected(); - } -} - -void Timeline::add_transition() { - ComboAction* ca = new ComboAction(); - bool adding = false; - - QVector selected_clips = sequence_->SelectedClips(); - - for (int i=0;itype() == olive::kTypeVideo) ? kCrossDissolveTransition - : kLinearFadeTransition; - - if (c->opening_transition == nullptr) { - ca->append(new AddTransitionCommand(c, - nullptr, - nullptr, - transition_to_add, - olive::config.default_transition_length)); - adding = true; - } - - if (c->closing_transition == nullptr) { - ca->append(new AddTransitionCommand(nullptr, - c, - nullptr, - transition_to_add, - olive::config.default_transition_length)); - adding = true; - } - } - - if (adding) { - olive::undo_stack.push(ca); - } else { - delete ca; - } - - update_ui(true); -} - -void Timeline::nest() { - if (sequence_ != nullptr) { - // get selected clips - QVector selected_clips = sequence_->SelectedClips(); - - // nest them - if (!selected_clips.isEmpty()) { - - // get earliest point in selected clips - long earliest_point = LONG_MAX; - for (int i=0;itimeline_in(), earliest_point); - } - - ComboAction* ca = new ComboAction(); - - // create "nest" sequence with the same attributes as the current sequence - SequencePtr s = std::make_shared(); - - s->set_name(olive::project_model.GetNextSequenceName(tr("Nested Sequence"))); - s->set_width(sequence_->width()); - s->set_height(sequence_->height()); - s->set_frame_rate(sequence_->frame_rate()); - s->set_audio_frequency(sequence_->audio_frequency()); - s->set_audio_layout(sequence_->audio_layout()); - - QVector new_clips; - - // copy all selected clips to the nest - for (int i=0;iappend(new DeleteClipAction(c)); - - // copy to new - Track* track = s->TrackAt(c->type(), c->track()->Index()); - ClipPtr copy = selected_clips.at(i)->copy(track); - copy->set_timeline_in(copy->timeline_in() - earliest_point); - copy->set_timeline_out(copy->timeline_out() - earliest_point); - track->AddClip(copy); - - new_clips.append(copy); - } - - // relink clips in new nested sequences - olive::timeline::RelinkClips(selected_clips, new_clips); - - // add sequence to project - MediaPtr m = olive::project_model.CreateSequence(ca, s, false, nullptr); - - // add nested sequence to active sequence - QVector media_list; - media_list.append(m.get()); - olive::timeline::CreateGhostsFromMedia(sequence_.get(), earliest_point, media_list); - - // ensure ghosts won't overlap anything - QVector all_sequence_clips = sequence_->GetAllClips(); - for (int j=0;jtrack() == 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 a track, and seek again. - g.track = g.track->Next(); - - // Restart entire loop again - j = -1; - break; - - } - } - } - } - - - sequence_->AddClipsFromGhosts(ca, ghosts); - - panel_graph_editor->set_row(nullptr); - panel_effect_controls->Clear(true); - sequence_->ClearSelections(); - - olive::undo_stack.push(ca); - - update_ui(true); - } - } -} - -void Timeline::update_sequence() { - bool null_sequence = (sequence_ == nullptr); - - for (int i=0;isetEnabled(!null_sequence); - } - snappingButton->setEnabled(!null_sequence); - zoomInButton->setEnabled(!null_sequence); - zoomOutButton->setEnabled(!null_sequence); - recordButton->setEnabled(!null_sequence); - addButton->setEnabled(!null_sequence); - headers->setEnabled(!null_sequence); - - UpdateTitle(); -} - -bool Timeline::focused() { - return (sequence_ != nullptr && (headers->hasFocus() || video_area->hasFocus() || audio_area->hasFocus())); -} - -void Timeline::repaint_timeline() { - if (!block_repaints) { - bool draw = true; - - if (sequence_ != nullptr - && !horizontalScrollBar->isSliderDown() - && !horizontalScrollBar->is_resizing() - && panel_sequence_viewer->playing - && !zoom_just_changed) { - // auto scroll - if (olive::config.autoscroll == olive::AUTOSCROLL_PAGE_SCROLL) { - int playhead_x = getTimelineScreenPointFromFrame(sequence_->playhead); - if (playhead_x < 0 || playhead_x > (editAreas->width())) { - horizontalScrollBar->setValue(getScreenPointFromFrame(zoom, sequence_->playhead)); - draw = false; - } - } else if (olive::config.autoscroll == olive::AUTOSCROLL_SMOOTH_SCROLL) { - if (center_scroll_to_playhead(horizontalScrollBar, zoom, sequence_->playhead)) { - draw = false; - } - } - } - - if (draw) { - headers->update(); - video_area->update(); - audio_area->update(); - - if (sequence_ != nullptr - && !zoom_just_changed) { - set_sb_max(); - } - } - - zoom_just_changed = false; - } -} - -void Timeline::select_all() { - if (sequence_ != nullptr) { - sequence_->SelectAll(); - repaint_timeline(); - } -} - -void Timeline::scroll_to_frame(long frame) { - scroll_to_frame_internal(horizontalScrollBar, frame, zoom, timeline_area->width()); -} - -void Timeline::resizeEvent(QResizeEvent *) { - // adjust maximum scrollbar - if (sequence_ != nullptr) set_sb_max(); - - - // resize tool button widget to its contents - QList tool_button_children = tool_button_widget->findChildren(); - - int horizontal_spacing = static_cast(tool_button_widget->layout())->horizontalSpacing(); - int vertical_spacing = static_cast(tool_button_widget->layout())->verticalSpacing(); - int total_area = tool_button_widget->height(); - - int button_count = tool_button_children.size(); - int button_height = tool_button_children.at(0)->sizeHint().height() + vertical_spacing; - - int cols = 0; - - int col_height; - - if (button_height < total_area) { - do { - cols++; - col_height = (qCeil(double(button_count)/double(cols))*button_height)-vertical_spacing; - } while (col_height > total_area); - } else { - cols = button_count; - } - - tool_button_widget->setFixedWidth((tool_button_children.at(0)->sizeHint().width())*cols + horizontal_spacing*(cols-1) + 1); -} - -void Timeline::toggle_enable_on_selected_clips() { - if (sequence_ != nullptr) { - - // get currently selected clips - QVector selected_clips = sequence_->SelectedClips(); - - if (!selected_clips.isEmpty()) { - // if clips are selected, create an undoable action - SetClipProperty* set_action = new SetClipProperty(kSetClipPropertyEnabled); - - // add each selected clip to the action - for (int i=0;iAddSetting(c, !c->enabled()); - } - - // push the action - olive::undo_stack.push(set_action); - update_ui(false); - } - } -} - -void Timeline::set_zoom_value(double v) { - // set zoom value - zoom = v; - - // update header zoom to match - headers->update_zoom(zoom); - - // set flag that zoom has just changed to prevent auto-scrolling since we change the scroll below - zoom_just_changed = true; - - // set scrollbar to center the playhead - if (sequence_ != nullptr) { - // update scrollbar maximum value for new zoom - set_sb_max(); - - if (!horizontalScrollBar->is_resizing()) { - center_scroll_to_playhead(horizontalScrollBar, zoom, sequence_->playhead); - } - } - - // repaint the timeline for the new zoom/location - repaint_timeline(); -} - -void Timeline::multiply_zoom(double m) { - showing_all = false; - set_zoom_value(zoom * m); -} - -void Timeline::zoom_in() { - multiply_zoom(2.0); -} - -void Timeline::zoom_out() { - multiply_zoom(0.5); -} - -void Timeline::ChangeTrackHeightUniformly(int diff) { - if (sequence_ != nullptr) { - sequence_->ChangeTrackHeightsRelatively(diff); - } - - // update the timeline - repaint_timeline(); -} - -void Timeline::IncreaseTrackHeight() { - ChangeTrackHeightUniformly(olive::timeline::kTrackHeightIncrement); -} - -void Timeline::DecreaseTrackHeight() { - ChangeTrackHeightUniformly(-olive::timeline::kTrackHeightIncrement); -} - -void Timeline::snapping_clicked(bool checked) { - olive::timeline::snapping = checked; -} - -/* -bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool relink) { - Clip* c = sequence_->clips.at(clip).get(); - if (c != nullptr) { - QVector pre_clips; - QVector post_clips; - - ClipPtr post = split_clip(ca, true, clip, frame); - - if (post == nullptr) { - return false; - } else { - post_clips.append(post); - - // if alt is not down, split clips links too - if (relink) { - pre_clips.append(clip); - - bool original_clip_is_selected = c->IsSelected(); - - // find linked clips of old clip - for (int i=0;ilinked.size();i++) { - int l = c->linked.at(i); - Clip* link = sequence_->clips.at(l).get(); - if ((original_clip_is_selected && link->IsSelected()) || !original_clip_is_selected) { - ClipPtr s = split_clip(ca, true, l, frame); - if (s != nullptr) { - pre_clips.append(l); - post_clips.append(s); - } - } - } - - relink_clips_using_ids(pre_clips, post_clips); - } - ca->append(new AddClipCommand(sequence_.get(), post_clips)); - return true; - } - } - return false; -} -*/ - - - -void Timeline::copy(bool del) { - if (sequence_ != nullptr) { - sequence_->AddSelectionsToClipboard(del); - } -} - -void Timeline::ripple_delete() { - - if (sequence_ != nullptr) { - - QVector selections = sequence_->Selections(); - - if (!selections.isEmpty()) { - - ComboAction* ca = new ComboAction(); - sequence_->DeleteAreas(ca, selections, true, true); - olive::undo_stack.push(ca); - repaint_timeline(); - - } else if (olive::config.hover_focus && get_focused_panel() == this) { - - ripple_delete_empty_space(); - - } - } - - -} - -void Timeline::ripple_delete_empty_space() -{ - if (sequence_ != nullptr) { - ComboAction* ca = new ComboAction(); - sequence_->RippleDeleteEmptySpace(ca, cursor_track, cursor_frame); - olive::undo_stack.push(ca); - - repaint_timeline(); - } -} - -void Timeline::set_marker() { - // determine if any clips are selected, and if so add markers to clips rather than the sequence - - QVector selected_clips = sequence_->SelectedClips(); - - if (selected_clips.isEmpty()) { - - Marker::SetOnSequence(sequence_.get()); - - } else { - - // Remove any clips that don't contain the playhead - for (int i=0;itimeline_out() < sequence_->playhead - || c->timeline_in() > sequence_->playhead) { - selected_clips.removeAt(i); - i--; - } - } - - // Check if we removed them all - if (selected_clips.isEmpty()) { - return; - } - - // If not, let's create markers on them - Marker::SetOnClips(selected_clips); - - } -} - -void Timeline::delete_inout() { - if (sequence_ != nullptr) { - sequence_->DeleteInToOut(false); - } -} - -void Timeline::ripple_delete_inout() { - if (sequence_ != nullptr) { - sequence_->DeleteInToOut(true); - } -} - -void Timeline::ripple_to_in_point() { - if (sequence_ != nullptr) { - sequence_->EditToPoint(true, true); - } -} - -void Timeline::ripple_to_out_point() { - if (sequence_ != nullptr) { - sequence_->EditToPoint(false, true); - } -} - -void Timeline::edit_to_in_point() { - if (sequence_ != nullptr) { - sequence_->EditToPoint(true, false); - } -} - -void Timeline::edit_to_out_point() { - if (sequence_ != nullptr) { - sequence_->EditToPoint(false, false); - } -} - -void Timeline::deselect() { - if (sequence_ != nullptr) { - sequence_->ClearSelections(); - repaint_timeline(); - } -} - -void Timeline::split_at_playhead() -{ - if (sequence_ != nullptr) { - sequence_->Split(); - repaint_timeline(); - } -} - -long getFrameFromScreenPoint(double zoom, int x) { - long f = qFloor(double(x) / zoom); - if (f < 0) { - return 0; - } - return f; -} - -int getScreenPointFromFrame(double zoom, long frame) { - return qRound(double(frame)*zoom); -} - -long Timeline::getTimelineFrameFromScreenPoint(int x) { - return getFrameFromScreenPoint(zoom, x + scroll); -} - -QVector Timeline::GetTracksInRectangle(int global_top, int global_bottom) -{ - QVector tracks; - - TimelineArea* area; - - foreach (area, areas) { - QPoint relative_tl = area->mapFromGlobal(QPoint(0, global_top)); - QPoint relative_br = area->mapFromGlobal(QPoint(0, global_bottom)); - - int rect_top = qMin(relative_tl.y(), relative_br.y()); - int rect_bottom = qMax(relative_tl.y(), relative_br.y()); - - // determine which clips are in this rectangular selection - QVector area_tracks = sequence_->GetTrackList(area->track_type()); - - for (int j=0;jview()->getScreenPointFromTrack(track); - int track_bottom = track_top + track->height(); - - // See if this track touches this rectangle at all - if (!(track_bottom < rect_top - || track_top > rect_bottom)) { - - // It does, so we add it to the list - tracks.append(track); - - } - } - } - - return tracks; -} - -int Timeline::getTimelineScreenPointFromFrame(long frame) { - return getScreenPointFromFrame(zoom, frame) - scroll; -} - -void Timeline::add_btn_click() { - Menu add_menu(this); - - QAction* titleMenuItem = new QAction(&add_menu); - titleMenuItem->setText(tr("Title...")); - titleMenuItem->setData(olive::timeline::ADD_OBJ_TITLE); - add_menu.addAction(titleMenuItem); - - QAction* solidMenuItem = new QAction(&add_menu); - solidMenuItem->setText(tr("Solid Color...")); - solidMenuItem->setData(olive::timeline::ADD_OBJ_SOLID); - add_menu.addAction(solidMenuItem); - - QAction* barsMenuItem = new QAction(&add_menu); - barsMenuItem->setText(tr("Bars...")); - barsMenuItem->setData(olive::timeline::ADD_OBJ_BARS); - add_menu.addAction(barsMenuItem); - - add_menu.addSeparator(); - - QAction* toneMenuItem = new QAction(&add_menu); - toneMenuItem->setText(tr("Tone...")); - toneMenuItem->setData(olive::timeline::ADD_OBJ_TONE); - add_menu.addAction(toneMenuItem); - - QAction* noiseMenuItem = new QAction(&add_menu); - noiseMenuItem->setText(tr("Noise...")); - noiseMenuItem->setData(olive::timeline::ADD_OBJ_NOISE); - add_menu.addAction(noiseMenuItem); - - connect(&add_menu, SIGNAL(triggered(QAction*)), this, SLOT(add_menu_item(QAction*))); - - add_menu.exec(QCursor::pos()); -} - -void Timeline::add_menu_item(QAction* action) { - creating = true; - creating_object = static_cast(action->data().toInt()); -} - -void Timeline::setScroll(int s) { - scroll = s; - headers->set_scroll(s); - repaint_timeline(); -} - -void Timeline::record_btn_click() { - if (olive::ActiveProjectFilename.isEmpty()) { - QMessageBox::critical(this, - tr("Unsaved Project"), - tr("You must save this project before you can record audio in it."), - QMessageBox::Ok); - } else { - creating = true; - creating_object = olive::timeline::ADD_OBJ_AUDIO; - olive::MainWindow->statusBar()->showMessage( - tr("Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe)"), - 10000); - } -} - -void Timeline::transition_tool_click() { - creating = false; - - Menu transition_menu(this); - - transition_menu.addAction(tr("Video Transitions"))->setEnabled(false); - - for (int i=0;itype() == EFFECT_TYPE_TRANSITION && node->subtype() == olive::kTypeVideo) { - QAction* a = transition_menu.addAction(node->name()); - a->setData(i); - } - } - - transition_menu.addSeparator(); - - transition_menu.addAction(tr("Audio Transitions"))->setEnabled(false); - - for (int i=0;itype() == EFFECT_TYPE_TRANSITION && node->subtype() == olive::kTypeAudio) { - QAction* a = transition_menu.addAction(node->name()); - a->setData(i); - } - } - - connect(&transition_menu, SIGNAL(triggered(QAction*)), this, SLOT(transition_menu_select(QAction*))); - - toolTransitionButton->setChecked(false); - - transition_menu.exec(QCursor::pos()); -} - -void Timeline::transition_menu_select(QAction* a) { - transition_tool_meta = static_cast(a->data().toInt()); - timeline_area->setCursor(Qt::CrossCursor); - olive::timeline::current_tool = olive::timeline::TIMELINE_TOOL_TRANSITION; - toolTransitionButton->setChecked(true); -} - -void Timeline::resize_move(double z) { - set_zoom_value(zoom * z); -} - -void Timeline::set_sb_max() { - headers->set_scrollbar_max(horizontalScrollBar, sequence_->GetEndFrame(), editAreas->width() - getScreenPointFromFrame(zoom, 200)); -} - -void Timeline::UpdateTitle() { - setWindowTitle( - tr("Timeline: %1").arg( - (sequence_ == nullptr) ? tr("(none)") : sequence_->name() - ) - ); -} - -void Timeline::setup_ui() { - QWidget* dockWidgetContents = new QWidget(); - - QHBoxLayout* horizontalLayout = new QHBoxLayout(dockWidgetContents); - horizontalLayout->setSpacing(0); - horizontalLayout->setMargin(0); - - setWidget(dockWidgetContents); - - tool_button_widget = new QWidget(); - tool_button_widget->setObjectName("timeline_toolbar"); - tool_button_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - - FlowLayout* tool_buttons_layout = new FlowLayout(tool_button_widget); - tool_buttons_layout->setSpacing(4); - tool_buttons_layout->setMargin(0); - - toolArrowButton = new QPushButton(); - toolArrowButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/arrow.svg"))); - toolArrowButton->setCheckable(true); - toolArrowButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_POINTER); - connect(toolArrowButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolArrowButton); - - toolEditButton = new QPushButton(); - toolEditButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/beam.svg"))); - toolEditButton->setCheckable(true); - toolEditButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_EDIT); - connect(toolEditButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolEditButton); - - toolRippleButton = new QPushButton(); - toolRippleButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/ripple.svg"))); - toolRippleButton->setCheckable(true); - toolRippleButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_RIPPLE); - connect(toolRippleButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolRippleButton); - - toolRazorButton = new QPushButton(); - toolRazorButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/razor.svg"))); - toolRazorButton->setCheckable(true); - toolRazorButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_RAZOR); - connect(toolRazorButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolRazorButton); - - toolSlipButton = new QPushButton(); - toolSlipButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/slip.svg"))); - toolSlipButton->setCheckable(true); - toolSlipButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_SLIP); - connect(toolSlipButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolSlipButton); - - toolSlideButton = new QPushButton(); - toolSlideButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/slide.svg"))); - toolSlideButton->setCheckable(true); - toolSlideButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_SLIDE); - connect(toolSlideButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolSlideButton); - - toolHandButton = new QPushButton(); - toolHandButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/hand.svg"))); - toolHandButton->setCheckable(true); - - toolHandButton->setProperty("tool", olive::timeline::TIMELINE_TOOL_HAND); - connect(toolHandButton, SIGNAL(clicked(bool)), this, SLOT(set_tool())); - tool_buttons_layout->addWidget(toolHandButton); - toolTransitionButton = new QPushButton(); - toolTransitionButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/transition-tool.svg"))); - toolTransitionButton->setCheckable(true); - connect(toolTransitionButton, SIGNAL(clicked(bool)), this, SLOT(transition_tool_click())); - tool_buttons_layout->addWidget(toolTransitionButton); - - snappingButton = new QPushButton(); - snappingButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/magnet.svg"))); - snappingButton->setCheckable(true); - snappingButton->setChecked(true); - connect(snappingButton, SIGNAL(toggled(bool)), this, SLOT(snapping_clicked(bool))); - tool_buttons_layout->addWidget(snappingButton); - - zoomInButton = new QPushButton(); - zoomInButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/zoomin.svg"))); - connect(zoomInButton, SIGNAL(clicked(bool)), this, SLOT(zoom_in())); - tool_buttons_layout->addWidget(zoomInButton); - - zoomOutButton = new QPushButton(); - zoomOutButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/zoomout.svg"))); - connect(zoomOutButton, SIGNAL(clicked(bool)), this, SLOT(zoom_out())); - tool_buttons_layout->addWidget(zoomOutButton); - - recordButton = new QPushButton(); - recordButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/record.svg"))); - connect(recordButton, SIGNAL(clicked(bool)), this, SLOT(record_btn_click())); - tool_buttons_layout->addWidget(recordButton); - - addButton = new QPushButton(); - addButton->setIcon(olive::icon::CreateIconFromSVG(QStringLiteral(":/icons/add-button.svg"))); - connect(addButton, SIGNAL(clicked()), this, SLOT(add_btn_click())); - tool_buttons_layout->addWidget(addButton); - - horizontalLayout->addWidget(tool_button_widget); - - timeline_area = new QWidget(); - QSizePolicy timeline_area_policy(QSizePolicy::Minimum, QSizePolicy::Minimum); - timeline_area_policy.setHorizontalStretch(1); - timeline_area_policy.setVerticalStretch(0); - timeline_area_policy.setHeightForWidth(timeline_area->sizePolicy().hasHeightForWidth()); - timeline_area->setSizePolicy(timeline_area_policy); - - QVBoxLayout* timeline_area_layout = new QVBoxLayout(timeline_area); - timeline_area_layout->setSpacing(0); - timeline_area_layout->setContentsMargins(0, 0, 0, 0); - - QHBoxLayout* timeline_header_layout = new QHBoxLayout(); - timeline_header_layout->addSpacing(olive::timeline::kTimelineLabelFixedWidth); - headers = new TimelineHeader(); - timeline_header_layout->addWidget(headers); - timeline_area_layout->addLayout(timeline_header_layout); - - editAreas = new QWidget(); - QHBoxLayout* editAreaLayout = new QHBoxLayout(editAreas); - editAreaLayout->setSpacing(0); - editAreaLayout->setContentsMargins(0, 0, 0, 0); - - QSplitter* splitter = new QSplitter(); - splitter->setChildrenCollapsible(false); - splitter->setOrientation(Qt::Vertical); - - video_area = new TimelineArea(this); - areas.append(video_area); - splitter->addWidget(video_area); - - audio_area = new TimelineArea(this); - areas.append(audio_area); - splitter->addWidget(audio_area); - - editAreaLayout->addWidget(splitter); - - timeline_area_layout->addWidget(editAreas); - - horizontalScrollBar = new ResizableScrollBar(); - horizontalScrollBar->setMaximum(0); - horizontalScrollBar->setSingleStep(20); - horizontalScrollBar->setOrientation(Qt::Horizontal); - - timeline_area_layout->addWidget(horizontalScrollBar); - - horizontalLayout->addWidget(timeline_area); - - audio_monitor = new AudioMonitor(); - audio_monitor->setMinimumSize(QSize(50, 0)); - - horizontalLayout->addWidget(audio_monitor); - - setWidget(dockWidgetContents); -} - -void Timeline::set_tool() { - QPushButton* button = static_cast(sender()); - olive::timeline::current_tool = static_cast(button->property("tool").toInt()); - creating = false; - switch (olive::timeline::current_tool) { - case olive::timeline::TIMELINE_TOOL_EDIT: - timeline_area->setCursor(Qt::IBeamCursor); - break; - case olive::timeline::TIMELINE_TOOL_RAZOR: - timeline_area->setCursor(olive::cursor::Razor); - break; - case olive::timeline::TIMELINE_TOOL_HAND: - timeline_area->setCursor(Qt::OpenHandCursor); - break; - default: - timeline_area->setCursor(Qt::ArrowCursor); - } -} - -void Timeline::visibility_changed_slot(bool visibility) -{ - if (visibility) { - emit SequenceChanged(sequence_); - } -} - -void olive::timeline::MultiplyTrackSizesByDPI() -{ - kTrackDefaultHeight *= QApplication::desktop()->devicePixelRatio(); - kTrackMinHeight *= QApplication::desktop()->devicePixelRatio(); - kTrackHeightIncrement *= QApplication::desktop()->devicePixelRatio(); - kTimelineLabelFixedWidth *= QApplication::desktop()->devicePixelRatio(); -} diff --git a/panels/timeline.h b/panels/timeline.h deleted file mode 100644 index 48cf9481f..000000000 --- a/panels/timeline.h +++ /dev/null @@ -1,220 +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 TIMELINE_H -#define TIMELINE_H - -#include -#include -#include - -#include "ui/timelinearea.h" -#include "timeline/timelinetools.h" -#include "timeline/timelinefunctions.h" -#include "timeline/selection.h" -#include "timeline/clip.h" -#include "timeline/mediaimportdata.h" -#include "timeline/ghost.h" -#include "undo/undo.h" -#include "ui/timelineheader.h" -#include "ui/resizablescrollbar.h" -#include "ui/audiomonitor.h" -#include "ui/panel.h" - -class Timeline : public Panel -{ - Q_OBJECT -public: - explicit Timeline(QWidget *parent = nullptr); - - static Timeline* GetTopTimeline(); - static SequencePtr GetTopSequence(); - static void OpenSequence(SequencePtr s); - static void CloseSequence(Sequence* s); - static void CloseAll(); - static bool IsImporting(); - - void SetSequence(SequencePtr sequence); - - virtual bool focused() override; - void multiply_zoom(double m); - void copy(bool del); - void update_sequence(); - - int getTimelineScreenPointFromFrame(long frame); - long getTimelineFrameFromScreenPoint(int x); - int getDisplayScreenPointFromFrame(long frame); - long getDisplayFrameFromScreenPoint(int x); - - QVector GetTracksInRectangle(int global_top, int global_bottom); - - void set_marker(); - - // shared information - long cursor_frame; - Track* cursor_track; - double zoom; - bool zoom_just_changed; - long drag_frame_start; - Track* drag_track_start; - void update_effect_controls(); - bool showing_all; - double old_zoom; - - // selecting functions - bool selecting; - QVector selection_cache; - void select_all(); - bool rect_select_init; - bool rect_select_proc; - QRect rect_select_rect; - - // moving - bool moving_init; - bool moving_proc; - QVector ghosts; - bool move_insert; - - // trimming - Clip* trim_target; - olive::timeline::TrimType trim_type; - int transition_select; - - // splitting - bool splitting; - QVector split_tracks; - - // importing - bool importing; - bool importing_files; - - // creating variables - bool creating; - olive::timeline::CreateObjects creating_object; - - // transition variables - bool transition_tool_init; - bool transition_tool_proc; - Clip* transition_tool_open_clip; - Clip* transition_tool_close_clip; - NodeType transition_tool_meta; - - // hand tool variables - bool hand_moving; - int drag_x_start; - int drag_y_start; - - bool block_repaints; - - TimelineHeader* headers; - AudioMonitor* audio_monitor; - ResizableScrollBar* horizontalScrollBar; - - QVector tool_buttons; - QButtonGroup* tool_button_group; - QPushButton* toolArrowButton; - QPushButton* toolEditButton; - QPushButton* toolRippleButton; - QPushButton* toolRazorButton; - QPushButton* toolSlipButton; - QPushButton* toolSlideButton; - QPushButton* toolHandButton; - QPushButton* toolTransitionButton; - QPushButton* snappingButton; - - void scroll_to_frame(long frame); - - bool can_ripple_empty_space(long frame, int track); - - virtual void Retranslate() override; -protected: - virtual void resizeEvent(QResizeEvent *event) override; -public slots: - void repaint_timeline(); - void toggle_show_all(); - void toggle_links(); - void deselect(); - void split_at_playhead(); - void ripple_delete(); - void ripple_delete_empty_space(); - void toggle_enable_on_selected_clips(); - - void delete_inout(); - void ripple_delete_inout(); - - void ripple_to_in_point(); - void ripple_to_out_point(); - void edit_to_in_point(); - void edit_to_out_point(); - - void IncreaseTrackHeight(); - void DecreaseTrackHeight(); - - void add_transition(); - - void nest(); - - void zoom_in(); - void zoom_out(); - -signals: - void SequenceChanged(SequencePtr s); - -private slots: - void snapping_clicked(bool checked); - void add_btn_click(); - void add_menu_item(QAction*); - void setScroll(int); - void record_btn_click(); - void transition_tool_click(); - void transition_menu_select(QAction*); - void resize_move(double d); - void set_tool(); - void visibility_changed_slot(bool visibility); - -private: - SequencePtr sequence_; - - void ChangeTrackHeightUniformly(int diff); - void set_zoom_value(double v); - void set_tool(int tool); - int scroll; - void set_sb_max(); - void UpdateTitle(); - - void setup_ui(); - - // ripple delete empty space variables - long rc_ripple_min; - long rc_ripple_max; - - QWidget* timeline_area; - TimelineArea* video_area; - TimelineArea* audio_area; - QVector areas; - QWidget* editAreas; - QPushButton* zoomInButton; - QPushButton* zoomOutButton; - QPushButton* recordButton; - QPushButton* addButton; - QWidget* tool_button_widget; -}; - -#endif // TIMELINE_H diff --git a/panels/viewer.cpp b/panels/viewer.cpp deleted file mode 100644 index 3b6b76d40..000000000 --- a/panels/viewer.cpp +++ /dev/null @@ -1,944 +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 "viewer.h" - -extern "C" { -#include -#include -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rendering/audio.h" -#include "timeline.h" -#include "panels/project.h" -#include "panels/effectcontrols.h" -#include "timeline/sequence.h" -#include "timeline/clip.h" -#include "panels/panels.h" -#include "global/config.h" -#include "global/timing.h" -#include "project/footage.h" -#include "project/media.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "ui/audiomonitor.h" -#include "rendering/renderfunctions.h" -#include "ui/viewercontainer.h" -#include "ui/labelslider.h" -#include "ui/timelineheader.h" -#include "ui/resizablescrollbar.h" -#include "ui/icons.h" -#include "global/global.h" -#include "global/debug.h" - -#define FRAMES_IN_ONE_MINUTE 1798 // 1800 - 2 -#define FRAMES_IN_TEN_MINUTES 17978 // (FRAMES_IN_ONE_MINUTE * 10) - 2 - -Viewer::Viewer(QWidget *parent) : - Panel(parent), - playing(false), - media(nullptr), - seq(nullptr), - created_sequence(false), - panel_name(tr("Viewer: %1")), - minimum_zoom(1.0), - cue_recording_internal(false), - playback_speed(0), - mode_(kTimelineMode) -{ - setup_ui(); - - headers->viewer = this; - headers->snapping = false; - headers->show_text(false); - viewer_container->viewer = this; - viewer_widget_ = viewer_container->child; - viewer_widget_->viewer = this; - set_media(nullptr); - - current_timecode_slider->setEnabled(false); - current_timecode_slider->SetMinimum(0); - current_timecode_slider->SetDefault(qSNaN()); - current_timecode_slider->SetValue(0); - current_timecode_slider->SetDisplayType(LabelSlider::FrameNumber); - connect(current_timecode_slider, SIGNAL(valueChanged(double)), this, SLOT(update_playhead())); - - recording_flasher.setInterval(500); - - connect(&playback_updater, SIGNAL(timeout()), this, SLOT(timer_update())); - connect(&recording_flasher, SIGNAL(timeout()), this, SLOT(recording_flasher_update())); - connect(horizontal_bar, SIGNAL(valueChanged(int)), headers, SLOT(set_scroll(int))); - connect(horizontal_bar, SIGNAL(valueChanged(int)), viewer_widget_, SLOT(set_waveform_scroll(int))); - connect(horizontal_bar, SIGNAL(resize_move(double)), this, SLOT(resize_move(double))); - - update_playhead_timecode(0); - update_end_timecode(); -} - -void Viewer::SetMode(Viewer::Mode mode) -{ - mode_ = mode; -} - -Viewer::Mode Viewer::mode() -{ - return mode_; -} - -void Viewer::Retranslate() { - /// Viewer panels are retranslated through the MainWindow to differentiate Media and Sequence Viewers -// update_window_title(); -} - -bool Viewer::focused() { - return headers->hasFocus() - || viewer_widget_->hasFocus() - || go_to_start_button->hasFocus() - || prev_frame_button->hasFocus() - || play_button->hasFocus() - || next_frame_button->hasFocus() - || go_to_end_frame->hasFocus(); -} - -void Viewer::reset_all_audio() { - // reset all clip audio - if (seq != nullptr) { - long last_frame = 0; - - QVector all_clips = seq->GetAllClips(); - for (int i=0;ireset_audio(); - last_frame = qMax(last_frame, c->timeline_out()); - - } - - audio_ibuffer_frame = seq->playhead; - if (playback_speed < 0) { - audio_ibuffer_frame = last_frame - audio_ibuffer_frame; - } - audio_ibuffer_timecode = double(audio_ibuffer_frame) / seq->frame_rate(); - } - clear_audio_ibuffer(); -} - -void Viewer::seek(long p) { - pause(); - - if (mode_ == kTimelineMode) { - seq->playhead = p; - } else { - seq->playhead = qMin(seq->GetEndFrame(), qMax(0L, p)); - } - - bool update_fx = false; - - if (mode_ == kTimelineMode) { - panel_timeline.first()->scroll_to_frame(p); - panel_effect_controls->scroll_to_frame(p); - if (olive::config.seek_also_selects) { - seq->SelectAtPlayhead(); - update_fx = true; - } - } - - reset_all_audio(); - audio_scrub = true; - last_playhead = seq->playhead; - update_parents(update_fx); -} - -void Viewer::go_to_start() { - if (seq != nullptr) seek(0); -} - -void Viewer::go_to_end() { - if (seq != nullptr) seek(seq->GetEndFrame()); -} - -void Viewer::close_media() { - set_media(nullptr); -} - -void Viewer::go_to_in() { - if (seq != nullptr) { - if (seq->using_workarea) { - seek(seq->workarea_in); - } else { - go_to_start(); - } - } -} - -void Viewer::previous_frame() { - if (seq != nullptr && seq->playhead > 0) seek(seq->playhead-1); -} - -void Viewer::next_frame() { - if (seq != nullptr) seek(seq->playhead+1); -} - -void Viewer::go_to_out() { - if (seq != nullptr) { - if (seq->using_workarea) { - seek(seq->workarea_out); - } else { - go_to_end(); - } - } -} - -void Viewer::cue_recording(long start, long end, Track* track) { - recording_start = start; - recording_end = end; - recording_track = track; - panel_sequence_viewer->seek(recording_start); - cue_recording_internal = true; - recording_flasher.start(); -} - -void Viewer::uncue_recording() { - cue_recording_internal = false; - recording_flasher.stop(); - play_button->setStyleSheet(QString()); -} - -bool Viewer::is_recording_cued() { - return cue_recording_internal; -} - -void Viewer::toggle_play() { - if (playing) { - pause(); - } else { - play(); - } -} - -void Viewer::increase_speed() { - int new_speed = playback_speed+1; - if (new_speed == 0) { - new_speed++; - } - set_playback_speed(new_speed); -} - -void Viewer::decrease_speed() { - int new_speed = playback_speed-1; - if (new_speed == 0) { - new_speed--; - } - set_playback_speed(new_speed); -} - -void Viewer::play(bool in_to_out) { - if (seq == nullptr) { - return; - } - - if (panel_sequence_viewer->playing) panel_sequence_viewer->pause(); - if (panel_footage_viewer->playing) panel_footage_viewer->pause(); - - long sequence_end_frame = seq->GetEndFrame(); - if (sequence_end_frame == 0) { - return; - } - - playing_in_to_out = in_to_out; - - if (seq != nullptr) { - - if (playing_in_to_out) { - uncue_recording(); - } - - bool seek_to_in = (seq->using_workarea && (olive::config.loop || playing_in_to_out)); - if (!is_recording_cued() - && playback_speed >= 0 - && (playing_in_to_out - || (olive::config.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); - } - - if (playback_speed == 0) { - playback_speed = 1; - } - - reset_all_audio(); - if (is_recording_cued() && !start_recording()) { - qCritical() << "Failed to record audio"; - return; - } - - playhead_start = seq->playhead; - playing = true; - SetAudioWakeObject(this); - set_playpause_icon(false); - start_msecs = QDateTime::currentMSecsSinceEpoch(); - - timer_update(); - } -} - -void Viewer::play_wake() { - start_msecs = QDateTime::currentMSecsSinceEpoch(); - playback_updater.start(); - if (audio_thread != nullptr) audio_thread->notifyReceiver(); -} - -void Viewer::pause() { - playing = false; - SetAudioWakeObject(nullptr); - set_playpause_icon(true); - playback_updater.stop(); - playback_speed = 0; - - if (is_recording_cued()) { - uncue_recording(); - - if (recording) { - stop_recording(); - - // import audio - QStringList file_list; - file_list.append(get_recorded_audio_filename()); - olive::project_model.process_file_list(file_list); - - // add it to the sequence - QVector last_imported_media = olive::project_model.GetLastImportedMedia(); - Media* m = last_imported_media.first(); - Footage* f = m->to_footage(); - - // wait for footage to be completely ready before taking metadata from it - f->ready_lock.lock(); - f->ready_lock.unlock(); - - // Check if we were able to import the audio we just recorded - if (f->invalid) { - - QMessageBox::critical(this, - tr("Failed to import recorded file"), - tr("An error occurred trying to import the recorded audio"), - QMessageBox::Ok); - - } else { - - // Make a clip out of it and add it to the Sequence - - ClipPtr c = std::make_shared(recording_track); - - c->set_media(m, 0); // latest media - c->set_timeline_in(recording_start); - c->set_timeline_out(recording_start + f->get_length_in_frames(seq->frame_rate())); - c->set_clip_in(0); - c->set_color(128, 192, 128); - c->set_name(m->get_name()); - - QVector add_clips; - add_clips.append(c); - olive::undo_stack.push(new AddClipCommand(add_clips)); // add clip - - } - - - - } - } -} - -void Viewer::update_playhead_timecode(long p) { - current_timecode_slider->SetValue(p); -} - -void Viewer::update_end_timecode() { - end_timecode->setText((seq == nullptr) ? frame_to_timecode(0, olive::config.timecode_view, 30) : frame_to_timecode(seq->GetEndFrame(), olive::config.timecode_view, seq->frame_rate())); -} - -void Viewer::update_header_zoom() { - if (seq != nullptr) { - long sequenceEndFrame = seq->GetEndFrame(); - if (cached_end_frame != sequenceEndFrame) { - minimum_zoom = (sequenceEndFrame > 0) ? (double(headers->width()) / double(sequenceEndFrame)) : 1; - headers->update_zoom(qMax(headers->get_zoom(), minimum_zoom)); - set_sb_max(); - viewer_widget_->waveform_zoom = headers->get_zoom(); - } else { - headers->update(); - } - } -} - -void Viewer::update_parents(bool reload_fx) { - if (mode_ == kTimelineMode) { - update_ui(reload_fx); - } else { - update_viewer(); - } -} - -int Viewer::get_playback_speed() { - return playback_speed; -} - -ViewerWidget *Viewer::viewer_widget() -{ - return viewer_widget_; -} - -void Viewer::set_marker() { - Marker::SetOnSequence(seq.get()); -} - -void Viewer::resizeEvent(QResizeEvent *e) { - QDockWidget::resizeEvent(e); - if (seq != nullptr) { - set_sb_max(); - viewer_widget_->update(); - } -} - -void Viewer::update_viewer() { - update_header_zoom(); - viewer_widget_->frame_update(); - if (seq != nullptr) { - update_playhead_timecode(seq->playhead); - } - update_end_timecode(); -} - -void Viewer::prev_cut() -{ - if (seq != nullptr - && seq->playhead > 0) { - - QVector sequence_clips = seq->GetAllClips(); - - long p_cut = 0; - for (int i=0;itimeline_out() > p_cut && c->timeline_out() < seq->playhead) { - p_cut = c->timeline_out(); - } else if (c->timeline_in() > p_cut && c->timeline_in() < seq->playhead) { - p_cut = c->timeline_in(); - } - } - panel_sequence_viewer->seek(p_cut); - } -} - -void Viewer::next_cut() -{ - if (seq != nullptr) { - - QVector sequence_clips = seq->GetAllClips(); - - bool seek_enabled = false; - long n_cut = LONG_MAX; - for (int i=0;itimeline_in() < n_cut && c->timeline_in() > seq->playhead) { - n_cut = c->timeline_in(); - seek_enabled = true; - } else if (c->timeline_out() < n_cut && c->timeline_out() > seq->playhead) { - n_cut = c->timeline_out(); - seek_enabled = true; - } - } - - if (seek_enabled) { - panel_sequence_viewer->seek(n_cut); - } - } -} - -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) { - olive::undo_stack.push(new SetTimelineInOutCommand(seq.get(), true, 0, seq->workarea_out)); - update_parents(); - } -} - -void Viewer::clear_out() { - if (seq != nullptr - && seq->using_workarea) { - olive::undo_stack.push(new SetTimelineInOutCommand(seq.get(), true, seq->workarea_in, seq->GetEndFrame())); - update_parents(); - } -} - -void Viewer::clear_inout_point() { - if (seq != nullptr - && seq->using_workarea) { - olive::undo_stack.push(new SetTimelineInOutCommand(seq.get(), false, 0, 0)); - update_parents(); - } -} - -void Viewer::set_in_point() { - if (seq != nullptr) { - headers->set_in_point(seq->playhead); - } -} - -void Viewer::set_out_point() { - if (seq != nullptr) { - headers->set_out_point(seq->playhead); - } -} - -void Viewer::set_zoom(bool in) { - if (seq != nullptr) { - set_zoom_value(in ? headers->get_zoom()*2 : qMax(minimum_zoom, headers->get_zoom()*0.5)); - } -} - -void Viewer::set_panel_name(const QString &n) { - panel_name = 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() { - setWindowTitle(panel_name.arg((seq == nullptr) ? tr("(none)") : seq->name())); -} - -void Viewer::set_zoom_value(double d) { - headers->update_zoom(d); - if (viewer_widget_->waveform) { - viewer_widget_->waveform_zoom = d; - viewer_widget_->update(); - } - if (seq != nullptr) { - set_sb_max(); - if (!horizontal_bar->is_resizing()) - center_scroll_to_playhead(horizontal_bar, headers->get_zoom(), seq->playhead); - } -} - -void Viewer::set_sb_max() { - headers->set_scrollbar_max(horizontal_bar, seq->GetEndFrame(), headers->width()); -} - -void Viewer::set_playback_speed(int s) { - pause(); - playback_speed = qMin(3, qMax(s, -3)); - if (playback_speed != 0) { - play(); - } -} - -long Viewer::get_seq_in() { - return ((olive::config.loop || playing_in_to_out) && seq->using_workarea) - ? seq->workarea_in - : 0; -} - -long Viewer::get_seq_out() { - return ((olive::config.loop || playing_in_to_out) && seq->using_workarea && previous_playhead < seq->workarea_out) - ? seq->workarea_out - : seq->GetEndFrame(); -} - -void Viewer::setup_ui() { - QWidget* contents = new QWidget(); - - QVBoxLayout* layout = new QVBoxLayout(contents); - layout->setSpacing(0); - layout->setMargin(0); - - setWidget(contents); - - viewer_container = new ViewerContainer(); - viewer_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - layout->addWidget(viewer_container); - - headers = new TimelineHeader(); - layout->addWidget(headers); - - horizontal_bar = new ResizableScrollBar(); - horizontal_bar->setSingleStep(20); - horizontal_bar->setOrientation(Qt::Horizontal); - layout->addWidget(horizontal_bar); - - QWidget* lower_controls = new QWidget(); - - QHBoxLayout* lower_control_layout = new QHBoxLayout(lower_controls); - lower_control_layout->setMargin(0); - - QSizePolicy timecode_container_policy(QSizePolicy::Minimum, QSizePolicy::Maximum); - QSizePolicy lower_control_policy(QSizePolicy::Maximum, 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); - current_timecode_slider = new LabelSlider(); - 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); - connect(go_to_start_button, SIGNAL(clicked(bool)), this, SLOT(go_to_in())); - playback_control_layout->addWidget(go_to_start_button); - - prev_frame_button = new QPushButton(); - prev_frame_button->setIcon(olive::icon::ViewerPrevFrame); - connect(prev_frame_button, SIGNAL(clicked(bool)), this, SLOT(previous_frame())); - playback_control_layout->addWidget(prev_frame_button); - - play_button = new QPushButton(); - play_button->setIcon(olive::icon::ViewerPlay); - connect(play_button, SIGNAL(clicked(bool)), this, SLOT(toggle_play())); - playback_control_layout->addWidget(play_button); - - next_frame_button = new QPushButton(); - next_frame_button->setIcon(olive::icon::ViewerNextFrame); - connect(next_frame_button, SIGNAL(clicked(bool)), this, SLOT(next_frame())); - playback_control_layout->addWidget(next_frame_button); - - go_to_end_frame = new QPushButton(); - go_to_end_frame->setIcon(olive::icon::ViewerGoToEnd); - 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); - end_timecode_layout->setMargin(0); - - end_timecode = new QLabel(); - end_timecode->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - end_timecode_layout->addWidget(end_timecode); - - lower_control_layout->addWidget(end_timecode_container); - - layout->addWidget(lower_controls); -} - -void Viewer::set_media(Media* m) { - media = m; - - SequencePtr new_sequence = nullptr; - - if (media != nullptr) { - switch (media->get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* footage = media->to_footage(); - - marker_ref = &footage->markers; - - new_sequence = std::make_shared(); - created_sequence = true; - new_sequence->wrapper_sequence = true; - new_sequence->set_name(footage->name); - - new_sequence->using_workarea = footage->using_inout; - if (footage->using_inout) { - new_sequence->workarea_in = footage->in; - new_sequence->workarea_out = footage->out; - } - - new_sequence->set_frame_rate(olive::config.default_sequence_framerate); - - if (footage->video_tracks.size() > 0) { - const FootageStream& video_stream = footage->video_tracks.at(0); - new_sequence->set_width(video_stream.video_width); - new_sequence->set_height(video_stream.video_height); - if (video_stream.video_frame_rate > 0 && !video_stream.infinite_length) { - new_sequence->set_frame_rate(video_stream.video_frame_rate * footage->speed); - } - - Track* first_track = new_sequence->FirstTrack(olive::kTypeVideo); - - ClipPtr c = std::make_shared(first_track); - c->set_media(media, video_stream.file_index); - c->set_timeline_in(0); - 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); - } - c->set_track(first_track); - c->set_clip_in(0); - c->refresh(); - first_track->AddClip(c); - } else { - new_sequence->set_width(olive::config.default_sequence_width); - new_sequence->set_height(olive::config.default_sequence_height); - } - - if (footage->audio_tracks.size() > 0) { - const FootageStream& audio_stream = footage->audio_tracks.at(0); - new_sequence->set_audio_frequency(audio_stream.audio_frequency); - - Track* track = new_sequence->FirstTrack(olive::kTypeAudio); - ClipPtr c = std::make_shared(track); - c->set_media(media, audio_stream.file_index); - c->set_timeline_in(0); - c->set_timeline_out(footage->get_length_in_frames(new_sequence->frame_rate())); - c->set_clip_in(0); - c->refresh(); - track->AddClip(c); - - if (footage->video_tracks.size() == 0) { - viewer_widget_->waveform = true; - viewer_widget_->waveform_clip = c; - viewer_widget_->waveform_ms = &audio_stream; - viewer_widget_->frame_update(); - } - } else { - new_sequence->set_audio_frequency(olive::config.default_sequence_audio_frequency); - } - - new_sequence->set_audio_layout(AV_CH_LAYOUT_STEREO); - } - break; - case MEDIA_TYPE_SEQUENCE: - new_sequence = media->to_sequence(); - break; - } - } - - set_sequence(new_sequence); -} - -void Viewer::update_playhead() { - seek(current_timecode_slider->value()); -} - -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::config.seek_also_selects) { - seq->SelectAtPlayhead(); - } - - update_parents(olive::config.seek_also_selects); - - if (playing) { - if (playback_speed < 0 && seq->playhead == 0) { - pause(); - } else if (recording) { - if (recording_start != recording_end && seq->playhead >= recording_end) { - pause(); - } - } else if (playback_speed > 0) { - long end_frame = seq->GetEndFrame(); - if ((olive::config.auto_seek_to_beginning || previous_playhead < end_frame) && seq->playhead >= end_frame) { - pause(); - } - if (seq->using_workarea && seq->playhead >= seq->workarea_out) { - if (olive::config.loop) { - // loop - play(); - } else if (playing_in_to_out) { - pause(); - } - } - } - } -} - -void Viewer::recording_flasher_update() { - if (play_button->styleSheet().isEmpty()) { - play_button->setStyleSheet("background: red;"); - } else { - play_button->setStyleSheet(QString()); - } -} - -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; - - if (created_sequence) { - // TODO delete undo commands referencing this sequence to avoid crashes - /* - for (int i=0;iwait_until_render_is_paused(); - - // If we had a current sequence open, close it - if (seq != nullptr) { - seq->Close(); - } - - clean_created_seq(); - - seq = s; - - bool null_sequence = (seq == nullptr); - - headers->setEnabled(!null_sequence); - current_timecode_slider->setEnabled(!null_sequence); - viewer_widget_->setEnabled(!null_sequence); - viewer_widget_->setVisible(!null_sequence); - go_to_start_button->setEnabled(!null_sequence); - prev_frame_button->setEnabled(!null_sequence); - 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()); - - playback_updater.setInterval(qFloor(1000 / seq->frame_rate())); - - update_playhead_timecode(seq->playhead); - update_end_timecode(); - - viewer_container->adjust(); - - if (!created_sequence) { - marker_ref = &seq->markers; - } - } else { - update_playhead_timecode(0); - update_end_timecode(); - } - - update_window_title(); - - update_header_zoom(); - - viewer_widget_->frame_update(); - - update(); -} - -void Viewer::set_playpause_icon(bool play) { - play_button->setIcon(play ? olive::icon::ViewerPlay : olive::icon::ViewerPause); -} diff --git a/panels/viewer.h b/panels/viewer.h deleted file mode 100644 index 9ce04ee39..000000000 --- a/panels/viewer.h +++ /dev/null @@ -1,182 +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 VIEWER_H -#define VIEWER_H - -#include -#include -#include -#include - -#include "timeline/marker.h" -#include "timeline/mediaimportdata.h" -#include "project/media.h" - -#include "ui/panel.h" -#include "ui/viewerwidget.h" -#include "ui/timelineview.h" -#include "ui/timelineheader.h" -#include "ui/labelslider.h" -#include "ui/resizablescrollbar.h" - -class Viewer : public Panel -{ - Q_OBJECT - -public: - explicit Viewer(QWidget *parent = nullptr); - - enum Mode { - kFootageMode, - kTimelineMode - }; - - void SetMode(Mode mode); - Mode mode(); - - virtual bool focused() override; - 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 clear_in(); - void clear_out(); - void clear_inout_point(); - void set_in_point(); - 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); - void play(bool in_to_out = false); - void pause(); - bool playing; - long playhead_start; - qint64 start_msecs; - QTimer playback_updater; - - - void cue_recording(long start, long end, Track *track); - void uncue_recording(); - bool is_recording_cued(); - long recording_start; - long recording_end; - Track* recording_track; - - void reset_all_audio(); - void update_parents(bool reload_fx = false); - - int get_playback_speed(); - - ViewerWidget* viewer_widget(); - - Media* media; - SequencePtr seq; - QVector* marker_ref; - - void set_marker(); - - TimelineHeader* headers; - - - - void initiate_drag(olive::timeline::MediaImportType drag_type); - - virtual void Retranslate() override; -protected: - virtual void resizeEvent(QResizeEvent *event) override; - -public slots: - void set_sequence(SequencePtr s); - - void play_wake(); - void go_to_start(); - void go_to_in(); - void previous_frame(); - void toggle_play(); - void increase_speed(); - void decrease_speed(); - void next_frame(); - void go_to_out(); - void go_to_end(); - void close_media(); - void update_viewer(); - void prev_cut(); - void next_cut(); - - -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(); - void clean_created_seq(); - bool created_sequence; - long cached_end_frame; - QString panel_name; - double minimum_zoom; - bool playing_in_to_out; - long last_playhead; - void set_zoom_value(double d); - void set_sb_max(); - void set_playback_speed(int s); - - long get_seq_in(); - long get_seq_out(); - - void setup_ui(); - - ViewerWidget* viewer_widget_; - - ResizableScrollBar* horizontal_bar; - ViewerContainer* viewer_container; - LabelSlider* current_timecode_slider; - QLabel* end_timecode; - - QPushButton* go_to_start_button; - QPushButton* prev_frame_button; - QPushButton* play_button; - QPushButton* next_frame_button; - QPushButton* go_to_end_frame; - - QPushButton* video_only_button; - QPushButton* audio_only_button; - - bool cue_recording_internal; - QTimer recording_flasher; - - long previous_playhead; - int playback_speed; - - Mode mode_; -}; - -#endif // VIEWER_H diff --git a/project/footage.cpp b/project/footage.cpp deleted file mode 100644 index 25ed0f969..000000000 --- a/project/footage.cpp +++ /dev/null @@ -1,179 +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 "footage.h" - -#include -#include -#include -#include -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -#include "project/previewgenerator.h" -#include "timeline/clip.h" -#include "global/config.h" -#include "global/global.h" - -Footage::Footage() : - ready(false), - preview_gen(nullptr), - invalid(false), - in(0), - out(0), - speed(1.0), - alpha_is_associated(true), - proxy(false), - start_number(0) -{ - ready_lock.lock(); -} - -Footage::~Footage() { - reset(); -} - -void Footage::Save(QXmlStreamWriter &stream) -{ - QDir proj_dir = QFileInfo(olive::ActiveProjectFilename).absoluteDir(); - - stream.writeStartElement("footage"); - stream.writeAttribute("id", QString::number(save_id)); - stream.writeAttribute("name", name); - stream.writeAttribute("url", proj_dir.relativeFilePath(url)); - stream.writeAttribute("duration", QString::number(length)); - stream.writeAttribute("using_inout", QString::number(using_inout)); - stream.writeAttribute("in", QString::number(in)); - stream.writeAttribute("out", QString::number(out)); - stream.writeAttribute("speed", QString::number(speed)); - stream.writeAttribute("alphapremul", QString::number(alpha_is_associated)); - stream.writeAttribute("startnumber", QString::number(start_number)); - stream.writeAttribute("colorspace", Colorspace()); - - stream.writeAttribute("proxy", QString::number(proxy)); - stream.writeAttribute("proxypath", proxy_path); - - // save video stream metadata - for (int j=0;jparseColorSpaceFromString(url.toUtf8()); - - if (!guess_colorspace.isEmpty()) { - return guess_colorspace; - } - - return olive::config.ocio_default_input_colorspace; -} - -void Footage::SetColorspace(const QString &cs) -{ - colorspace_ = cs; -} - -void Footage::reset() { - if (preview_gen != nullptr) { - preview_gen->cancel(); - } - video_tracks.clear(); - audio_tracks.clear(); - ready = false; -} - -long Footage::get_length_in_frames(double frame_rate) { - if (length >= 0) { - return qFloor((double(length) / double(AV_TIME_BASE)) * frame_rate / speed); - } - return 0; -} - -FootageStream* Footage::get_stream_from_file_index(bool video, int index) { - if (video) { - for (int i=0;i. - -***/ - -#ifndef FOOTAGE_H -#define FOOTAGE_H - -extern "C" { - #include -} - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "timeline/marker.h" - -enum VideoInterlacingMode { - VIDEO_PROGRESSIVE, - VIDEO_TOP_FIELD_FIRST, - VIDEO_BOTTOM_FIELD_FIRST -}; - -class Sequence; -class Clip; -class PreviewGenerator; -class Footage; - -struct FootageStream { - // Format stream index - Footage* footage; - int file_index; - - // Video parameters - int video_width; - int video_height; - double video_frame_rate; - int video_interlacing; - int video_auto_interlacing; - bool infinite_length; - - // Audio parameters - int audio_channels; - int audio_layout; - int audio_frequency; - - // Enabled - bool enabled; - - // preview thumbnail/waveform - bool preview_done; - QImage video_preview; - QVector audio_preview; -}; - -class Footage { -public: - Footage(); - ~Footage(); - - void Save(QXmlStreamWriter& stream); - - // footage metadata - QString url; - QString name; - int64_t length; - QVector video_tracks; - QVector audio_tracks; - int save_id; - bool ready; - bool invalid; - double speed; - bool alpha_is_associated; - int start_number; - - // color management - QString Colorspace(); - void SetColorspace(const QString& cs); - - // proxy config - bool proxy; - QString proxy_path; - - // thumbnail/waveform generation - PreviewGenerator* preview_gen; - QMutex ready_lock; - - // in/out points - bool using_inout; - long in; - long out; - - // markers - QVector markers; - - // functions - long get_length_in_frames(double frame_rate); - FootageStream *get_stream_from_file_index(bool video, int index); - void reset(); - - static QString get_channel_layout_name(int channels, uint64_t layout); - static QString get_interlacing_name(int interlacing); -private: - QString colorspace_; -}; - -using FootagePtr = std::shared_ptr; - -#endif // FOOTAGE_H diff --git a/project/loadthread.cpp b/project/loadthread.cpp deleted file mode 100644 index 28edeb135..000000000 --- a/project/loadthread.cpp +++ /dev/null @@ -1,803 +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 "loadthread.h" - -#include "global/global.h" -#include "ui/mainwindow.h" -#include "panels/panels.h" -#include "project/projectelements.h" -#include "global/config.h" -#include "rendering/renderfunctions.h" -#include "project/previewgenerator.h" -#include "project/projectfunctions.h" -#include "effects/internal/voideffect.h" -#include "global/debug.h" -#include "effects/effectloaders.h" - -#include -#include - -const int LOAD_TYPE_VERSION = 100; -const int LOAD_TYPE_URL = 101; - -LoadThread::LoadThread(const QString& filename, bool autorecovery) : - filename_(filename), - autorecovery_(autorecovery), - cancelled_(false) -{ - connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); - - connect(this, SIGNAL(success()), this, SLOT(success_func()), Qt::QueuedConnection); - - connect(this, SIGNAL(error()), this, SLOT(error_func()), Qt::QueuedConnection); - - connect(this, - SIGNAL(start_question(const QString&, const QString &, int)), - this, - SLOT(question_func(const QString &, const QString &, int)), - Qt::QueuedConnection); -} - -void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) { - QString tag = stream.name().toString(); - - // variables to store effect metadata in - QString effect_id; - QString effect_name; - bool effect_enabled = true; - long effect_length = -1; - - // loop through attributes for effect metadata - for (int j=0;j sequence_clips = c->track()->sequence()->GetAllClips(); - for (int i=0;iload_id == clip_id) { - sharing_clip = test_clip; - break; - } - } - - if (sharing_clip == nullptr) { - qWarning() << "Failed to link shared transition. Project may be corrupt."; - } else if (tag == "opening") { - c->opening_transition = (sharing_clip->closing_transition); - - // since this is the opened clip, switch secondaries and primaries - c->opening_transition->secondary_clip = c->opening_transition->parent_clip; - c->opening_transition->parent_clip = c; - c->opening_transition->refresh(); - } else if (tag == "closing") { - c->closing_transition = (sharing_clip->opening_transition); - - // since this is the closed clip, make this clip the secondary - c->closing_transition->secondary_clip = c; - } - return; - } - } - - // Effect loading occurs in another thread, and while it's usually very quick, just for safety we wait here - // for all the effects to finish loading - olive::effects_loaded.lock(); - - NodeType type = kInvalidNode; - - // find effect with this name - if (!effect_id.isEmpty()) { - for (int i=0;iid() == effect_id) { - type = static_cast(i); - break; - } - } - } - - olive::effects_loaded.unlock(); - - TransitionType ttype; - if (tag == "opening") { - ttype = kTransitionOpening; - } else if (tag == "closing") { - ttype = kTransitionClosing; - } else { - ttype = kTransitionNone; - } - - // effect construction - if (cancelled_) return; - if (ttype == kTransitionNone) { - if (type == kInvalidNode) { - // create void effect - OldEffectNodePtr ve = std::make_shared(c, effect_name, effect_id); - ve->SetEnabled(effect_enabled); - ve->load(stream); - - ve->moveToThread(QApplication::instance()->thread()); - - c->effects.append(ve); - } else { - OldEffectNodePtr e = olive::node_library[type]->Create(c); - e->SetEnabled(effect_enabled); - e->load(stream); - - e->moveToThread(QApplication::instance()->thread()); - - c->effects.append(e); - } - } else { - TransitionPtr t = std::static_pointer_cast(olive::node_library[type]->Create(c)); - if (effect_length > -1) { - t->set_length(effect_length); - } - t->SetEnabled(effect_enabled); - t->load(stream); - - t->moveToThread(QApplication::instance()->thread()); - - if (ttype == kTransitionOpening) { - c->opening_transition = t; - } else { - c->closing_transition = t; - } - } -} - -void LoadThread::read_next(QXmlStreamReader &stream) { - stream.readNext(); - update_current_element_count(stream); -} - -void LoadThread::read_next_start_element(QXmlStreamReader &stream) { - stream.readNextStartElement(); - update_current_element_count(stream); -} - -void LoadThread::update_current_element_count(QXmlStreamReader &stream) { - if (is_element(stream)) { - current_element_count++; - report_progress((current_element_count * 100) / total_element_count); - } -} - -void LoadThread::show_message(const QString& title, const QString& body, int buttons) -{ - emit start_question( - title, - body, - buttons - ); - waitCond.wait(&mutex); -} - -bool LoadThread::is_element(QXmlStreamReader &stream) { - return stream.isStartElement() - && (stream.name() == "folder" - || stream.name() == "footage" - || stream.name() == "sequence" - || stream.name() == "clip" - || stream.name() == "effect"); -} - -bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { - f.seek(0); - stream.setDevice(stream.device()); - - QString root_search; - QString child_search; - - switch (type) { - case LOAD_TYPE_VERSION: - root_search = "version"; - break; - case LOAD_TYPE_URL: - root_search = "url"; - break; - case MEDIA_TYPE_FOLDER: - root_search = "folders"; - child_search = "folder"; - break; - case MEDIA_TYPE_FOOTAGE: - root_search = "media"; - child_search = "footage"; - break; - case MEDIA_TYPE_SEQUENCE: - root_search = "sequences"; - child_search = "sequence"; - break; - } - - show_err = true; - - int proj_version = olive::kSaveVersion; - - while (!stream.atEnd() && !cancelled_) { - read_next_start_element(stream); - if (stream.name() == root_search) { - if (type == LOAD_TYPE_VERSION) { - proj_version = stream.readElementText().toInt(); - if (proj_version < olive::kMinimumSaveVersion || proj_version > olive::kSaveVersion) { - show_message( - tr("Version Mismatch"), - tr("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?"), - QMessageBox::Yes | QMessageBox::No - ); - if (question_btn == QMessageBox::No) { - show_err = false; - return false; - } - } - } else if (type == LOAD_TYPE_URL) { - internal_proj_url = stream.readElementText(); - internal_proj_dir = QFileInfo(internal_proj_url).absoluteDir(); - } else { - while (!cancelled_ && !stream.atEnd() && !(stream.name() == root_search && stream.isEndElement())) { - read_next(stream); - if (stream.name() == child_search && stream.isStartElement()) { - switch (type) { - case MEDIA_TYPE_FOLDER: - { - MediaPtr folder = olive::project::CreateFolder(nullptr); - folder->temp_id2 = 0; - for (int j=0;jtemp_id = attr.value().toInt(); - } else if (attr.name() == "name") { - folder->set_name(attr.value().toString()); - } else if (attr.name() == "parent") { - folder->temp_id2 = attr.value().toInt(); - } - } - loaded_folders.append(folder); - } - break; - case MEDIA_TYPE_FOOTAGE: - { - int folder = 0; - - MediaPtr item = std::make_shared(); - FootagePtr f = std::make_shared(); - - f->using_inout = false; - - for (int j=0;jsave_id = attr.value().toInt(); - } else if (attr.name() == "folder") { - folder = attr.value().toInt(); - } else if (attr.name() == "name") { - f->name = attr.value().toString(); - } else if (attr.name() == "url") { - f->url = attr.value().toString(); - - if (!QFileInfo::exists(f->url)) { // if path is not absolute - // tries to locate file using a file path relative to the project's current folder - QString proj_dir_test = proj_dir.absoluteFilePath(f->url); - - // tries to locate file using a file path relative to the folder the project was saved in - // (unaffected by moving the project file) - QString internal_proj_dir_test = internal_proj_dir.absoluteFilePath(f->url); - - // tries to locate file using the file name directly in the project's current folder - QString proj_dir_direct_test = proj_dir.filePath(QFileInfo(f->url).fileName()); - - if (QFileInfo::exists(proj_dir_test)) { - - f->url = proj_dir_test; - qInfo() << "Matched" << attr.value().toString() << "relative to project's current directory"; - - } else if (QFileInfo::exists(internal_proj_dir_test)) { - - f->url = internal_proj_dir_test; - qInfo() << "Matched" << attr.value().toString() << "relative to project's internal directory"; - - } else if (QFileInfo::exists(proj_dir_direct_test)) { - - f->url = proj_dir_direct_test; - qInfo() << "Matched" << attr.value().toString() << "directly to project's current directory"; - - } else if (f->url.contains('%')) { - - // hack for image sequences (qt won't be able to find the URL with %, but ffmpeg may) - f->url = internal_proj_dir_test; - qInfo() << "Guess image sequence" << attr.value().toString() << "path to project's internal directory"; - - } else { - - qInfo() << "Failed to match" << attr.value().toString() << "to file"; - - } - } else { - f->url = QFileInfo(f->url).absoluteFilePath(); - qInfo() << "Matched" << attr.value().toString() << "with absolute path"; - } - } else if (attr.name() == "duration") { - f->length = attr.value().toLongLong(); - } else if (attr.name() == "using_inout") { - f->using_inout = (attr.value() == "1"); - } else if (attr.name() == "in") { - f->in = attr.value().toLong(); - } else if (attr.name() == "out") { - f->out = attr.value().toLong(); - } else if (attr.name() == "speed") { - f->speed = attr.value().toDouble(); - } else if (attr.name() == "alphapremul") { - f->alpha_is_associated = (attr.value() == "1"); - } else if (attr.name() == "proxy") { - f->proxy = (attr.value() == "1"); - } else if (attr.name() == "proxypath") { - f->proxy_path = attr.value().toString(); - } else if (attr.name() == "startnumber") { - f->start_number = attr.value().toInt(); - } else if (attr.name() == "colorspace") { - f->SetColorspace(attr.value().toString()); - } - } - - while (!cancelled_ && !(stream.name() == child_search && stream.isEndElement()) && !stream.atEnd()) { - read_next_start_element(stream); - if (stream.name() == "marker" && stream.isStartElement()) { - Marker m; - for (int j=0;jmarkers.append(m); - } - } - - item->set_footage(f); - - olive::project_model.appendChild(find_loaded_folder_by_id(folder), item); - - // analyze media to see if it's the same - loaded_media_items.append(item.get()); - } - break; - case MEDIA_TYPE_SEQUENCE: - { - Media* parent = nullptr; - SequencePtr s = std::make_shared(); - - // load attributes about sequence - for (int j=0;jset_name(attr.value().toString()); - } else if (attr.name() == "folder") { - int folder = attr.value().toInt(); - if (folder > 0) parent = find_loaded_folder_by_id(folder); - } else if (attr.name() == "id") { - s->save_id = attr.value().toInt(); - } else if (attr.name() == "width") { - s->set_width(attr.value().toInt()); - } else if (attr.name() == "height") { - s->set_height(attr.value().toInt()); - } else if (attr.name() == "framerate") { - s->set_frame_rate(attr.value().toDouble()); - } else if (attr.name() == "afreq") { - s->set_audio_frequency(attr.value().toInt()); - } else if (attr.name() == "alayout") { - s->set_audio_layout(attr.value().toInt()); - } else if (attr.name() == "open") { - open_seq = s; - } else if (attr.name() == "workarea") { - s->using_workarea = (attr.value() == "1"); - } else if (attr.name() == "workareaIn") { - s->workarea_in = attr.value().toLong(); - } else if (attr.name() == "workareaOut") { - s->workarea_out = attr.value().toLong(); - } - } - - // load all clips and clip information - while (!cancelled_ && !(stream.name() == child_search && stream.isEndElement()) && !stream.atEnd()) { - read_next_start_element(stream); - if (stream.name() == "marker" && stream.isStartElement()) { - Marker m; - for (int j=0;jmarkers.append(m); - } else if (stream.name() == "clip" && stream.isStartElement()) { - int media_type = -1; - int media_id = -1; - int stream_id = -1; - - Track* t; - ClipPtr c = std::make_shared(t); - //ClipPtr c = std::make_shared(s.get()); - - QColor clip_color; - ClipSpeed speed_info = c->speed(); - - for (int j=0;jset_name(attr.value().toString()); - } else if (attr.name() == "enabled") { - c->set_enabled(attr.value() == "1"); - } else if (attr.name() == "id") { - c->load_id = attr.value().toInt(); - } else if (attr.name() == "clipin") { - c->set_clip_in(attr.value().toLong()); - } else if (attr.name() == "in") { - c->set_timeline_in(attr.value().toLong()); - } else if (attr.name() == "out") { - c->set_timeline_out(attr.value().toLong()); - } else if (attr.name() == "r") { - clip_color.setRed(attr.value().toInt()); - } else if (attr.name() == "g") { - clip_color.setGreen(attr.value().toInt()); - } else if (attr.name() == "b") { - clip_color.setBlue(attr.value().toInt()); - } else if (attr.name() == "autoscale") { - c->set_autoscaled(attr.value() == "1"); - } else if (attr.name() == "media") { - media_type = MEDIA_TYPE_FOOTAGE; - media_id = attr.value().toInt(); - } else if (attr.name() == "stream") { - stream_id = attr.value().toInt(); - } else if (attr.name() == "speed") { - speed_info.value = attr.value().toDouble(); - } else if (attr.name() == "maintainpitch") { - speed_info.maintain_audio_pitch = (attr.value() == "1"); - } else if (attr.name() == "reverse") { - c->set_reversed(attr.value() == "1"); - } else if (attr.name() == "sequence") { - media_type = MEDIA_TYPE_SEQUENCE; - - // since we haven't finished loading sequences, we defer linking this until later - c->set_media(nullptr, attr.value().toInt()); - loaded_clips.append(c); - } - } - - c->set_color(clip_color); - c->set_speed(speed_info); - - // set media and media stream - switch (media_type) { - case MEDIA_TYPE_FOOTAGE: - if (media_id >= 0 && stream_id >= 0) { - for (int j=0;jto_footage(); - if (m->save_id == media_id) { - c->set_media(loaded_media_items.at(j), stream_id); - break; - } - } - } - break; - } - - // load links and effects - while (!cancelled_ && !(stream.name() == "clip" && stream.isEndElement()) && !stream.atEnd()) { - read_next(stream); - if (stream.isStartElement()) { - if (stream.name() == "linked") { - while (!cancelled_ && !(stream.name() == "linked" && stream.isEndElement()) && !stream.atEnd()) { - read_next(stream); - if (stream.name() == "link" && stream.isStartElement()) { - for (int k=0;klinked.append(link_attr.value().toInt()); - break; - } - } - } - } - if (cancelled_) return false; - } else if (stream.isStartElement() - && (stream.name() == "effect" - || stream.name() == "opening" - || stream.name() == "closing")) { - load_effect(stream, c.get()); - } else if (stream.name() == "marker" && stream.isStartElement()) { - Marker m; - for (int j=0;jget_markers().append(m); - } - } - } - if (cancelled_) return false; - - //s->clips.append(c); - } - } - if (cancelled_) return false; - - /* - // correct links, clip IDs, transitions - for (int i=0;iclips.size();i++) { - // correct links - Clip* correct_clip = s->clips.at(i).get(); - for (int j=0;jlinked.size();j++) { - bool found = false; - for (int k=0;kclips.size();k++) { - if (s->clips.at(k)->load_id == correct_clip->linked.at(j)) { - correct_clip->linked[j] = k; - found = true; - break; - } - } - if (!found) { - correct_clip->linked.removeAt(j); - j--; - - show_message( - tr("Invalid Clip Link"), - tr("This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it?"), - QMessageBox::Yes | QMessageBox::No - ); - - if (question_btn == QMessageBox::No) { - s.reset(); - return false; - } - } - } - } - - MediaPtr m = panel_project->create_sequence_internal(nullptr, s, false, parent); - - loaded_sequences.append(m.get()); - */ - } - break; - } - } - } - if (cancelled_) return false; - } - break; - } - } - return !cancelled_; -} - -Media* LoadThread::find_loaded_folder_by_id(int id) { - if (id == 0) return nullptr; - for (int j=0;jtemp_id == id) { - return parent_item; - } - } - return nullptr; -} - -void LoadThread::OrganizeFolders(int folder) { - for (int i=0;itemp_id2; - - if (parent_id == folder) { - olive::project_model.appendChild(find_loaded_folder_by_id(parent_id), item); - - OrganizeFolders(item->temp_id); - } - - } -} - -void LoadThread::run() { - mutex.lock(); - - QFile file(filename_); - if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Could not open file"; - return; - } - - /* set up directories to search for media - * most of the time, these will be the same but in - * case the project file has moved without the footage, - * we check both - */ - proj_dir = QFileInfo(filename_).absoluteDir(); - internal_proj_dir = QFileInfo(filename_).absoluteDir(); - internal_proj_url = filename_; - - QXmlStreamReader stream(&file); - - bool cont = false; - error_str.clear(); - show_err = true; - - open_seq = nullptr; - - // get "element" count - current_element_count = 0; - total_element_count = 0; - while (!cancelled_ && !stream.atEnd()) { - stream.readNextStartElement(); - if (is_element(stream)) { - total_element_count++; - } - } - cont = !cancelled_; - - // find project file version - if (cont) { - cont = load_worker(file, stream, LOAD_TYPE_VERSION); - } - - // find project's internal URL - if (cont) { - cont = load_worker(file, stream, LOAD_TYPE_URL); - } - - // load folders first - if (cont) { - cont = load_worker(file, stream, MEDIA_TYPE_FOLDER); - } - - if (cont) { - // since folders loaded correctly, organize them appropriately - OrganizeFolders(); - - // load media - cont = load_worker(file, stream, MEDIA_TYPE_FOOTAGE); - } - - // load sequences - if (cont) { - cont = load_worker(file, stream, MEDIA_TYPE_SEQUENCE); - } - - if (!cancelled_) { - if (!cont) { - xml_error = false; - if (show_err) emit error(); - } else if (stream.hasError()) { - error_str = tr("%1 - Line: %2 Col: %3").arg(stream.errorString(), QString::number(stream.lineNumber()), QString::number(stream.columnNumber())); - xml_error = true; - emit error(); - cont = false; - } else { - // attach nested sequence clips to their sequences - for (int i=0;imedia() == nullptr - && loaded_clips.at(i)->media_stream_index() == loaded_sequences.at(j)->to_sequence()->save_id) { - loaded_clips.at(i)->set_media(loaded_sequences.at(j), loaded_clips.at(i)->media_stream_index()); - loaded_clips.at(i)->refresh(); - break; - } - } - } - } - } - - if (cont) { - emit success(); // run in main thread - - for (int i=0;i(buttons)); - mutex.unlock(); - waitCond.wakeAll(); -} - -void LoadThread::error_func() { - if (xml_error) { - qCritical() << "Error parsing XML." << error_str; - QMessageBox::critical(olive::MainWindow, - tr("XML Parsing Error"), - tr("Couldn't load '%1'. %2").arg(filename_, error_str), - QMessageBox::Ok); - } else { - QMessageBox::critical(olive::MainWindow, - tr("Project Load Error"), - tr("Error loading project: %1").arg(error_str), - QMessageBox::Ok); - } -} - -void LoadThread::success_func() { - if (autorecovery_) { - QString orig_filename = internal_proj_url; - int insert_index = internal_proj_url.lastIndexOf(".ove", -1, Qt::CaseInsensitive); - if (insert_index == -1) insert_index = internal_proj_url.length(); - int counter = 1; - while (QFileInfo::exists(orig_filename)) { - orig_filename = internal_proj_url; - QString recover_text = "recovered"; - if (counter > 1) { - recover_text += " " + QString::number(counter); - } - orig_filename.insert(insert_index, " (" + recover_text + ")"); - counter++; - } - - olive::Global->update_project_filename(orig_filename); - } else { - olive::Global->add_recent_project(filename_); - } - - olive::Global->set_modified(autorecovery_); - if (open_seq != nullptr) { - Timeline::OpenSequence(open_seq); - } -} diff --git a/project/loadthread.h b/project/loadthread.h deleted file mode 100644 index 7f57f60cc..000000000 --- a/project/loadthread.h +++ /dev/null @@ -1,92 +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 LOADTHREAD_H -#define LOADTHREAD_H - -#include -#include -#include -#include -#include -#include - -#include "project/projectelements.h" -#include "timeline/clip.h" - -class LoadThread : public QThread -{ - Q_OBJECT -public: - LoadThread(const QString& filename, bool autorecovery); - void run(); -public slots: - void cancel(); -signals: - void start_question(const QString &title, const QString &text, int buttons); - void success(); - void error(); - void report_progress(int p); -private slots: - void question_func(const QString &title, const QString &text, int buttons); - void error_func(); - void success_func(); -private: - bool autorecovery_; - QString filename_; - - bool load_worker(QFile& f, QXmlStreamReader& stream, int type); - void load_effect(QXmlStreamReader& stream, Clip* c); - - void read_next(QXmlStreamReader& stream); - void read_next_start_element(QXmlStreamReader& stream); - void update_current_element_count(QXmlStreamReader& stream); - - void show_message(const QString& title, const QString& body, int buttons); - - SequencePtr open_seq; - QVector loaded_media_items; - QDir proj_dir; - QDir internal_proj_dir; - QString internal_proj_url; - bool show_err; - QString error_str; - - bool is_element(QXmlStreamReader& stream); - - QVector loaded_folders; - QVector loaded_clips; - QVector loaded_sequences; - Media* find_loaded_folder_by_id(int id); - void OrganizeFolders(int folder = 0); - - int current_element_count; - int total_element_count; - - QMutex mutex; - QWaitCondition waitCond; - - bool cancelled_; - bool xml_error; - - QMessageBox::StandardButton question_btn; -}; - -#endif // LOADTHREAD_H diff --git a/project/media.cpp b/project/media.cpp deleted file mode 100644 index 6d1f2a9bf..000000000 --- a/project/media.cpp +++ /dev/null @@ -1,394 +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 "media.h" - -extern "C" { -#include -#include -} - -#include -#include - -#include "footage.h" -#include "timeline/sequence.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "global/config.h" -#include "panels/project.h" -#include "ui/icons.h" -#include "projectmodel.h" -#include "global/debug.h" -#include "global/timing.h" - -Media::Media() : - root(false), - type(-1), - disable_thumbnail_(false) -{ -} - -void Media::Save(QXmlStreamWriter &stream) -{ - switch (type) { - case MEDIA_TYPE_FOLDER: - stream.writeStartElement("folder"); - stream.writeAttribute("name", get_name()); - stream.writeEndElement(); - break; - case MEDIA_TYPE_FOOTAGE: - to_footage()->Save(stream); - break; - case MEDIA_TYPE_SEQUENCE: - to_sequence()->Save(stream); - break; - } -} - -Footage* Media::to_footage() { - return static_cast(object.get()); -} - -SequencePtr Media::to_sequence() { - return std::static_pointer_cast(object); -} - -void Media::set_footage(FootagePtr f) { - type = MEDIA_TYPE_FOOTAGE; - object = VoidPtr(f); -} - -void Media::set_sequence(SequencePtr s) { - set_icon(olive::icon::MediaSequence); - type = MEDIA_TYPE_SEQUENCE; - object = VoidPtr(s); - if (s != nullptr) { - update_tooltip(); - } -} - -void Media::set_folder() { - if (folder_name.isEmpty()) { - folder_name = QCoreApplication::translate("Media", "New Folder"); - } - set_icon(olive::icon::MediaFolder); - type = MEDIA_TYPE_FOLDER; - object = nullptr; -} - -void Media::set_icon(const QString &str) -{ - set_icon(QIcon(str)); -} - -void Media::set_icon(const QIcon &ico) { - icon = ico; -} - -void Media::set_parent(Media *p) { - parent = p; -} - -void Media::update_tooltip(const QString& error) { - switch (type) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* f = to_footage(); - tooltip = QCoreApplication::translate("Media", "Name:") + " " + f->name + "\n" + QCoreApplication::translate("Media", "Filename:") + " " + f->url + "\n"; - - if (error.isEmpty()) { - if (f->video_tracks.size() > 0) { - tooltip += QCoreApplication::translate("Media", "Video Dimensions:") + " "; - for (int i=0;ivideo_tracks.size();i++) { - if (i > 0) { - tooltip += ", "; - } - tooltip += QString::number(f->video_tracks.at(i).video_width) + "x" + QString::number(f->video_tracks.at(i).video_height); - } - tooltip += "\n"; - - if (!f->video_tracks.at(0).infinite_length) { - tooltip += QCoreApplication::translate("Media", "Frame Rate:") + " "; - for (int i=0;ivideo_tracks.size();i++) { - if (i > 0) { - tooltip += ", "; - } - if (f->video_tracks.at(i).video_interlacing == VIDEO_PROGRESSIVE) { - tooltip += QString::number(f->video_tracks.at(i).video_frame_rate * f->speed); - } else { - double adjusted_rate = f->video_tracks.at(i).video_frame_rate * f->speed; - - tooltip += QCoreApplication::translate("Media", "%1 field(s) (%2 frame(s))").arg( - QString::number(adjusted_rate*2.0), - QString::number(adjusted_rate) - ); - } - } - tooltip += "\n"; - } - - tooltip += QCoreApplication::translate("Media", "Interlacing:") + " "; - for (int i=0;ivideo_tracks.size();i++) { - if (i > 0) { - tooltip += ", "; - } - tooltip += Footage::get_interlacing_name(f->video_tracks.at(i).video_interlacing); - } - } - - if (f->audio_tracks.size() > 0) { - tooltip += "\n"; - - tooltip += QCoreApplication::translate("Media", "Audio Frequency:") + " "; - for (int i=0;iaudio_tracks.size();i++) { - if (i > 0) { - tooltip += ", "; - } - tooltip += QString::number(f->audio_tracks.at(i).audio_frequency * f->speed); - } - tooltip += "\n"; - - tooltip += QCoreApplication::translate("Media", "Audio Channels:") + " "; - for (int i=0;iaudio_tracks.size();i++) { - if (i > 0) { - tooltip += ", "; - } - tooltip += Footage::get_channel_layout_name(f->audio_tracks.at(i).audio_channels, f->audio_tracks.at(i).audio_layout); - } - // tooltip += "\n"; - } - } else { - tooltip += error; - } - } - break; - case MEDIA_TYPE_SEQUENCE: - { - Sequence* s = to_sequence().get(); - - tooltip = QCoreApplication::translate("Media", "Name: %1" - "\nVideo Dimensions: %2x%3" - "\nFrame Rate: %4" - "\nAudio Frequency: %5" - "\nAudio Layout: %6").arg( - s->name(), - QString::number(s->width()), - QString::number(s->height()), - QString::number(s->frame_rate()), - QString::number(s->audio_frequency()), - Footage::get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout()), s->audio_layout()) - ); - } - break; - } - -} - -VoidPtr Media::to_object() { - return object; -} - -int Media::get_type() { - return type; -} - -const QString &Media::get_name() { - switch (type) { - case MEDIA_TYPE_FOOTAGE: return to_footage()->name; - case MEDIA_TYPE_SEQUENCE: return to_sequence()->name(); - default: return folder_name; - } -} - -void Media::set_name(const QString &n) { - switch (type) { - case MEDIA_TYPE_FOOTAGE: to_footage()->name = n; break; - case MEDIA_TYPE_SEQUENCE: to_sequence()->set_name(n); break; - case MEDIA_TYPE_FOLDER: folder_name = n; break; - } -} - -void Media::disable_thumbnail(bool disable) -{ - disable_thumbnail_ = disable; -} - -double Media::get_frame_rate(int stream) { - switch (get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* f = to_footage(); - if (stream < 0) return f->video_tracks.at(0).video_frame_rate * f->speed; - return f->get_stream_from_file_index(true, stream)->video_frame_rate * f->speed; - } - case MEDIA_TYPE_SEQUENCE: return to_sequence()->frame_rate(); - } - return 0; -} - -int Media::get_sampling_rate(int stream) { - switch (get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* f = to_footage(); - if (stream < 0) return f->audio_tracks.at(0).audio_frequency * f->speed; - return to_footage()->get_stream_from_file_index(false, stream)->audio_frequency * f->speed; - } - case MEDIA_TYPE_SEQUENCE: return to_sequence()->audio_frequency(); - } - return 0; -} - -void Media::appendChild(MediaPtr child) { - child->set_parent(this); - children.append(child); -} - -bool Media::setData(int col, const QVariant &value) { - if (col == 0) { - QString n = value.toString(); - if (!n.isEmpty() && get_name() != n) { - olive::undo_stack.push(new MediaRename(this, value.toString())); - return true; - } - } - return false; -} - -Media *Media::child(int row) { - return children.value(row).get(); -} - -int Media::childCount() const { - return children.count(); -} - -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::config.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::config.timecode_view, r); - } - return QString(); -} - -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 (!disable_thumbnail_ - && f->video_tracks.size() > 0 - && f->video_tracks.at(0).preview_done) { - return QIcon(QPixmap::fromImage(f->video_tracks.at(0).video_preview)); - } - } - - return icon; - } - break; - case Qt::DisplayRole: - switch (column) { - case 0: return (root) ? QCoreApplication::translate("Media", "Name") : get_name(); - case 1: - if (root) return QCoreApplication::translate("Media", "Duration"); - return GetStringDuration(); - break; - case 2: - if (root) return QCoreApplication::translate("Media", "Rate"); - if (get_type() == MEDIA_TYPE_SEQUENCE) return QString::number(get_frame_rate()) + " FPS"; - if (get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* f = to_footage(); - double r; - if (f->video_tracks.size() > 0 && !qIsNull(r = get_frame_rate())) { - return QString::number(get_frame_rate()) + " FPS"; - } else if (f->audio_tracks.size() > 0) { - return QString::number(get_sampling_rate()) + " Hz"; - } - } - break; - } - break; - case Qt::ToolTipRole: - return tooltip; - - case Qt::UserRole: - // User role returns the duration - return GetStringDuration(); - } - return QVariant(); -} - -int Media::row() const { - if (parent != nullptr) { - for (int i=0;ichildren.size();i++) { - if (parent->children.at(i).get() == this) { - return i; - } - } - } - return 0; -} - -Media *Media::parentItem() { - return parent; -} - -void Media::removeChild(int i) { - children.removeAt(i); -} - -MediaPtr Media::get_shared_ptr(Media *m) -{ - for (int i=0;i &Media::get_markers() { - // returns the marker array from the internal object - // - // NOTE: if this media object is not footage or a sequence, the result is - // undefined - most likely a crash - - if (get_type() == MEDIA_TYPE_FOOTAGE) { - return to_footage()->markers; - } else { - return to_sequence()->markers; - } -} diff --git a/project/media.h b/project/media.h deleted file mode 100644 index e9555b310..000000000 --- a/project/media.h +++ /dev/null @@ -1,104 +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 MEDIA_H -#define MEDIA_H - -#include -#include -#include - -#include "timeline/marker.h" -#include "project/footage.h" - -enum MediaType { - MEDIA_TYPE_FOOTAGE, - MEDIA_TYPE_SEQUENCE, - MEDIA_TYPE_FOLDER -}; - -class Sequence; -using SequencePtr = std::shared_ptr; - -using VoidPtr = std::shared_ptr; - -class Media; -using MediaPtr = std::shared_ptr; - -class Media -{ -public: - Media(); - - void Save(QXmlStreamWriter& stream); - - Footage *to_footage(); - SequencePtr to_sequence(); - void set_icon(const QString& str); - void set_icon(const QIcon &ico); - void set_footage(FootagePtr f); - void set_sequence(SequencePtr s); - void set_folder(); - void set_parent(Media* p); - void update_tooltip(const QString& error = nullptr); - VoidPtr to_object(); - int get_type(); - const QString& get_name(); - void set_name(const QString& n); - void disable_thumbnail(bool disable); - - double get_frame_rate(int stream = -1); - int get_sampling_rate(int stream = -1); - - // item functions - void appendChild(MediaPtr child); - bool setData(int col, const QVariant &value); - Media *child(int row); - int childCount() const; - int columnCount() const; - QVariant data(int column, int role); - int row() const; - Media *parentItem(); - void removeChild(int i); - MediaPtr get_shared_ptr(Media* m); - - // get markers from internal object - QVector& get_markers(); - - bool root; - int temp_id; - int temp_id2; - -private: - int type; - VoidPtr object; - - QString GetStringDuration(); - - // item functions - QList children; - Media* parent; - QString folder_name; - QString tooltip; - QIcon icon; - bool disable_thumbnail_; -}; - -#endif // MEDIA_H diff --git a/project/previewgenerator.cpp b/project/previewgenerator.cpp deleted file mode 100644 index 937841506..000000000 --- a/project/previewgenerator.cpp +++ /dev/null @@ -1,628 +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 "previewgenerator.h" - -#include "ui/mediaiconservice.h" -#include "project/media.h" -#include "project/footage.h" -#include "panels/viewer.h" -#include "panels/project.h" -#include "global/config.h" -#include "global/path.h" -#include "global/debug.h" - -#include -#include -#include -#include -#include -#include -#include - -QSemaphore sem(5); // only 5 preview generators can run at one time - -PreviewGenerator::PreviewGenerator(Media* i) : - QThread(nullptr) -{ - fmt_ctx_ = (nullptr); - media_ = (i); - retrieve_duration_ = (false); - contains_still_image_ = (false); - cancelled_ = (false); - footage_ = media_->to_footage(); - - footage_->preview_gen = this; - - data_dir_ = QDir(get_data_dir().filePath("previews")); - if (!data_dir_.exists()) { - data_dir_.mkpath("."); - } - - connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); - - // set up throbber animation - olive::media_icon_service->SetMediaIcon(media_, ICON_TYPE_LOADING); - - start(QThread::LowPriority); -} - -void PreviewGenerator::parse_media() { - // detect video/audio streams in file - for (int i=0;inb_streams);i++) { - // Find the decoder for the video stream - if (avcodec_find_decoder(fmt_ctx_->streams[i]->codecpar->codec_id) == nullptr) { - qCritical() << "Unsupported codec in stream" << i << "of file" << footage_->name; - } else { - FootageStream ms; - ms.preview_done = false; - ms.file_index = i; - ms.enabled = true; - ms.infinite_length = false; - - bool append = false; - - if (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO - && fmt_ctx_->streams[i]->codecpar->width > 0 - && fmt_ctx_->streams[i]->codecpar->height > 0) { - - // heuristic to determine if video is a still image (if it is, we treat it differently in the playback/render process) - if (fmt_ctx_->streams[i]->avg_frame_rate.den == 0 - && fmt_ctx_->streams[i]->codecpar->codec_id != AV_CODEC_ID_DNXHD) { // silly hack but this is the only scenario i've seen this - if (footage_->url.contains('%')) { - // must be an image sequence - ms.video_frame_rate = 25; - } else { - ms.infinite_length = true; - contains_still_image_ = true; - ms.video_frame_rate = 0; - } - - } else { - // using ffmpeg's built-in heuristic - ms.video_frame_rate = av_q2d(av_guess_frame_rate(fmt_ctx_, fmt_ctx_->streams[i], nullptr)); - } - - ms.video_width = fmt_ctx_->streams[i]->codecpar->width; - ms.video_height = fmt_ctx_->streams[i]->codecpar->height; - - // default value, we get the true value later in generate_waveform() - ms.video_auto_interlacing = VIDEO_PROGRESSIVE; - ms.video_interlacing = VIDEO_PROGRESSIVE; - - append = true; - } else if (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - ms.audio_channels = fmt_ctx_->streams[i]->codecpar->channels; - ms.audio_layout = int(fmt_ctx_->streams[i]->codecpar->channel_layout); - ms.audio_frequency = fmt_ctx_->streams[i]->codecpar->sample_rate; - - append = true; - } - - if (append) { - QVector& stream_list = (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ? - footage_->audio_tracks : footage_->video_tracks; - - for (int j=0;jlength = fmt_ctx_->duration; - - if (fmt_ctx_->duration == INT64_MIN) { - retrieve_duration_ = true; - } else { - finalize_media(); - } -} - -bool PreviewGenerator::retrieve_preview(const QString& hash) { - // returns true if generate_waveform must be run, false if we got all previews from cached files - if (retrieve_duration_) { - //dout << "[NOTE] " << media->name << "needs to retrieve duration"; - return true; - } - - bool found = true; - for (int i=0;ivideo_tracks.size();i++) { - FootageStream& ms = footage_->video_tracks[i]; - QString thumb_path = get_thumbnail_path(hash, ms); - QFile f(thumb_path); - if (f.exists() && ms.video_preview.load(thumb_path)) { - ms.preview_done = true; - } else { - found = false; - break; - } - } - for (int i=0;iaudio_tracks.size();i++) { - FootageStream& ms = footage_->audio_tracks[i]; - QString waveform_path = get_waveform_path(hash, ms); - QFile f(waveform_path); - if (f.exists()) { - //dout << "loaded wave" << ms->file_index << "from" << waveform_path; - f.open(QFile::ReadOnly); - QByteArray data = f.readAll(); - ms.audio_preview.resize(data.size()); - memcpy(ms.audio_preview.data(), data, data.size()); - ms.preview_done = true; - f.close(); - } else { - found = false; - break; - } - } - if (!found) { - for (int i=0;ivideo_tracks.size();i++) { - FootageStream& ms = footage_->video_tracks[i]; - ms.preview_done = false; - } - for (int i=0;iaudio_tracks.size();i++) { - FootageStream& ms = footage_->audio_tracks[i]; - ms.audio_preview.clear(); - ms.preview_done = false; - } - } - return !found; -} - -void PreviewGenerator::finalize_media() { - if (!cancelled_) { - bool footage_is_ready = true; - - if (footage_->video_tracks.isEmpty() && footage_->audio_tracks.isEmpty()) { - // ERROR - footage_is_ready = false; - invalidate_media(tr("Failed to find any valid video/audio streams")); - } else if (!footage_->video_tracks.isEmpty() && !contains_still_image_) { - // VIDEO - olive::media_icon_service->SetMediaIcon(media_, ICON_TYPE_VIDEO); - } else if (!footage_->audio_tracks.isEmpty()) { - // AUDIO - olive::media_icon_service->SetMediaIcon(media_, ICON_TYPE_AUDIO); - } else { - // IMAGE - olive::media_icon_service->SetMediaIcon(media_, ICON_TYPE_IMAGE); - } - - if (footage_is_ready) { - footage_->ready_lock.unlock(); - footage_->ready = true; - media_->update_tooltip(); - } - - QVector all_sequences = olive::project_model.GetAllSequences(); - for (int i=0;ito_sequence()->RefreshClipsUsingMedia(media_); - } - } -} - -void PreviewGenerator::invalidate_media(const QString &error_msg) -{ - media_->update_tooltip(error_msg); - olive::media_icon_service->SetMediaIcon(media_, ICON_TYPE_ERROR); - footage_->invalid = true; - footage_->ready_lock.unlock(); -} - -void PreviewGenerator::generate_waveform() { - SwsContext* sws_ctx; - SwrContext* swr_ctx; - AVFrame* temp_frame = av_frame_alloc(); - - // stores codec contexts for format's streams - AVCodecContext** codec_ctx = new AVCodecContext* [fmt_ctx_->nb_streams]; - - // stores media lengths while scanning in case the format has no duration metadata - int64_t* media_lengths = new int64_t[fmt_ctx_->nb_streams]{0}; - - // stores samples while scanning before they get sent to preview file - qint8*** waveform_cache_data = new qint8** [fmt_ctx_->nb_streams]; - int waveform_cache_count = 0; - - // defaults to false, sets to true if we find a valid stream to make a preview of - bool create_previews = false; - - for (unsigned int i=0;inb_streams;i++) { - - // default to nullptr values for easier memory management later - codec_ctx[i] = nullptr; - waveform_cache_data[i] = nullptr; - - // we only generate previews for video and audio - // and only if the thumbnail and waveform sizes are > 0 - if ((fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && olive::config.thumbnail_resolution > 0) - || (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && olive::config.waveform_resolution > 0)) { - AVCodec* codec = avcodec_find_decoder(fmt_ctx_->streams[i]->codecpar->codec_id); - if (codec != nullptr) { - - // alloc the context and load the params into it - codec_ctx[i] = avcodec_alloc_context3(codec); - avcodec_parameters_to_context(codec_ctx[i], fmt_ctx_->streams[i]->codecpar); - - // open the decoder - avcodec_open2(codec_ctx[i], codec, nullptr); - - // audio specific functions - if (fmt_ctx_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - - // allocate sample cache for this stream - waveform_cache_data[i] = new qint8* [fmt_ctx_->streams[i]->codecpar->channels]; - - // each channel gets a min and a max value so we allocate two ints for each one - for (int j=0;jstreams[i]->codecpar->channels;j++) { - waveform_cache_data[i][j] = new qint8[2]; - } - - // if codec context has no defined channel layout, guess it from the channel count - if (codec_ctx[i]->channel_layout == 0) { - codec_ctx[i]->channel_layout = av_get_default_channel_layout(fmt_ctx_->streams[i]->codecpar->channels); - } - - } - - // enable next step of process - create_previews = true; - } - } - } - - if (create_previews) { - // TODO may be unnecessary - doesn't av_read_frame allocate a packet itself? - AVPacket* packet = av_packet_alloc(); - - bool done = true; - - bool end_of_file = false; - - // get the ball rolling - do { - av_read_frame(fmt_ctx_, packet); - } while (codec_ctx[packet->stream_index] == nullptr); - avcodec_send_packet(codec_ctx[packet->stream_index], packet); - - while (!end_of_file) { - while (codec_ctx[packet->stream_index] == nullptr || avcodec_receive_frame(codec_ctx[packet->stream_index], temp_frame) == AVERROR(EAGAIN)) { - av_packet_unref(packet); - int read_ret = av_read_frame(fmt_ctx_, packet); - - if (read_ret < 0) { - end_of_file = true; - if (read_ret != AVERROR_EOF) qCritical() << "Failed to read packet for preview generation" << read_ret; - break; - } - if (codec_ctx[packet->stream_index] != nullptr) { - int send_ret = avcodec_send_packet(codec_ctx[packet->stream_index], packet); - if (send_ret < 0 && send_ret != AVERROR(EAGAIN)) { - qCritical() << "Failed to send packet for preview generation - aborting" << send_ret; - end_of_file = true; - break; - } - } - } - if (!end_of_file) { - FootageStream* s = footage_->get_stream_from_file_index(fmt_ctx_->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO, packet->stream_index); - if (s != nullptr) { - if (fmt_ctx_->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - if (!s->preview_done) { - int dstH = olive::config.thumbnail_resolution; - int dstW = qRound(dstH * (float(temp_frame->width)/float(temp_frame->height))); - - sws_ctx = sws_getContext( - temp_frame->width, - temp_frame->height, - static_cast(temp_frame->format), - dstW, - dstH, - static_cast(AV_PIX_FMT_RGBA), - SWS_FAST_BILINEAR, - nullptr, - nullptr, - nullptr - ); - - int linesize[AV_NUM_DATA_POINTERS]; - linesize[0] = dstW*4; - - s->video_preview = QImage(dstW, dstH, QImage::Format_RGBA8888); - uint8_t* data = s->video_preview.bits(); - - sws_scale(sws_ctx, - temp_frame->data, - temp_frame->linesize, - 0, - temp_frame->height, - &data, - linesize); - - // 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; - - s->preview_done = true; - - sws_freeContext(sws_ctx); - - if (!retrieve_duration_) { - avcodec_close(codec_ctx[packet->stream_index]); - codec_ctx[packet->stream_index] = nullptr; - } - } - media_lengths[packet->stream_index]++; - } else if (fmt_ctx_->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - AVFrame* swr_frame = av_frame_alloc(); - swr_frame->channel_layout = temp_frame->channel_layout; - swr_frame->sample_rate = temp_frame->sample_rate; - swr_frame->format = AV_SAMPLE_FMT_U8P; - - swr_ctx = swr_alloc_set_opts( - nullptr, - temp_frame->channel_layout, - static_cast(swr_frame->format), - temp_frame->sample_rate, - temp_frame->channel_layout, - static_cast(temp_frame->format), - temp_frame->sample_rate, - 0, - nullptr - ); - - swr_init(swr_ctx); - - swr_convert_frame(swr_ctx, swr_frame, temp_frame); - - // `config.waveform_resolution` determines how many samples per second are stored in waveform. - // `sample_rate` is samples per second, so `interval` is how many samples are averaged in - // each "point" of the waveform - int interval = qFloor((temp_frame->sample_rate/olive::config.waveform_resolution)/4)*4; - - // get the amount of bytes in an audio sample - int sample_size = av_get_bytes_per_sample(static_cast(swr_frame->format)); - - // total amount of data in this frame - int nb_bytes = swr_frame->nb_samples * sample_size; - - // loop through entire frame - for (int i=0;ichannels;j++) { - qint8& min = waveform_cache_data[packet->stream_index][j][0]; - qint8& max = waveform_cache_data[packet->stream_index][j][1]; - - s->audio_preview.append(min); - s->audio_preview.append(max); - } - - waveform_cache_count = 0; - } - - // standard processing for each channel of information - for (int j=0;jchannels;j++) { - qint8& min = waveform_cache_data[packet->stream_index][j][0]; - qint8& max = waveform_cache_data[packet->stream_index][j][1]; - - // if we're starting over, reset cache to zero - if (waveform_cache_count == 0) { - min = 0; - max = 0; - } - - // Convert unsigned 8-bit PCM sample to signed - qint8 sample = qint8(int(swr_frame->data[j][i]-128)); - - // Store most minimum and most maximum samples of this interval - min = qMin(min, sample); - max = qMax(max, sample); - } - - waveform_cache_count++; - - if (cancelled_) { - break; - } - } - - swr_free(&swr_ctx); - av_frame_free(&swr_frame); - - if (cancelled_) { - end_of_file = true; - break; - } - } - } - - // check if we've got all our previews - if (retrieve_duration_) { - done = false; - } else if (footage_->audio_tracks.size() == 0) { - done = true; - for (int i=0;ivideo_tracks.size();i++) { - if (!footage_->video_tracks.at(i).preview_done) { - done = false; - break; - } - } - if (done) { - end_of_file = true; - break; - } - } - av_packet_unref(packet); - } - } - - av_frame_free(&temp_frame); - av_packet_free(&packet); - - for (unsigned int i=0;inb_streams;i++) { - if (waveform_cache_data[i] != nullptr) { - for (int j=0;jchannels;j++) { - delete [] waveform_cache_data[i][j]; - } - delete [] waveform_cache_data[i]; - } - - if (codec_ctx[i] != nullptr) { - avcodec_close(codec_ctx[i]); - avcodec_free_context(&codec_ctx[i]); - } - } - - // by this point, we'll have made all audio waveform previews - for (int i=0;iaudio_tracks.size();i++) { - footage_->audio_tracks[i].preview_done = true; - } - } - - if (retrieve_duration_) { - footage_->length = 0; - unsigned int maximum_stream = 0; - for (unsigned int i=0;inb_streams;i++) { - if (media_lengths[i] > media_lengths[maximum_stream]) { - maximum_stream = i; - } - } - - // FIXME: length is currently retrieved as a frame count rather than a timestamp - footage_->length = qRound(double(media_lengths[maximum_stream]) / av_q2d(fmt_ctx_->streams[maximum_stream]->avg_frame_rate) * AV_TIME_BASE); - - finalize_media(); - } - - delete [] waveform_cache_data; - delete [] media_lengths; - delete [] codec_ctx; -} - -QString PreviewGenerator::get_thumbnail_path(const QString& hash, const FootageStream& ms) { - return data_dir_.filePath(QString("%1t%2").arg(hash, QString::number(ms.file_index))); -} - -QString PreviewGenerator::get_waveform_path(const QString& hash, const FootageStream& ms) { - return data_dir_.filePath(QString("%1w%2").arg(hash, QString::number(ms.file_index))); -} - -void PreviewGenerator::run() { - Q_ASSERT(footage_ != nullptr); - Q_ASSERT(media_ != nullptr); - - const QString url = footage_->url; - QByteArray ba = url.toUtf8(); - char* filename = new char[ba.size()+1]; - strcpy(filename, ba.data()); - - QString errorStr; - bool error = false; - - AVDictionary* format_opts = nullptr; - - // for image sequences that don't start at 0, set the index where it does start - if (footage_->start_number > 0) { - av_dict_set(&format_opts, "start_number", QString::number(footage_->start_number).toUtf8(), 0); - } - - int errCode = avformat_open_input(&fmt_ctx_, filename, nullptr, &format_opts); - if(errCode != 0) { - char err[1024]; - av_strerror(errCode, err, 1024); - errorStr = tr("Could not open file - %1").arg(err); - error = true; - } else { - errCode = avformat_find_stream_info(fmt_ctx_, nullptr); - if (errCode < 0) { - char err[1024]; - av_strerror(errCode, err, 1024); - errorStr = tr("Could not find stream information - %1").arg(err); - error = true; - } else { - av_dump_format(fmt_ctx_, 0, filename, 0); - parse_media(); - - // see if we already have data for this - QString hash = get_file_hash(footage_->url); - - if (retrieve_preview(hash)) { - sem.acquire(); - - if (!cancelled_) { - generate_waveform(); - - if (!cancelled_) { - // save preview to file - for (int i=0;ivideo_tracks.size();i++) { - FootageStream& ms = footage_->video_tracks[i]; - ms.video_preview.save(get_thumbnail_path(hash, ms), "PNG"); - //dout << "saved" << ms->file_index << "thumbnail to" << get_thumbnail_path(hash, ms); - } - for (int i=0;iaudio_tracks.size();i++) { - FootageStream& ms = footage_->audio_tracks[i]; - QFile f(get_waveform_path(hash, ms)); - f.open(QFile::WriteOnly); - f.write(reinterpret_cast(ms.audio_preview.constData()), ms.audio_preview.size()); - f.close(); - //dout << "saved" << ms->file_index << "waveform to" << get_waveform_path(hash, ms); - } - } - } - - sem.release(); - } - } - avformat_close_input(&fmt_ctx_); - } - - if (!cancelled_) { - if (error) { - invalidate_media(errorStr); - } - } - - delete [] filename; - footage_->preview_gen = nullptr; -} - -void PreviewGenerator::cancel() { - cancelled_ = true; - wait(); -} - -void PreviewGenerator::AnalyzeMedia(Media *m) -{ - // PreviewGenerator's constructor starts the thread, sets a reference of itself as the media's generator, - // and connects its thread completion to its own deletion, therefore handling its own memory. Nothing else needs to - // be done. - new PreviewGenerator(m); -} diff --git a/project/previewgenerator.h b/project/previewgenerator.h deleted file mode 100644 index b2c401b22..000000000 --- a/project/previewgenerator.h +++ /dev/null @@ -1,65 +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 PREVIEWGENERATOR_H -#define PREVIEWGENERATOR_H - -#include -#include -#include - -#include "project/footage.h" -#include "project/media.h" - -extern "C" { -#include -#include -#include -#include -} - -class PreviewGenerator : public QThread -{ - Q_OBJECT -public: - PreviewGenerator(Media*); - void run(); - void cancel(); - - static void AnalyzeMedia(Media*); -private: - void parse_media(); - bool retrieve_preview(const QString &hash); - void generate_waveform(); - void finalize_media(); - void invalidate_media(const QString& error_msg); - QString get_thumbnail_path(const QString &hash, const FootageStream &ms); - QString get_waveform_path(const QString& hash, const FootageStream &ms); - - AVFormatContext* fmt_ctx_; - Media* media_; - Footage* footage_; - bool retrieve_duration_; - bool contains_still_image_; - bool cancelled_; - QDir data_dir_; -}; - -#endif // PREVIEWGENERATOR_H diff --git a/project/projectelements.h b/project/projectelements.h deleted file mode 100644 index 3b17f454f..000000000 --- a/project/projectelements.h +++ /dev/null @@ -1,34 +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 PROJECTELEMENTS_H -#define PROJECTELEMENTS_H - -/** - - Simple header to include all classes used for an Olive project file - - */ - -// includes elements the user can use in a project -#include "media.h" -#include "footage.h" - -#endif // PROJECTELEMENTS_H diff --git a/project/projectfilter.cpp b/project/projectfilter.cpp deleted file mode 100644 index 2f0c33008..000000000 --- a/project/projectfilter.cpp +++ /dev/null @@ -1,84 +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 "projectfilter.h" - -#include "project/media.h" -#include "timeline/sequence.h" - -#include - -ProjectFilter::ProjectFilter(QObject *parent) : - QSortFilterProxyModel(parent), - show_sequences(true) -{} - -bool ProjectFilter::get_show_sequences() { - return show_sequences; -} - -void ProjectFilter::set_show_sequences(bool b) { - show_sequences = b; - invalidateFilter(); -} - -void ProjectFilter::update_search_filter(const QString &s) { - search_filter = s; - invalidateFilter(); -} - -bool ProjectFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { - // retrieve media object from index - QModelIndex index = sourceModel()->index(source_row, 0, source_parent); - Media* media = static_cast(index.internalPointer()); - - // hide sequences if show_sequences is false - if (!show_sequences) { - if (media != nullptr && media->get_type() == MEDIA_TYPE_SEQUENCE) { - return false; - } - } - - // filter by search filter string - if (!search_filter.isEmpty()) { - // search markers if media is a sequene - bool marker_contains_search = false; - - if (media->get_type() == MEDIA_TYPE_SEQUENCE - || media->get_type() == MEDIA_TYPE_FOOTAGE) { - QVector& markers = media->get_markers(); - for (int i=0;iget_type() != MEDIA_TYPE_FOLDER - && !media->get_name().contains(search_filter, Qt::CaseInsensitive)) { - return false; - } - } - - return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); -} diff --git a/project/projectfilter.h b/project/projectfilter.h deleted file mode 100644 index b5f633de6..000000000 --- a/project/projectfilter.h +++ /dev/null @@ -1,57 +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 PROJECTFILTER_H -#define PROJECTFILTER_H - -#include - -class ProjectFilter : public QSortFilterProxyModel { - Q_OBJECT -public: - ProjectFilter(QObject *parent = nullptr); - - // are sequences visible - bool get_show_sequences(); - -public slots: - - // set whether sequences are visible - void set_show_sequences(bool b); - - // update search filter - void update_search_filter(const QString& s); - -protected: - - // function that filters whether rows are displayed or not - virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; - -private: - - // internal variable for whether to show sequences - bool show_sequences; - - // search filter variable - QString search_filter; - -}; - -#endif // PROJECTFILTER_H diff --git a/project/projectfunctions.cpp b/project/projectfunctions.cpp deleted file mode 100644 index 27e62e031..000000000 --- a/project/projectfunctions.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "projectfunctions.h" - -#include "projectmodel.h" -#include "global/config.h" - -MediaPtr olive::project::CreateFolder(QString name) { - - MediaPtr item = std::make_shared(); - - item->set_folder(); - item->set_name(name); - - return item; - -} - -SequencePtr olive::project::CreateSequenceFromMedia(QVector &media_list) -{ - SequencePtr s = std::make_shared(); - - s->set_name(olive::project_model.GetNextSequenceName()); - - // Retrieve default Sequence settings from Config - s->set_width(olive::config.default_sequence_width); - s->set_height(olive::config.default_sequence_height); - s->set_frame_rate(olive::config.default_sequence_framerate); - s->set_audio_frequency(olive::config.default_sequence_audio_frequency); - s->set_audio_layout(olive::config.default_sequence_audio_channel_layout); - - bool got_video_values = false; - bool got_audio_values = false; - for (int i=0;iget_type()) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* m = media->to_footage(); - if (m->ready) { - if (!got_video_values) { - for (int j=0;jvideo_tracks.size();j++) { - const FootageStream& ms = m->video_tracks.at(j); - s->set_width(ms.video_width); - s->set_height(ms.video_height); - if (!qFuzzyCompare(ms.video_frame_rate, 0.0)) { - s->set_frame_rate(ms.video_frame_rate * m->speed); - - if (ms.video_interlacing != VIDEO_PROGRESSIVE) s->set_frame_rate(s->frame_rate() * 2); - - // only break with a decent frame rate, otherwise there may be a better candidate - got_video_values = true; - break; - } - } - } - if (!got_audio_values && m->audio_tracks.size() > 0) { - const FootageStream& ms = m->audio_tracks.at(0); - s->set_audio_frequency(ms.audio_frequency); - got_audio_values = true; - } - } - } - break; - case MEDIA_TYPE_SEQUENCE: - { - // Clone all attributes of the original sequence (seq) into the new one (s) - Sequence* seq = media->to_sequence().get(); - - s->set_width(seq->width()); - s->set_height(seq->height()); - s->set_frame_rate(seq->frame_rate()); - s->set_audio_frequency(seq->audio_frequency()); - s->set_audio_layout(seq->audio_layout()); - - got_video_values = true; - got_audio_values = true; - } - break; - } - if (got_video_values && got_audio_values) break; - } - - return s; -} diff --git a/project/projectfunctions.h b/project/projectfunctions.h deleted file mode 100644 index 1c62d8f24..000000000 --- a/project/projectfunctions.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PROJECTFUNCTIONS_H -#define PROJECTFUNCTIONS_H - -#include "project/media.h" -#include "timeline/sequence.h" -#include "timeline/mediaimportdata.h" - -namespace olive { -namespace project { - -MediaPtr CreateFolder(QString name); - -SequencePtr CreateSequenceFromMedia(QVector &media_list); - -} -} - -#endif // PROJECTFUNCTIONS_H diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp deleted file mode 100644 index 234abf6be..000000000 --- a/project/projectmodel.cpp +++ /dev/null @@ -1,661 +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 "projectmodel.h" - -#include - -#include "panels/panels.h" -#include "panels/viewer.h" -#include "ui/viewerwidget.h" -#include "ui/mainwindow.h" -#include "project/media.h" -#include "global/debug.h" -#include "global/config.h" -#include "global/global.h" -#include "projectfunctions.h" -#include "previewgenerator.h" - -ProjectModel olive::project_model; - -ProjectModel::ProjectModel(QObject *parent) : QAbstractItemModel(parent), root_item_(nullptr) { - make_root(); -} - -ProjectModel::~ProjectModel() { - destroy_root(); -} - -int ProjectModel::PrepareToSave() -{ - int element_count = 0; - - PrepareToSaveInternal(element_count, get_root()); - - return element_count; -} - -void ProjectModel::PrepareToSaveInternal(int& element_count, Media *root) -{ - for (int i=0;ichildCount();i++) { - Media* child = root->child(i); - - switch (child->get_type()) { - case MEDIA_TYPE_FOLDER: - child->temp_id = element_count; - break; - case MEDIA_TYPE_FOOTAGE: - child->to_footage()->save_id = element_count; - break; - case MEDIA_TYPE_SEQUENCE: - child->to_sequence()->save_id = element_count; - break; - } - - element_count++; - - if (child->childCount() > 0) { - PrepareToSaveInternal(element_count, child); - } - } -} - -void ProjectModel::Save(QXmlStreamWriter &stream, Media* root) -{ - if (root == nullptr) { - root = get_root(); - } - - for (int i=0;ichildCount();i++) { - Media* child = root->child(i); - - child->Save(stream); - - if (child->childCount() > 0) { - Save(stream, child); - } - } -} - -void ProjectModel::make_root() { - root_item_ = std::make_shared(); - root_item_->temp_id = 0; - root_item_->root = true; -} - -void ProjectModel::destroy_root() { - if (panel_sequence_viewer != nullptr) { - panel_sequence_viewer->set_media(nullptr); - } - if (panel_footage_viewer != nullptr) { - panel_footage_viewer->set_media(nullptr); - } - - root_item_ = nullptr; -} - -void ProjectModel::clear() { - beginResetModel(); - destroy_root(); - make_root(); - endResetModel(); -} - -Media *ProjectModel::get_root() const { - return root_item_.get(); -} - -QVariant ProjectModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) - return QVariant(); - - Media* media = static_cast(index.internalPointer()); - - return media->data(index.column(), role); -} - -Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const { - if (!index.isValid()) - return Qt::ItemIsDropEnabled; - - return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable; -} - -QVariant ProjectModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return root_item_->data(section, role); - - return QVariant(); -} - -QModelIndex ProjectModel::index(int row, int column, const QModelIndex &parent) const { - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - Media *parentItem; - - if (!parent.isValid()) { - parentItem = get_root(); - } else { - parentItem = static_cast(parent.internalPointer()); - } - - Media *childItem = parentItem->child(row); - if (childItem) { - return createIndex(row, column, childItem); - } else { - return QModelIndex(); - } -} - -QModelIndex ProjectModel::create_index(int arow, int acolumn, void* adata) { - return createIndex(arow, acolumn, adata); -} - -QModelIndex ProjectModel::parent(const QModelIndex &index) const { - if (!index.isValid()) - return QModelIndex(); - - Media *childItem = static_cast(index.internalPointer()); - Media *parentItem = childItem->parentItem(); - - if (parentItem == get_root()) - return QModelIndex(); - - return createIndex(parentItem->row(), 0, parentItem); -} - -bool ProjectModel::canFetchMore(const QModelIndex &parent) const -{ - - // Mostly implementing this because QSortFilterProxyModel will actually *ignore* a "true" result from hasChildren() - // and then query this value for a "true" result. So we need to override both this and hasChildren() to show a - // persistent childIndicator for folder items. - - if (parent.isValid() - && static_cast(parent.internalPointer())->get_type() == MEDIA_TYPE_FOLDER) { - return true; - } - return QAbstractItemModel::canFetchMore(parent); -} - -bool ProjectModel::hasChildren(const QModelIndex &parent) const -{ - if (parent.isValid() - && static_cast(parent.internalPointer())->get_type() == MEDIA_TYPE_FOLDER) { - return true; - } - return QAbstractItemModel::hasChildren(parent); -} - -bool ProjectModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (role != Qt::EditRole) - return false; - - Media *item = static_cast(index.internalPointer()); - bool result = item->setData(index.column(), value); - - if (result) - emit dataChanged(index, index); - - return result; -} - -int ProjectModel::rowCount(const QModelIndex &parent) const { - Media *parentItem; - if (parent.column() > 0) - return 0; - - if (!parent.isValid()) { - parentItem = get_root(); - } else { - parentItem = static_cast(parent.internalPointer()); - } - - return parentItem->childCount(); -} - -int ProjectModel::columnCount(const QModelIndex &parent) const { - if (parent.isValid()) - return static_cast(parent.internalPointer())->columnCount(); - else - return root_item_->columnCount(); -} - -Media *ProjectModel::getItem(const QModelIndex &index) const { - if (index.isValid()) { - Media *item = static_cast(index.internalPointer()); - if (item) - return item; - } - return get_root(); -} - -void ProjectModel::set_icon(Media* m, const QIcon &ico) { - QModelIndex index = createIndex(m->row(), 0, m); - m->set_icon(ico); - emit dataChanged(index, index); -} - -QVector ProjectModel::GetAllSequences() -{ - return GetAllMediaOfType(MEDIA_TYPE_SEQUENCE); -} - -QVector ProjectModel::GetAllFootage() -{ - return GetAllMediaOfType(MEDIA_TYPE_FOOTAGE); -} - -QVector ProjectModel::GetAllFolders() -{ - return GetAllMediaOfType(MEDIA_TYPE_FOLDER); -} - -QString ProjectModel::GetNextSequenceName(QString prepend) -{ - if (prepend.isEmpty()) { - prepend = tr("Sequence %1"); - } - - int sequence_number = 1; - QString test; - QVector all_sequences = GetAllSequences(); - bool found; - - do { - found = false; - test = prepend.arg(sequence_number); - for (int i=0;iget_name() == test) { - found = true; - sequence_number++; - break; - } - } - } while (found); - - return test; -} - -MediaPtr ProjectModel::CreateSequence(ComboAction *ca, SequencePtr s, bool open, Media *parent) -{ - MediaPtr item = std::make_shared(); - item->set_sequence(s); - - if (ca != nullptr) { - - ca->append(new AddMediaCommand(item, parent)); - - } else { - - appendChild(parent, item); - - } - - if (open) { - Timeline::OpenSequence(s); - } - - return item; -} - -QVector ProjectModel::GetAllMediaOfType(int search_type) -{ - QVector media_list; - RecurseTree(root_item_.get(), media_list, search_type); - return media_list; -} - -void ProjectModel::RecurseTree(Media* parent, QVector& list, int search_type) -{ - for (int i=0;ichildCount();i++) { - - Media* child = parent->child(i); - - if (child->get_type() == search_type) { - list.append(child); - } - - if (child->childCount() > 0) { - RecurseTree(child, list, search_type); - } - } -} - -void ProjectModel::appendChild(Media* parent, MediaPtr child) { - QModelIndex row_start; - - if (parent == nullptr) { - - parent = get_root(); - row_start = QModelIndex(); - - } else { - - row_start = createIndex(parent->row(), 0, parent); - - } - - beginInsertRows(row_start, parent->childCount(), parent->childCount()); - parent->appendChild(child); - endInsertRows(); -} - -void ProjectModel::moveChild(MediaPtr child, Media *to) { - if (to == nullptr) { - to = get_root(); - } - - Media* from = child->parentItem(); - - beginMoveRows( - from == get_root() ? QModelIndex() : createIndex(from->row(), 0, from), - child->row(), - child->row(), - to == get_root() ? QModelIndex() : createIndex(to->row(), 0, to), - to->childCount() - ); - - from->removeChild(child->row()); - to->appendChild(child); - endMoveRows(); -} - -void ProjectModel::removeChild(Media* parent, Media* m) { - if (parent == nullptr) { - parent = get_root(); - } - beginRemoveRows(parent == get_root() ? - QModelIndex() : createIndex(parent->row(), 0, parent), m->row(), m->row()); - parent->removeChild(m->row()); - endRemoveRows(); -} - -Media* ProjectModel::child(int i, Media* parent) { - if (parent == nullptr) { - parent = get_root(); - } - return parent->child(i); -} - -int ProjectModel::childCount(Media *parent) { - if (parent == nullptr) { - parent = get_root(); - } - return parent->childCount(); -} - -void ProjectModel::process_file_list(QStringList& files, bool recursive, MediaPtr replace, Media* parent) { - bool imported = false; - - // retrieve the array of image formats from the user's configuration - QStringList image_sequence_formats = olive::config.img_seq_formats.split("|"); - - // a cache of image sequence formatted URLS to assist the user in importing image sequences - QVector image_sequence_urls; - QVector image_sequence_importassequence; - - if (!recursive) last_imported_media.clear(); - - bool create_undo_action = (!recursive && replace == nullptr); - ComboAction* ca = nullptr; - if (create_undo_action) ca = new ComboAction(); - - // Loop through received files - for (int i=0;iappend(new AddMediaCommand(folder, parent)); - } else { - appendChild(parent, folder); - } - - process_file_list(subdir_filenames, true, nullptr, folder.get()); - - imported = true; - - } else if (!files.at(i).isEmpty()) { - QString file = files.at(i); - - // Check if the user is importing an Olive project file - if (file.endsWith(".ove", Qt::CaseInsensitive)) { - - // This file is an Olive project file. Ask the user if they really want to import it. - if (QMessageBox::question(olive::MainWindow, - tr("Import a Project"), - tr("\"%1\" is an Olive project file. It will merge with this project. " - "Do you wish to continue?").arg(file), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - - // load the project without clearing the current one - olive::Global->ImportProject(file); - - } - - } else { - - // This file is NOT an Olive project file - - // Used later if this file is part of an already processed image sequence - bool skip = false; - - /* Heuristic to determine whether file is part of an image sequence */ - - // Firstly, we run a heuristic on whether this file is an image by checking its file extension - - bool file_is_an_image = false; - - // Get the string position of the extension in the filename - int lastcharindex = file.lastIndexOf("."); - - if (lastcharindex != -1 && lastcharindex > file.lastIndexOf('/')) { - - QString ext = file.mid(lastcharindex+1); - - // If the file extension is part of a predetermined list (from Config::img_seq_formats), we'll treat it - // as an image - if (image_sequence_formats.contains(ext, Qt::CaseInsensitive)) { - file_is_an_image = true; - } - - } else { - - // If we're here, the file has no extension, but we'll still check if its an image sequence just in case - lastcharindex = file.length(); - file_is_an_image = true; - - } - - // Some image sequence's don't start at "0", if it is indeed an image sequence, we'll use this variable - // later to determine where it does start - int start_number = 0; - - // Check if we passed the earlier heuristic to check whether this is a file, and whether the last number in - // the filename (before the extension) is a number - if (file_is_an_image && file[lastcharindex-1].isDigit()) { - - // Check how many digits are at the end of this filename - int digit_count = 0; - int digit_test = lastcharindex-1; - while (file[digit_test].isDigit()) { - digit_count++; - digit_test--; - } - - // Retrieve the integer represented at the end of this filename - digit_test++; - int file_number = file.mid(digit_test, digit_count).toInt(); - - // Check whether a file exists with the same format but one number higher or one number lower - if (QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number-1, digit_count, 10, QChar('0')) + file.mid(lastcharindex))) - || QFileInfo::exists(QString(file.left(digit_test) + QString("%1").arg(file_number+1, digit_count, 10, QChar('0')) + file.mid(lastcharindex)))) { - - // - // If so, it certainly looks like it *could* be an image sequence, but we'll ask the user just in case - // - - // Firstly we should check if this file is part of a sequence the user has already confirmed as either a - // sequence or not a sequence (e.g. if the user happened to select a bunch of images that happen to increase - // consecutively). We format the filename with FFmpeg's '%Nd' (N = digits) formatting for reading image - // sequences - QString new_filename = file.left(digit_test) + "%" + QString::number(digit_count) + "d" + file.mid(lastcharindex); - - int does_url_cache_already_contain_this = image_sequence_urls.indexOf(new_filename); - - if (does_url_cache_already_contain_this > -1) { - - // We've already processed an image with the same formatting - - // Check if the last time we saw this formatting, the user chose to import as a sequence - if (image_sequence_importassequence.at(does_url_cache_already_contain_this)) { - - // If so, no need to import this file too, so we signal to the rest of the function to skip this file - skip = true; - - } - - // If not, we can fall-through to the next step which is importing normally - - } else { - - // If we're here, we've never seen a file with this formatting before, so we'll ask whether to import - // as a sequence or not - - // Add this file formatting file to the URL cache - image_sequence_urls.append(new_filename); - - // This does look like an image sequence, let's ask the user if it'll indeed be an image sequence - if (QMessageBox::question(olive::MainWindow, - tr("Image sequence detected"), - tr("The file '%1' appears to be part of an image sequence. " - "Would you like to import it as such?").arg(file), - QMessageBox::Yes | QMessageBox::No, - QMessageBox::Yes) == QMessageBox::Yes) { - - // Proceed to the next step of this with the formatted filename - file = new_filename; - - // Cache the user's answer alongside the image_sequence_urls value - in this case, YES, this will be an - // image sequence - image_sequence_importassequence.append(true); - - - // FFmpeg needs to know what file number to start at in the sequence. In case the image sequence doesn't - // start at a zero, we'll loop decreasing the number until it doesn't exist anymore - QString test_filename_format = QString("%1%2%3").arg(file.left(digit_test), "%1", file.mid(lastcharindex)); - int test_file_number = file_number; - do { - test_file_number--; - } while (QFileInfo::exists(test_filename_format.arg(QString("%1").arg(test_file_number, digit_count, 10, QChar('0'))))); - - // set the image sequence's start number to the last that existed - start_number = test_file_number + 1; - - } else { - - // Cache the user's response to the image sequence question - i.e. none of the files imported with this - // formatting should be imported as an image sequence - image_sequence_importassequence.append(false); - - } - } - - } - - } - - // If we're not skipping this file, let's import it - if (!skip) { - MediaPtr item; - FootagePtr m; - - if (replace != nullptr) { - item = replace; - } else { - item = std::make_shared(); - } - - m = std::make_shared(); - - // Edge case for PNGs that standardized unassociated alpha - if (file.endsWith("png", Qt::CaseInsensitive)) { - m->alpha_is_associated = false; - } - - m->using_inout = false; - m->url = file; - m->name = QFileInfo(files.at(i)).fileName(); - m->start_number = start_number; - - item->set_footage(m); - - last_imported_media.append(item.get()); - - if (replace == nullptr) { - if (create_undo_action) { - ca->append(new AddMediaCommand(item, parent)); - } else { - appendChild(parent, item); - } - } - - imported = true; - } - - } - - - } - } - if (create_undo_action) { - if (imported) { - olive::undo_stack.push(ca); - - for (int i=0;i ProjectModel::GetLastImportedMedia() -{ - return last_imported_media; -} diff --git a/project/projectmodel.h b/project/projectmodel.h deleted file mode 100644 index d9c0f4311..000000000 --- a/project/projectmodel.h +++ /dev/null @@ -1,132 +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 PROJECTMODEL_H -#define PROJECTMODEL_H - -#include - -#include "project/media.h" -#include "undo/comboaction.h" - -class ProjectModel : public QAbstractItemModel -{ - Q_OBJECT -public: - ProjectModel(QObject* parent = nullptr); - ~ProjectModel() override; - - /** - * @brief Makes preparations for saving the project file. - * - * Some items require IDs to link between them (e.g. the Footage or Nested Sequences used by Clips, linked clips, - * etc). This function sets up those IDs before saving. - * - * NOTE: This function should **always** be called before Save(). - * - * @return - * - * A count of the elements in the project to save into the project file. The loading system can later use this value - * to determine the load progress. - */ - int PrepareToSave(); - - /** - * @brief Initiate a save of all the project data - * - * Recursively goes through the entire project tree saving everything to a specified QXmlStreamWriter object. - * - * It's not recommended to use this function directly as it expects an existing QXmlStreamWriter and doesn't write a - * header and footer for the resulting XML document. Instead use olive::Save(). - * - * NOTE: **Always** call PrepareToSave() just before calling this function to set up valid IDs for saving. - * - * @param stream - * - * A QXmlStreamWriter object. - * - * @param root - * - * Used for recursion, set to any child and called again whenever a child is found with children. If this is nullptr, - * this function will loop over the root item. - */ - void Save(QXmlStreamWriter& stream, Media *root = nullptr); - - void make_root(); - void destroy_root(); - void clear(); - Media* get_root() const; - QVariant data(const QModelIndex &index, int role) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const override; - QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const override; - QModelIndex create_index(int arow, int acolumn, void *adata); - QModelIndex parent(const QModelIndex &index) const override; - bool canFetchMore(const QModelIndex &parent) const override; - bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - Media* getItem(const QModelIndex &index) const; - - void appendChild(Media *parent, MediaPtr child); - void moveChild(MediaPtr child, Media* to); - void removeChild(Media* parent, Media* m); - Media* child(int i, Media* parent = nullptr); - int childCount(Media* parent = nullptr); - void set_icon(Media* m, const QIcon &ico); - - void process_file_list(QStringList& files, bool recursive = false, MediaPtr replace = nullptr, Media *parent = nullptr); - - /** - * @brief Get a list of the last imported media - * - * @return - * - * Returns a list of all the Media processed by the last call to process_file_list(). - */ - QVector GetLastImportedMedia(); - - QVector GetAllSequences(); - QVector GetAllFootage(); - QVector GetAllFolders(); - - QString GetNextSequenceName(QString prepend = QString()); - - MediaPtr CreateSequence(ComboAction *ca, SequencePtr s, bool open, Media* parent); - -private: - MediaPtr root_item_; - - QVector last_imported_media; - - QVector GetAllMediaOfType(int search_type); - void RecurseTree(Media* parent, QVector &list, int search_type); - - void PrepareToSaveInternal(int& element_count, Media* root); -}; - -namespace olive { -extern ProjectModel project_model; -} - -#endif // PROJECTMODEL_H diff --git a/project/proxygenerator.cpp b/project/proxygenerator.cpp deleted file mode 100644 index 57830019e..000000000 --- a/project/proxygenerator.cpp +++ /dev/null @@ -1,427 +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 "proxygenerator.h" - -extern "C" { -#include -#include -#include -} - -#include -#include -#include -#include -#include - -#include "global/path.h" -#include "project/previewgenerator.h" -#include "ui/mediaiconservice.h" -#include "ui/mainwindow.h" - -// TODO provide more codecs than just this one -enum AVCodecID temp_enc_codec = AV_CODEC_ID_PRORES; - -ProxyGenerator::ProxyGenerator() : cancelled(false) {} - -void ProxyGenerator::transcode(const ProxyInfo& info) { - Footage* footage = info.media->to_footage(); - - // set progress to 0 - current_progress = 0.0; - - // for image sequences that don't start at 0, set the index where it does start - AVDictionary* format_opts = nullptr; - if (footage->start_number > 0) { - av_dict_set(&format_opts, "start_number", QString::number(footage->start_number).toUtf8(), 0); - } - - // open input file - AVFormatContext* input_fmt_ctx = nullptr; - avformat_open_input(&input_fmt_ctx, footage->url.toUtf8(), nullptr, &format_opts); - - // open output file - AVFormatContext* output_fmt_ctx = nullptr; - avformat_alloc_output_context2(&output_fmt_ctx, nullptr, nullptr, info.path.toUtf8()); - - // open output file writing handle - avio_open(&output_fmt_ctx->pb, info.path.toUtf8(), AVIO_FLAG_WRITE); - - // get stream info from input file - avformat_find_stream_info(input_fmt_ctx, nullptr); - - // create array of input decoders - QVector input_streams; - input_streams.resize(input_fmt_ctx->nb_streams); - input_streams.fill(nullptr); - - // create array of output encoders - QVector output_streams; - output_streams.resize(input_fmt_ctx->nb_streams); - output_streams.fill(nullptr); - - // create array of swscale contexts for pixel format conversion - QVector sws_contexts; - sws_contexts.resize(input_fmt_ctx->nb_streams); - sws_contexts.fill(nullptr); - - // loop through file to find compatible video streams - for (int i=0;inb_streams);i++) { - AVStream* in_stream = input_fmt_ctx->streams[i]; - - // create new stream in output - AVStream* out_stream = avformat_new_stream(output_fmt_ctx, nullptr); - out_stream->id = in_stream->id; - - // find decoder for this codec - AVCodec* dec_codec = avcodec_find_decoder(in_stream->codecpar->codec_id); - - // find encoder for chosen proxy type - AVCodec* enc_codec = avcodec_find_encoder(temp_enc_codec); - - // we only transcode video streams, others we just passthrough - if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && dec_codec != nullptr) { - - // allocate decoding context for this stream - AVCodecContext* dec_ctx = avcodec_alloc_context3(dec_codec); - - // copy parameters from stream to decoding context - avcodec_parameters_to_context(dec_ctx, in_stream->codecpar); - - // open decoder - avcodec_open2(dec_ctx, dec_codec, nullptr); - - // store decoding context in array - input_streams[i] = dec_ctx; - - // retrieve more information about this stream - av_dump_format(input_fmt_ctx, i, footage->url.toUtf8(), 0); - - // allocate encoding context for this stream - AVCodecContext* enc_ctx = avcodec_alloc_context3(enc_codec); - - // copy properties from decoding context to encoding context - enc_ctx->codec_id = temp_enc_codec; - enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO; - enc_ctx->width = qFloor(dec_ctx->width*info.size_multiplier); - enc_ctx->height = qFloor(dec_ctx->height*info.size_multiplier); - enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; - enc_ctx->pix_fmt = avcodec_find_best_pix_fmt_of_list(enc_codec->pix_fmts, dec_ctx->pix_fmt, 1, nullptr); - enc_ctx->framerate = dec_ctx->framerate; - enc_ctx->time_base = in_stream->time_base; - out_stream->time_base = in_stream->time_base; - - // if format uses global headers, add flag to enc_ctx - if (output_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { - enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - } - - // set encoder options (mostly just multithreading) - AVDictionary* opts = nullptr; - av_dict_set(&opts, "threads", "auto", 0); - - // open encoder - avcodec_open2(enc_ctx, enc_codec, &opts); - - // copy parameters from encoding context to stream - avcodec_parameters_from_context(out_stream->codecpar, enc_ctx); - - // store encoding context in array - output_streams[i] = enc_ctx; - - // create swscontext for this stream - SwsContext* sws_ctx = sws_getContext( - in_stream->codecpar->width, - in_stream->codecpar->height, - static_cast(in_stream->codecpar->format), - enc_ctx->width, - enc_ctx->height, - enc_ctx->pix_fmt, - 0, - nullptr, - nullptr, - nullptr - ); - - sws_contexts[i] = sws_ctx; - } else { - avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar); - } - } - - // write video header - avformat_write_header(output_fmt_ctx, nullptr); - - // packet that av_read_frame will dump file packets into - AVPacket packet; - av_init_packet(&packet); - - // frame that decoder will decode into - AVFrame* dec_frame = av_frame_alloc(); - - // main transcoding loop - while (!skip) { - - // cache stream index - int stream_index = packet.stream_index; - - // retrieve frame from decoder (this will clear the last frame so we don't have to do that) - int read_ret = -1; - int recfr_ret = -1; - do { - // read from input file - read_ret = av_read_frame(input_fmt_ctx, &packet); - - // handle errors - if (read_ret < 0) { - - // AVERROR_EOF means we've simply reached the end of the file, otherwise this is an error - if (read_ret != AVERROR_EOF) { - qWarning() << "Proxy generation for file" << footage->url << "ended prematurely"; - } - - // either way, we shall abort reading - break; - } - - stream_index = packet.stream_index; - - // determine whether this frame is from a stream we're transcoding - if (input_streams.at(stream_index) == nullptr) { - // if we didn't allocate a decoder for this earlier, we just pass it through - - av_packet_rescale_ts(&packet, input_fmt_ctx->streams[stream_index]->time_base, output_fmt_ctx->streams[stream_index]->time_base); - - // write packet to output - av_interleaved_write_frame(output_fmt_ctx, &packet); - - } else { - // we're going to transcode this packet. - - // send packet to decoder - avcodec_send_packet(input_streams.at(stream_index), &packet); - - // use timestamp and stream duration to create a rough estimation of the progress through this file - current_progress = qCeil((double(packet.pts)/double(input_fmt_ctx->streams[packet.stream_index]->duration))*100); - - } - - // free packet allocated by av_read_frame - av_packet_unref(&packet); - } while ((recfr_ret = avcodec_receive_frame(input_streams.at(packet.stream_index), dec_frame)) == AVERROR(EAGAIN) && !skip); - - // error/eof handling - cancel while loop - if (read_ret < 0 || skip) { - break; - } - - // free packet as we're about to use it for encoding - av_packet_unref(&packet); - - // rescale input frame timestamp to output timestamp - dec_frame->pts = av_rescale_q(dec_frame->pts, - input_fmt_ctx->streams[stream_index]->time_base, - output_fmt_ctx->streams[stream_index]->time_base); - - // determine if the pix_fmt, width, and/or height is different, so if we need to convert - bool convert_pix_fmt = (output_streams.at(stream_index)->pix_fmt != input_streams.at(stream_index)->pix_fmt - || output_streams.at(stream_index)->width != input_streams.at(stream_index)->width - || output_streams.at(stream_index)->height != input_streams.at(stream_index)->height); - - // create reference to the frame to be sent to the encoder - AVFrame* enc_frame = dec_frame; - - if (convert_pix_fmt) { - // create sws frame for pixel format conversion - enc_frame = av_frame_alloc(); - enc_frame->width = output_streams.at(stream_index)->width; - enc_frame->height = output_streams.at(stream_index)->height; - enc_frame->format = output_streams.at(stream_index)->pix_fmt; - av_frame_get_buffer(enc_frame, 0); - - // convert pixel format to format expected by the encoder - sws_scale(sws_contexts.at(stream_index), dec_frame->data, dec_frame->linesize, 0, dec_frame->height, enc_frame->data, enc_frame->linesize); - - // set same pts as dec_frame - enc_frame->pts = dec_frame->pts; - } - - // send frame to encoder - avcodec_send_frame(output_streams.at(stream_index), enc_frame); - - if (convert_pix_fmt) { - // free sws frame since we made one before - av_frame_free(&enc_frame); - } - - // return value for packet receiving - int recret; - - // loop through receiving packets - while ((recret = avcodec_receive_packet(output_streams.at(stream_index), &packet)) >= 0 && !skip) { - - // set packet stream index to current stream index - packet.stream_index = stream_index; - - // write frame to file - av_interleaved_write_frame(output_fmt_ctx, &packet); - - // unref old packet - av_packet_unref(&packet); - - } - - } - - // free dec_frame - av_frame_free(&dec_frame); - - // write video trailer - av_write_trailer(output_fmt_ctx); - - // free stream contexts - for (int i=0;inb_streams);i++) { - if (input_streams[i] != nullptr) { - // free swscale contexts - sws_freeContext(sws_contexts[i]); - - // free input decoding context - avcodec_close(input_streams[i]); - avcodec_free_context(&input_streams[i]); - - // free output encoding context - avcodec_close(output_streams[i]); - avcodec_free_context(&output_streams[i]); - } - } - - // close output file handle - avio_closep(&output_fmt_ctx->pb); - - // close output file - avformat_free_context(output_fmt_ctx); - - // close input file - avformat_close_input(&input_fmt_ctx); - - // set footage to use newly generated proxy - footage->proxy = true; - footage->proxy_path = info.path; - - qInfo() << "Finished creating proxy for" << footage->url; - QMetaObject::invokeMethod(olive::MainWindow->statusBar(), - "showMessage", - Qt::QueuedConnection, - Q_ARG(QString, tr("Finished generating proxy for \"%1\"").arg(footage->url))); -} - -// main proxy generating loop -void ProxyGenerator::run() { - // mutex used for thread safe signalling - mutex.lock(); - - while (!cancelled) { - // wait for queue() to be called - waitCond.wait(&mutex); - - // quit thread if cancel() was called - if (cancelled) break; - - // loop through queue until the queue is empty - while (proxy_queue.size() > 0) { - - // grab proxy info - const ProxyInfo& info = proxy_queue.first(); - - // create directory for info - QFileInfo(info.path).dir().mkpath("."); - - // set skip to false - skip = false; - - // set media icon to animated loading icon - olive::media_icon_service->SetMediaIcon(info.media, ICON_TYPE_LOADING); - - // transcode proxy - transcode(info); - - // set media icon back to video - olive::media_icon_service->SetMediaIcon(info.media, ICON_TYPE_VIDEO); - - // we're finished with this proxy, remove it - proxy_queue.removeFirst(); - - // quit loop if cancel() was called - if (cancelled) break; - - } - } - - mutex.unlock(); -} - -// called to add footage to generate proxies for -void ProxyGenerator::queue(const ProxyInfo &info) { - // remove any queued proxies with the same footage - if (!proxy_queue.isEmpty() - && proxy_queue.first().media == info.media) { - // if the thread is currently processing a proxy with the same footage, abort it - skip = true; - } - - // scan through the rest of the queue for another proxy with the same footage (start with 1 since we already processed first()) - for (int i=1;i. - -***/ - -#ifndef PROXYGENERATOR_H -#define PROXYGENERATOR_H - -#include -#include -#include -#include - -#include "project/media.h" - -struct ProxyInfo { - Media* media; - double size_multiplier; - int codec_type; - QString path; -}; - -class ProxyGenerator : public QThread { - Q_OBJECT -public: - ProxyGenerator(); - void run(); - void queue(const ProxyInfo& info); - void cancel(); - double get_proxy_progress(Media *f); -private: - // queue of footage to process proxies for - QVector proxy_queue; - - // threading objects - QWaitCondition waitCond; - QMutex mutex; - - // set to true if you want to permanently close ProxyGenerator - bool cancelled; - - // set to true if you want to abort the footage currently being processed - bool skip; - - // stores progress in percent of proxy currently being processed - double current_progress; - - // function that performs the actual transcode - void transcode(const ProxyInfo& info); -}; - -namespace olive { - // proxy generator is a global omnipotent entity - extern ProxyGenerator proxy_generator; -} - -#endif // PROXYGENERATOR_H diff --git a/project/savethread.cpp b/project/savethread.cpp deleted file mode 100644 index 380f03be1..000000000 --- a/project/savethread.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "savethread.h" - -#include -#include -#include -#include - -#include "global/global.h" -#include "global/config.h" -#include "projectmodel.h" - -/* -void RecursiveSave() { - -} - -void save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) { - for (int i=0;iget_type()) { - if (m->get_type() == MEDIA_TYPE_FOLDER) { - if (set_ids_only) { - m->temp_id = folder_id; // saves a temporary ID for matching in the project file - folder_id++; - } else { - // if we're saving folders, save the folder - stream.writeStartElement("folder"); - stream.writeAttribute("name", m->get_name()); - stream.writeAttribute("id", QString::number(m->temp_id)); - if (!item.parent().isValid()) { - stream.writeAttribute("parent", "0"); - } else { - stream.writeAttribute("parent", QString::number(olive::project_model.getItem(item.parent())->temp_id)); - } - stream.writeEndElement(); - } - // save_folder(stream, item, type, set_ids_only); - } else { - int folder = m->parentItem()->temp_id; - if (type == MEDIA_TYPE_FOOTAGE) { - - } else if (type == MEDIA_TYPE_SEQUENCE) { - Sequence* s = m->to_sequence().get(); - if (set_ids_only) { - s->save_id = sequence_id; - sequence_id++; - } else { - s->Save(stream); - } - } - } - } - - if (m->get_type() == MEDIA_TYPE_FOLDER) { - save_folder(stream, type, set_ids_only, item); - } - } -} -*/ - -void olive::Save(bool autorecovery) -{ - QFile file(autorecovery ? olive::Global->get_autorecovery_filename() : olive::ActiveProjectFilename); - if (!file.open(QIODevice::WriteOnly)) { - qCritical() << "Could not open file"; - return; - } - - QXmlStreamWriter stream(&file); - stream.setAutoFormatting(true); - stream.writeStartDocument(); // doc - - stream.writeStartElement("project"); // project - - stream.writeTextElement("version", QString::number(olive::kSaveVersion)); - - stream.writeTextElement("url", olive::ActiveProjectFilename); - - // Prepare project for saving and retrieve element count - int element_count = olive::project_model.PrepareToSave(); - - // Write element count to file - used by the loading thread to determine its loading progress - stream.writeTextElement("elements", QString::number(element_count)); - - olive::project_model.Save(stream); - - stream.writeEndElement(); // project - - stream.writeEndDocument(); // doc - - file.close(); - - if (!autorecovery) { - olive::Global->add_recent_project(olive::ActiveProjectFilename); - olive::Global->set_modified(false); - } -} diff --git a/project/savethread.h b/project/savethread.h deleted file mode 100644 index 0687defd5..000000000 --- a/project/savethread.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SAVETHREAD_H -#define SAVETHREAD_H - -namespace olive { -void Save(bool autorecovery); -} - -#endif // SAVETHREAD_H diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp deleted file mode 100644 index 433a007c3..000000000 --- a/project/sourcescommon.cpp +++ /dev/null @@ -1,466 +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 "sourcescommon.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "ui/menuhelper.h" -#include "panels/panels.h" -#include "project/media.h" -#include "undo/undo.h" -#include "rendering/renderfunctions.h" -#include "panels/timeline.h" -#include "panels/project.h" -#include "project/footage.h" -#include "panels/viewer.h" -#include "project/projectfilter.h" -#include "timeline/sequence.h" -#include "global/config.h" -#include "global/global.h" -#include "dialogs/proxydialog.h" -#include "ui/viewerwidget.h" -#include "project/proxygenerator.h" -#include "project/projectfunctions.h" -#include "ui/mainwindow.h" -#include "ui/menu.h" -#include "undo/undostack.h" - -SourcesCommon::SourcesCommon(Project* parent, ProjectFilter &sort_filter) : - editing_item(nullptr), - project_parent(parent), - sort_filter_(sort_filter) -{ - 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_list; - for (int i=0;iitem_to_media(selected_items.at(i))); - } - - ComboAction* ca = new ComboAction(); - SequencePtr s = olive::project::CreateSequenceFromMedia(media_list); - - // add clips to it - s->AddClipsFromGhosts(ca, olive::timeline::CreateGhostsFromMedia(s.get(), 0, media_list)); - - olive::project_model.CreateSequence(ca, s, true, nullptr); - olive::undo_stack.push(ca); - } -} - -void SourcesCommon::show_context_menu(QWidget* parent, const QModelIndexList& items) { - Menu menu(parent); - - selected_items = items; - - QAction* import_action = menu.addAction(tr("Import...")); - QObject::connect(import_action, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(open_import_dialog())); - - Menu* new_menu = new Menu(tr("New")); - menu.addMenu(new_menu); - olive::MenuHelper.make_new_menu(new_menu); - - Menu* view_menu = new Menu(tr("View")); - menu.addMenu(view_menu); - - QAction* tree_view_action = view_menu->addAction(tr("Tree View")); - connect(tree_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_tree_view())); - - QAction* icon_view_action = view_menu->addAction(tr("Icon View")); - connect(icon_view_action, SIGNAL(triggered(bool)), project_parent, SLOT(set_icon_view())); - - QAction* toolbar_action = view_menu->addAction(tr("Show Toolbar")); - toolbar_action->setCheckable(true); - 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(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) { - Media* first_media = project_parent->item_to_media(items.at(0)); - - // replace footage - int type = first_media->get_type(); - if (type == MEDIA_TYPE_FOOTAGE) { - QAction* replace_action = menu.addAction(tr("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(tr("Reveal in Explorer")); -#elif defined(Q_OS_MAC) - QAction* reveal_in_explorer = menu.addAction(tr("Reveal in Finder")); -#else - QAction* reveal_in_explorer = menu.addAction(tr("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(tr("Replace Clips Using This Media")); - QObject::connect(replace_clip_media, SIGNAL(triggered(bool)), project_parent, SLOT(replace_clip_media())); - } - } - - // analyze selected footage types - bool all_sequences = true; - bool all_footage = true; - - cached_selected_footage.clear(); - for (int i=0;iitem_to_media(items.at(i)); - if (m->get_type() != MEDIA_TYPE_SEQUENCE) { - all_sequences = false; - } - if (m->get_type() == MEDIA_TYPE_FOOTAGE) { - cached_selected_footage.append(m); - } else { - all_footage = false; - } - } - - // create sequence from - QAction* create_seq_from = menu.addAction(tr("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(tr("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(tr("Delete All Clips Using This Media")); - QObject::connect(delete_footage_from_sequences, SIGNAL(triggered(bool)), project_parent, SLOT(delete_clips_using_selected_media())); - - Menu* proxies = new Menu(tr("Proxy")); - menu.addMenu(proxies); - - // special case if one footage item is selected and its proxy is currently being generated - if (cached_selected_footage.size() == 1 - && cached_selected_footage.at(0)->to_footage()->proxy - && cached_selected_footage.at(0)->to_footage()->proxy_path.isEmpty()) { - QAction* action = proxies->addAction(tr("Generating proxy: %1% complete").arg( - olive::proxy_generator.get_proxy_progress(cached_selected_footage.at(0)) - ) - ); - action->setEnabled(false); - } else { - // determine whether any selected footage has or doesn't have proxies - bool footage_without_proxies_exists = false; - bool footage_with_proxies_exists = false; - - for (int i=0;ito_footage()->proxy) { - footage_with_proxies_exists = true; - } else { - footage_without_proxies_exists = true; - } - } - - // if footage was selected WITHOUT proxies - if (footage_without_proxies_exists) { - QString create_proxy_text; - - if (footage_with_proxies_exists) { - // some of the footage already has proxies, so we use a different string - create_proxy_text = tr("Create/Modify Proxy"); - } else { - // none of the footage has proxies - create_proxy_text = tr("Create Proxy"); - } - - proxies->addAction(create_proxy_text, this, SLOT(open_create_proxy_dialog())); - } - - // if footage was selected WITH proxies - if (footage_with_proxies_exists) { - - if (!footage_without_proxies_exists) { - // if all the footage has proxies, we didn't make a "Create/Modify" above, so we create one here (but only "modify") - proxies->addAction(tr("Modify Proxy"), this, SLOT(open_create_proxy_dialog())); - } - - proxies->addAction(tr("Restore Original"), this, SLOT(clear_proxies_from_selected())); - } - } - } - - // delete media - QAction* delete_action = menu.addAction(tr("Delete")); - QObject::connect(delete_action, SIGNAL(triggered(bool)), project_parent, SLOT(delete_selected_media())); - - if (items.size() == 1) { - Media* media_item = project_parent->item_to_media(items.at(0)); - - if (media_item->get_type() != MEDIA_TYPE_FOLDER) { - QAction* preview_in_media_viewer_action = menu.addAction(tr("Preview in Media Viewer"), - this, - SLOT(OpenSelectedMediaInMediaViewerFromAction())); - preview_in_media_viewer_action->setData(reinterpret_cast(media_item)); - } - - QAction* properties_action = menu.addAction(tr("Properties...")); - QObject::connect(properties_action, SIGNAL(triggered(bool)), project_parent, SLOT(open_properties())); - } - } - - menu.exec(QCursor::pos()); -} - -void SourcesCommon::replace_media(MediaPtr item, QString filename) -{ - if (filename.isEmpty()) { - filename = QFileDialog::getOpenFileName( - olive::MainWindow, - tr("Replace '%1'").arg(item->get_name()), - "", - tr("All Files") + " (*)"); - } - if (!filename.isEmpty()) { - ReplaceMediaCommand* rmc = new ReplaceMediaCommand(item, filename); - olive::undo_stack.push(rmc); - } -} - -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(const QModelIndexList& selected_items) { - stop_rename_timer(); - if (selected_items.size() == 0) { - olive::Global->open_import_dialog(); - } else if (selected_items.size() == 1) { - Media* media = project_parent->item_to_media(selected_items.at(0)); - if (media->get_type() == MEDIA_TYPE_SEQUENCE) { - Timeline::OpenSequence(media->to_sequence()); - } else { - OpenSelectedMediaInMediaViewer(project_parent->item_to_media(selected_items.at(0))); - } - } -} - -void SourcesCommon::dropEvent(QWidget* parent, - QDropEvent *event, - const QModelIndex& drop_item, - const QModelIndexList& items) { - const QMimeData* mimeData = event->mimeData(); - MediaPtr m = project_parent->item_to_media_ptr(drop_item); - if (mimeData->hasUrls()) { - // drag files in from outside - QList urls = mimeData->urls(); - if (!urls.isEmpty()) { - QStringList paths; - for (int i=0;iget_type() == MEDIA_TYPE_FOOTAGE - && !QFileInfo(paths.at(0)).isDir() - && olive::config.drop_on_media_to_replace - && QMessageBox::question( - parent, - tr("Replace Media"), - tr("You dropped a file onto '%1'. Would you like to replace it with the dropped file?").arg(m->get_name()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { - replace = true; - 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(); - } - } - olive::project_model.process_file_list(paths, false, nullptr, project_parent->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() || m->get_type() == MEDIA_TYPE_FOLDER) { - QVector move_items; - for (int i=0;iitem_to_media_ptr(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 0) { - MediaMove* mm = new MediaMove(); - mm->to = m.get(); - mm->items = move_items; - olive::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 != nullptr) { - view->edit(editing_index); - } -} - -void SourcesCommon::item_renamed(Media* item) { - if (editing_item == item) { - MediaRename* mr = new MediaRename(item, "idk"); - olive::undo_stack.push(mr); - editing_item = nullptr; - } -} - -void SourcesCommon::OpenSelectedMediaInMediaViewerFromAction() -{ - OpenSelectedMediaInMediaViewer(reinterpret_cast(static_cast(sender())->data().value())); -} - -void SourcesCommon::OpenSelectedMediaInMediaViewer(Media* item) { - if (item->get_type() != MEDIA_TYPE_FOLDER) { - panel_footage_viewer->set_media(item); - panel_footage_viewer->setFocus(); - } -} - -void SourcesCommon::open_create_proxy_dialog() { - // open the proxy dialog and send it a list of currently selected footage - ProxyDialog pd(olive::MainWindow, cached_selected_footage); - pd.exec(); -} - -void SourcesCommon::clear_proxies_from_selected() { - QList delete_list; - - for (int i=0;ito_footage(); - - if (f->proxy && !f->proxy_path.isEmpty()) { - if (QFileInfo::exists(f->proxy_path)) { - if (QMessageBox::question(olive::MainWindow, - tr("Delete proxy"), - tr("Would you like to delete the proxy file \"%1\" as well?").arg(f->proxy_path), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - delete_list.append(f->proxy_path); - } - } - } - - f->proxy = false; - f->proxy_path.clear(); - } - - QVector all_sequences = olive::project_model.GetAllSequences(); - for (int i=0;ito_sequence()->Close(); - } - - // delete proxies requested to be deleted - for (int i=0;iseq != nullptr) { - // update viewer (will re-open active clips with original media) - panel_sequence_viewer->viewer_widget()->frame_update(); - } - - olive::Global->set_modified(true); -} diff --git a/project/sourcescommon.h b/project/sourcescommon.h deleted file mode 100644 index 06e572551..000000000 --- a/project/sourcescommon.h +++ /dev/null @@ -1,77 +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 SOURCESCOMMON_H -#define SOURCESCOMMON_H - -#include -#include -#include - -#include "project/footage.h" -#include "project/projectfilter.h" -#include "media.h" - -class Project; -class QMouseEvent; -class QAbstractItemView; -class QDropEvent; - -class SourcesCommon : public QObject { - Q_OBJECT -public: - SourcesCommon(Project *parent, ProjectFilter& sort_filter); - QAbstractItemView* view; - void show_context_menu(QWidget* parent, const QModelIndexList &items); - - void replace_media(MediaPtr item, QString filename); - - void mousePressEvent(QMouseEvent* e); - void mouseDoubleClickEvent(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); -public slots: - void stop_rename_timer(); -private slots: - void create_seq_from_selected(); - void reveal_in_browser(); - void rename_interval(); - void item_renamed(Media *item); - void OpenSelectedMediaInMediaViewerFromAction(); - void OpenSelectedMediaInMediaViewer(Media* item); - - // proxy functions - void open_create_proxy_dialog(); - void clear_proxies_from_selected(); -private: - Media* editing_item; - QModelIndex editing_index; - QModelIndexList selected_items; - Project* project_parent; - QTimer rename_timer; - - // we cache the selected footage items for open_create_proxy_dialog() - QVector cached_selected_footage; - - ProjectFilter& sort_filter_; -}; - -#endif // SOURCESCOMMON_H diff --git a/rendering/audio.cpp b/rendering/audio.cpp deleted file mode 100644 index 94eaf74af..000000000 --- a/rendering/audio.cpp +++ /dev/null @@ -1,426 +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 "audio.h" - -#include "global/global.h" - -#include "timeline/sequence.h" - -#include "panels/panels.h" - -#include "global/config.h" -#include "ui/audiomonitor.h" -#include "rendering/renderfunctions.h" -#include "global/debug.h" - -#include -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -} - -QAudioOutput* audio_output; -QIODevice* audio_io_device; -bool audio_device_set = false; -bool audio_scrub = false; -QMutex audio_write_lock; -QAudioInput* audio_input = nullptr; -QFile output_recording; -bool recording = false; - -int audio_rendering_rate = 0; - -float audio_ibuffer[audio_ibuffer_size]; -qint64 audio_ibuffer_read = 0; -long audio_ibuffer_frame = 0; -double audio_ibuffer_timecode = 0; - -AudioSenderThread* audio_thread = nullptr; - -bool is_audio_device_set() { - return audio_device_set; -} - -QAudioDeviceInfo get_audio_device(QAudio::Mode mode) { - QList devs = QAudioDeviceInfo::availableDevices(mode); - - // try to retrieve preferred device from config - QString preferred_device = (mode == QAudio::AudioOutput) ? olive::config.preferred_audio_output : olive::config.preferred_audio_input; - if (!preferred_device.isEmpty()) { - for (int i=0;i 0) { - return devs.at(0); - } - - // couldn't find any audio devices, return null device - return QAudioDeviceInfo(); -} - -void init_audio() { - stop_audio(); - - QAudioFormat audio_format; - audio_format.setSampleRate(olive::config.audio_rate); - audio_format.setChannelCount(2); - audio_format.setSampleSize(32); - audio_format.setCodec("audio/pcm"); - audio_format.setByteOrder(QAudioFormat::LittleEndian); - audio_format.setSampleType(QAudioFormat::Float); - - QAudioDeviceInfo info = get_audio_device(QAudio::AudioOutput); - - // see if desired format can be used by the device, use nearest if not - if (!info.isFormatSupported(audio_format)) { - qWarning() << "Audio format is not supported by backend, using nearest"; - audio_format = info.nearestFormat(audio_format); - } - - audio_output = new QAudioOutput(info, audio_format); - audio_output->moveToThread(QApplication::instance()->thread()); - audio_output->setNotifyInterval(5); - - // connect - audio_io_device = audio_output->start(); - if (audio_io_device == nullptr) { - qWarning() << "Received nullptr audio device. No compatible audio output was found."; - } else { - audio_device_set = true; - - // start sender thread - audio_thread = new AudioSenderThread(); - QObject::connect(audio_output, SIGNAL(notify()), audio_thread, SLOT(notifyReceiver())); - audio_thread->start(QThread::TimeCriticalPriority); - - clear_audio_ibuffer(); - } -} - -void stop_audio() { - if (audio_device_set) { - audio_thread->stop(); - - audio_output->stop(); - delete audio_output; - audio_device_set = false; - } -} - -void clear_audio_ibuffer() { - if (audio_thread != nullptr) audio_thread->lock.lock(); - audio_write_lock.lock(); - memset(audio_ibuffer, 0, audio_ibuffer_size * sizeof(float)); - audio_ibuffer_read = 0; - audio_write_lock.unlock(); - if (audio_thread != nullptr) audio_thread->lock.unlock(); -} - -int current_audio_freq() { - return olive::Global->is_exporting() - ? audio_rendering_rate : audio_output->format().sampleRate(); -} - -qint64 get_buffer_offset_from_frame(double framerate, long frame) { - if (frame >= audio_ibuffer_frame) { - int multiplier = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO); - return qFloor((double(frame - audio_ibuffer_frame)/framerate)*current_audio_freq())*multiplier; - } else { - qWarning() << "Invalid values passed to get_buffer_offset_from_frame" << frame << "<" << audio_ibuffer_frame; - return 0; - } -} - -AudioSenderThread::AudioSenderThread() : close(false) { - connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); -} - -void AudioSenderThread::stop() { - close = true; - cond.wakeAll(); - wait(); -} - -void AudioSenderThread::notifyReceiver() { - cond.wakeAll(); -} - -void AudioSenderThread::run() { - // start data loop - send_audio_to_output(0, audio_ibuffer_size); - - lock.lock(); - while (true) { - cond.wait(&lock); - if (close) { - break; - } else if (panel_sequence_viewer->playing || panel_footage_viewer->playing || audio_scrub) { - - int adjusted_read_index = (audio_ibuffer_read%audio_ibuffer_size); - int max_write = (audio_ibuffer_size - adjusted_read_index) * sizeof(float); - int actual_write = send_audio_to_output(adjusted_read_index, max_write); - if (actual_write == max_write) { - // got all the bytes, write again - send_audio_to_output(0, audio_ibuffer_size); - } - - audio_scrub = false; - } - } - lock.unlock(); -} - -int AudioSenderThread::send_audio_to_output(qint64 offset, int max) { - // send audio to device - audio_write_lock.lock(); - - qint64 actual_write = audio_io_device->write(reinterpret_cast(&audio_ibuffer[offset]), max); - - if (actual_write > 0) { - // average values and send to audio monitor - int channels = audio_output->format().channelCount(); - qint64 lim = offset + (actual_write/sizeof(float)); - QVector averages; - averages.resize(channels); - averages.fill(0.0); - - for (qint64 i=offset;iaudio_monitor->set_value(averages); - } - - memset(&audio_ibuffer[offset], 0, actual_write); - - audio_ibuffer_read += (actual_write / sizeof(float)); - - audio_write_lock.unlock(); - - return actual_write; -} - -double log_volume(double linear) { - // expects a value between 0 and 1 (or more if amplifying) - return (qExp(linear)-1.0f)/(M_E-1.0f); -} - -void int32_to_char_array(qint32 i, char* array) { - memcpy(array, &i, 4); -} - -void write_wave_header(QFile& f, const QAudioFormat& format) { - qint32 int32bit; - char arr[4]; - - // 4 byte riff header - f.write("RIFF"); - - // 4 byte file size, filled in later - for (int i=0;i<4;i++) f.putChar(0); - - // 4 byte file type header + 4 byte format chunk marker - f.write("WAVEfmt"); - f.putChar(0x20); - - // 4 byte length of the above format data (always 16 bytes) - f.putChar(16); - for (int i=0;i<3;i++) f.putChar(0); - - // 2 byte type format (1 is PCM) - f.putChar(1); - f.putChar(0); - - // 2 byte channel count - int32bit = format.channelCount(); - int32_to_char_array(int32bit, arr); - f.write(arr, 2); - - // 4 byte integer for sample rate - int32bit = format.sampleRate(); - int32_to_char_array(int32bit, arr); - f.write(arr, 4); - - // 4 byte integer for bytes per second - int32bit = (format.sampleRate() * format.sampleSize() * format.channelCount()) / 8; - int32_to_char_array(int32bit, arr); - f.write(arr, 4); - - // 2 byte integer for bytes per sample per channel - int32bit = (format.sampleSize() * format.channelCount()) / 8; - int32_to_char_array(int32bit, arr); - f.write(arr, 2); - - // 2 byte integer for bits per sample (16) - int32bit = format.sampleSize(); - int32_to_char_array(int32bit, arr); - f.write(arr, 2); - - // data chunk header - f.write("data"); - - // 4 byte integer for data chunk size (filled in later)? - for (int i=0;i<4;i++) f.putChar(0); -} - -void write_wave_trailer(QFile& f) { - char arr[4]; - - f.seek(4); - - // 4 bytes for total file size - 8 bytes - qint32 file_size = qint32(f.size()) - 8; - int32_to_char_array(file_size, arr); - f.write(arr, 4); - - f.seek(40); - - // 4 bytes for data chunk size (file size - header) - file_size = qint32(f.size()) - 44; - int32_to_char_array(file_size, arr); - f.write(arr, 4); -} - -bool start_recording() { - if (!olive::Global->CheckForActiveSequence(true)) { - return false; - } - - QString audio_path = QCoreApplication::translate("Audio", "%1 Audio").arg(olive::ActiveProjectFilename); - QDir audio_dir(audio_path); - if (!audio_dir.exists() && !audio_dir.mkpath(".")) { - qCritical() << "Failed to create audio directory"; - return false; - } - - QString audio_file_path; - int file_number = 0; - do { - file_number++; - - QString audio_filename = QString("%1.wav").arg( - QCoreApplication::translate("Audio", "Recording %1").arg(QString::number(file_number)) - ); - - audio_file_path = audio_dir.filePath(audio_filename); - } while (QFile(audio_file_path).exists()); - - output_recording.setFileName(audio_file_path); - if (!output_recording.open(QFile::WriteOnly)) { - qCritical() << "Failed to open output file. Does Olive have permission to write to this directory?"; - return false; - } - - QAudioFormat audio_format = audio_output->format(); - if (olive::config.recording_mode != audio_format.channelCount()) { - audio_format.setChannelCount(olive::config.recording_mode); - } - - QAudioDeviceInfo info = get_audio_device(QAudio::AudioInput); - - if (!info.isFormatSupported(audio_format)) { - qWarning() << "Default format not supported, using nearest"; - audio_format = info.nearestFormat(audio_format); - } - write_wave_header(output_recording, audio_format); - audio_input = new QAudioInput(info, audio_format); - audio_input->start(&output_recording); - recording = true; - - return true; -} - -void stop_recording() { - if (recording) { - audio_input->stop(); - - write_wave_trailer(output_recording); - - output_recording.close(); - - delete audio_input; - audio_input = nullptr; - recording = false; - } -} - -QString get_recorded_audio_filename() { - return output_recording.fileName(); -} - -void combobox_audio_sample_rates(QComboBox *combobox) { - combobox->addItem("22050 Hz", 22050); - combobox->addItem("24000 Hz", 24000); - combobox->addItem("32000 Hz", 32000); - combobox->addItem("44100 Hz", 44100); - combobox->addItem("48000 Hz", 48000); - combobox->addItem("88200 Hz", 88200); - combobox->addItem("96000 Hz", 96000); -} - -QObject* audio_wake_object = nullptr; -QMutex audio_wake_mutex; - -QObject* GetAudioWakeObject() -{ - audio_wake_mutex.lock(); - - QObject* wake_object = audio_wake_object; - audio_wake_object = nullptr; - - audio_wake_mutex.unlock(); - - return wake_object; -} - -void SetAudioWakeObject(QObject *o) -{ - audio_wake_mutex.lock(); - audio_wake_object = o; - audio_wake_mutex.unlock(); -} - -void WakeAudioWakeObject() { - QObject* audio_wake_object = GetAudioWakeObject(); - - if (audio_wake_object != nullptr) { - QMetaObject::invokeMethod(audio_wake_object, "play_wake", Qt::QueuedConnection); - } -} diff --git a/rendering/audio.h b/rendering/audio.h deleted file mode 100644 index b121a3572..000000000 --- a/rendering/audio.h +++ /dev/null @@ -1,85 +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 AUDIO_H -#define AUDIO_H - -#include -#include -#include -#include -#include -#include -#include - -#include "timeline/sequence.h" - -class AudioSenderThread : public QThread { - Q_OBJECT -public: - AudioSenderThread(); - void run(); - void stop(); - QWaitCondition cond; - bool close; - QMutex lock; -public slots: - void notifyReceiver(); -private: - QVector samples; - int send_audio_to_output(qint64 offset, int max); -}; - -double log_volume(double linear); - -extern QAudioOutput* audio_output; -extern QIODevice* audio_io_device; -extern AudioSenderThread* audio_thread; -extern QMutex audio_write_lock; - -#define audio_ibuffer_size 192000 -extern float audio_ibuffer[audio_ibuffer_size]; -extern qint64 audio_ibuffer_read; -extern long audio_ibuffer_frame; -extern double audio_ibuffer_timecode; -extern bool audio_scrub; -extern bool recording; -extern int audio_rendering_rate; -void clear_audio_ibuffer(); - -QObject *GetAudioWakeObject(); -void SetAudioWakeObject(QObject* o); -void WakeAudioWakeObject(); - -int current_audio_freq(); - -bool is_audio_device_set(); - -void init_audio(); -void stop_audio(); -qint64 get_buffer_offset_from_frame(double framerate, long frame); - -bool start_recording(); -void stop_recording(); -QString get_recorded_audio_filename(); - -void combobox_audio_sample_rates(QComboBox* combobox); - -#endif // AUDIO_H diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp deleted file mode 100644 index d3fe1bba2..000000000 --- a/rendering/cacher.cpp +++ /dev/null @@ -1,1459 +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 "cacher.h" - -#ifndef __STDC_FORMAT_MACROS -// For some reason the Windows AppVeyor build fails to find PRIx64 without this definition and including -// Maybe something to do with the GCC version being used? Either way, that's why it's here. -#define __STDC_FORMAT_MACROS 1 -#endif - -#include - -#include -#include -#include -#include - -#include "panels/panels.h" -#include "project/projectelements.h" -#include "rendering/audio.h" -#include "rendering/renderfunctions.h" -#include "global/timing.h" -#include "global/config.h" -#include "global/global.h" -#include "global/debug.h" -#include "ui/mainwindow.h" - -// Enable verbose audio messages - good for debugging reversed audio -//#define AUDIOWARNINGS - -const AVSampleFormat kDestSampleFmt = AV_SAMPLE_FMT_FLTP; - -double samples_to_seconds(int nb_samples, int nb_channels, int sample_rate) { - return (double(nb_samples) / double(nb_channels) / double(sample_rate)); -} - -int samples_to_bytes(int nb_samples, int nb_channels) { - return nb_samples * nb_channels * sizeof(float); -} - -void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int nb_samples, int nb_channels, QVector nests) { - // perform all audio effects - double timecode_end; - timecode_end = timecode_start + samples_to_seconds(nb_samples, frame->channels, frame->sample_rate); - - for (int j=0;jeffects.size();j++) { - OldEffectNode* e = clip->effects.at(j).get(); - if (e->IsEnabled()) { - e->process_audio(timecode_start, timecode_end, reinterpret_cast(frame->data), nb_samples, nb_channels, kTransitionNone); - } - } - if (clip->opening_transition != nullptr) { - if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - double transition_start = (clip->clip_in(true) / clip->track()->sequence()->frame_rate()); - double transition_end = (clip->clip_in(true) + clip->opening_transition->get_length()) / clip->track()->sequence()->frame_rate(); - if (timecode_end < transition_end) { - double adjustment = transition_end - transition_start; - double adjusted_range_start = (timecode_start - transition_start) / adjustment; - double adjusted_range_end = (timecode_end - transition_start) / adjustment; - clip->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, reinterpret_cast(frame->data), nb_samples, nb_channels, kTransitionOpening); - } - } - } - if (clip->closing_transition != nullptr) { - if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - long length_with_transitions = clip->timeline_out(true) - clip->timeline_in(true); - double transition_start = (clip->clip_in(true) + length_with_transitions - clip->closing_transition->get_length()) / clip->track()->sequence()->frame_rate(); - double transition_end = (clip->clip_in(true) + length_with_transitions) / clip->track()->sequence()->frame_rate(); - if (timecode_start > transition_start) { - double adjustment = transition_end - transition_start; - double adjusted_range_start = (timecode_start - transition_start) / adjustment; - double adjusted_range_end = (timecode_end - transition_start) / adjustment; - clip->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, reinterpret_cast(frame->data), nb_samples, nb_channels, kTransitionClosing); - } - } - } - - if (!nests.isEmpty()) { - Clip* next_nest = nests.last(); - nests.removeLast(); - apply_audio_effects(next_nest, - timecode_start + (double(clip->timeline_in(true)-clip->clip_in(true))/clip->track()->sequence()->frame_rate()), - frame, - nb_samples, - nb_channels, - nests); - } -} - -#define AUDIO_BUFFER_PADDING 2048 -void Cacher::CacheAudioWorker() { - // main thread waits until cacher starts fully, wake it up here - WakeMainThread(); - - bool audio_just_reset = false; - - // for audio clips, something may have triggered an audio reset (common if the user seeked) - if (audio_reset_) { - Reset(); - audio_reset_ = false; - audio_just_reset = true; - } - - long timeline_in = clip->timeline_in(true); - long timeline_out = clip->timeline_out(true); - long target_frame = audio_target_frame; - - bool temp_reverse = (playback_speed_ < 0); - bool reverse_audio = IsReversed(); - - long frame_skip = 0; - double last_fr = clip->track()->sequence()->frame_rate(); - if (!nests_.isEmpty()) { - for (int i=nests_.size()-1;i>=0;i--) { - timeline_in = rescale_frame_number(timeline_in, last_fr, nests_.at(i)->track()->sequence()->frame_rate()) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); - timeline_out = rescale_frame_number(timeline_out, last_fr, nests_.at(i)->track()->sequence()->frame_rate()) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); - target_frame = rescale_frame_number(target_frame, last_fr, nests_.at(i)->track()->sequence()->frame_rate()) + nests_.at(i)->timeline_in(true) - nests_.at(i)->clip_in(true); - - timeline_out = qMin(timeline_out, nests_.at(i)->timeline_out(true)); - - frame_skip = rescale_frame_number(frame_skip, last_fr, nests_.at(i)->track()->sequence()->frame_rate()); - - long validator = nests_.at(i)->timeline_in(true) - timeline_in; - if (validator > 0) { - frame_skip += validator; - //timeline_in = nests_.at(i)->timeline_in(true); - } - - last_fr = nests_.at(i)->track()->sequence()->frame_rate(); - } - } - - if (temp_reverse) { - // FIXME breakable? - long seq_end = Timeline::GetTopSequence()->GetEndFrame(); - timeline_in = seq_end - timeline_in; - timeline_out = seq_end - timeline_out; - target_frame = seq_end - target_frame; - - long temp = timeline_in; - timeline_in = timeline_out; - timeline_out = temp; - } - - while (true) { - AVFrame* frame; - int nb_samples = INT_MAX; - - if (clip->media() == nullptr) { - frame = frame_; - nb_samples = frame->nb_samples; - while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_samples) && nb_samples > 0) { - // create "new frame" - memset(frame_->data[0], 0, nb_samples); - apply_audio_effects(clip, samples_to_seconds(frame->pts, frame->channels, frame->sample_rate), frame, nb_samples, frame->channels, nests_); - frame_->pts += nb_samples; - frame_sample_index_ = 0; - if (audio_buffer_write == 0) { - audio_buffer_write = get_buffer_offset_from_frame(last_fr, qMax(timeline_in, target_frame)); - } - int offset = audio_ibuffer_read - audio_buffer_write; - if (offset > 0) { - audio_buffer_write += offset; - frame_sample_index_ += offset; - } - } - } else if (clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - double timebase = av_q2d(stream->time_base); - - frame = queue_.at(0); - - // retrieve frame - bool new_frame = false; - while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_samples) && nb_samples > 0) { - - // no more audio left in frame, get a new one - if (!reached_end) { - int loop = 0; - - if (reverse_audio && !audio_just_reset) { - avcodec_flush_buffers(codecCtx); - reached_end = false; - int64_t backtrack_seek = qMax(reverse_target_ - static_cast(av_q2d(av_inv_q(stream->time_base))), - static_cast(0)); - av_seek_frame(formatCtx, stream->index, backtrack_seek, AVSEEK_FLAG_BACKWARD); -#ifdef AUDIOWARNINGS - if (backtrack_seek == 0) { - dout << "backtracked to 0"; - } -#endif - } - - do { - av_frame_unref(frame); - - int ret; - - while ((ret = av_buffersink_get_frame(buffersink_ctx, frame)) == AVERROR(EAGAIN)) { - ret = RetrieveFrameFromDecoder(frame_); - if (ret >= 0) { - if ((ret = av_buffersrc_add_frame_flags(buffersrc_ctx, frame_, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) { - qCritical() << "Could not feed filtergraph -" << ret; - break; - } - } else { - if (ret == AVERROR_EOF) { -#ifdef AUDIOWARNINGS - dout << "reached EOF while reading"; -#endif - // TODO revise usage of reached_end in audio - if (!reverse_audio) { - reached_end = true; - } else { - } - } else { - qWarning() << "Raw audio frame data could not be retrieved." << ret; - reached_end = true; - } - break; - } - } - - if (ret < 0) { - if (ret != AVERROR_EOF) { - qCritical() << "Could not pull from filtergraph"; - reached_end = true; - break; - } else { -#ifdef AUDIOWARNINGS - dout << "reached EOF while pulling from filtergraph"; -#endif - if (!reverse_audio) break; - } - } - - if (reverse_audio) { - if (loop > 1) { - AVFrame* rev_frame = queue_.at(1); - if (ret != AVERROR_EOF) { - if (loop == 2) { -#ifdef AUDIOWARNINGS - dout << "starting rev_frame"; -#endif - rev_frame->nb_samples = 0; - rev_frame->pts = frame_->pkt_pts; - } - int offset = rev_frame->nb_samples * av_get_bytes_per_sample(static_cast(rev_frame->format)) * rev_frame->channels; -#ifdef AUDIOWARNINGS - dout << "offset 1:" << offset; - dout << "retrieved samples:" << frame->nb_samples << "size:" << (frame->nb_samples * av_get_bytes_per_sample(static_cast(frame->format)) * frame->channels); -#endif - memcpy( - rev_frame->data[0]+offset, - frame->data[0], - (frame->nb_samples * av_get_bytes_per_sample(static_cast(frame->format)) * frame->channels) - ); -#ifdef AUDIOWARNINGS - dout << "pts:" << frame_->pts << "dur:" << frame_->pkt_duration << "rev_target:" << reverse_target << "offset:" << offset << "limit:" << rev_frame->linesize[0]; -#endif - } - - rev_frame->nb_samples += frame->nb_samples; - - if ((frame_->pts >= reverse_target_) || (ret == AVERROR_EOF)) { - /* -#ifdef AUDIOWARNINGS - dout << "time for the end of rev cache" << rev_frame->nb_samples << clip->rev_target << frame_->pts << frame_->pkt_duration << frame_->nb_samples; - dout << "diff:" << (frame_->pkt_pts + frame_->pkt_duration) - clip->rev_target; -#endif - int cutoff = qRound64((((frame_->pkt_pts + frame_->pkt_duration) - reverse_target) * timebase) * audio_output->format().sampleRate()); - if (cutoff > 0) { -#ifdef AUDIOWARNINGS - dout << "cut off" << cutoff << "samples (rate:" << audio_output->format().sampleRate() << ")"; -#endif - rev_frame->nb_samples -= cutoff; - } -*/ - -#ifdef AUDIOWARNINGS - dout << "pre cutoff deets::: rev_frame.pts:" << rev_frame->pts << "rev_frame.nb_samples" << rev_frame->nb_samples << "rev_target:" << reverse_target; -#endif - double playback_speed_ = clip->speed().value * clip->media()->to_footage()->speed; - rev_frame->nb_samples = qRound64(double(reverse_target_ - rev_frame->pts) * timebase * (current_audio_freq() / playback_speed_)); -#ifdef AUDIOWARNINGS - dout << "post cutoff deets::" << rev_frame->nb_samples; -#endif - - int frame_size = rev_frame->nb_samples * rev_frame->channels * av_get_bytes_per_sample(static_cast(rev_frame->format)); - int half_frame_size = frame_size >> 1; - - int sample_size = rev_frame->channels*av_get_bytes_per_sample(static_cast(rev_frame->format)); - char* temp_chars = new char[sample_size]; - for (int i=0;idata[0][i], sample_size); - - memcpy(&rev_frame->data[0][i], &rev_frame->data[0][frame_size-i-sample_size], sample_size); - - memcpy(&rev_frame->data[0][frame_size-i-sample_size], temp_chars, sample_size); - } - delete [] temp_chars; - - reverse_target_ = rev_frame->pts; - frame = rev_frame; - break; - } - } - - loop++; - -#ifdef AUDIOWARNINGS - dout << "loop" << loop; -#endif - } else { - frame->pts = frame_->pts; - break; - } - } while (true); - } else { - // if there is no more data in the file, we flush the remainder out of swresample - break; - } - - new_frame = true; - - if (frame_sample_index_ < 0) { - frame_sample_index_ = 0; - } else { - frame_sample_index_ -= nb_samples; - } - - nb_samples = frame->nb_samples; - - if (audio_just_reset) { - // get precise sample offset for the elected clip_in from this audio frame - double target_sts = playhead_to_clip_seconds(clip, audio_target_frame); - - int64_t stream_start = qMax(static_cast(0), stream->start_time); - double frame_sts = ((frame->pts - stream_start) * timebase); - - int nb_samples = qRound64((target_sts - frame_sts)*current_audio_freq()); - frame_sample_index_ = nb_samples * 4; -#ifdef AUDIOWARNINGS - dout << "fsts:" << frame_sts << "tsts:" << target_sts << "nbs:" << nb_samples << "nbb:" << nb_bytes << "rev_targetToSec:" << (reverse_target * timebase); - dout << "fsi-calc:" << frame_sample_index; -#endif - if (reverse_audio) frame_sample_index_ = nb_samples - frame_sample_index_; - audio_just_reset = false; - } - -#ifdef AUDIOWARNINGS - dout << "fsi-post-post:" << frame_sample_index; -#endif - if (audio_buffer_write == 0) { - audio_buffer_write = get_buffer_offset_from_frame(last_fr, qMax(timeline_in, target_frame)); - - if (frame_skip > 0) { - int target = get_buffer_offset_from_frame(last_fr, qMax(timeline_in + frame_skip, target_frame)); - frame_sample_index_ += (target - audio_buffer_write); - audio_buffer_write = target; - } - } - - int offset = audio_ibuffer_read - audio_buffer_write; - if (offset > 0) { - audio_buffer_write += offset; - frame_sample_index_ += offset; - } - - // try to correct negative fsi - if (frame_sample_index_ < 0) { - audio_buffer_write -= frame_sample_index_; - frame_sample_index_ = 0; - } - } - - if (reverse_audio) frame = queue_.at(1); - -#ifdef AUDIOWARNINGS - dout << "j" << frame_sample_index << nb_bytes; -#endif - - // apply any audio effects to the data - if (nb_samples == INT_MAX) { - nb_samples = frame->nb_samples; - } - if (new_frame) { - apply_audio_effects(clip, - samples_to_seconds(audio_buffer_write, 2, current_audio_freq()) - + audio_ibuffer_timecode - + (double(clip->clip_in(true))/clip->track()->sequence()->frame_rate()) - - (double(timeline_in)/last_fr), - frame, - nb_samples, - frame->channels, - nests_); - } - } - - // mix audio into internal buffer - if (frame->nb_samples == 0) { - break; - } else { - qint64 buffer_timeline_out = get_buffer_offset_from_frame(clip->track()->sequence()->frame_rate(), timeline_out); - - audio_write_lock.lock(); - - int sample_skip = qMax(0, qAbs(playback_speed_)-1); - - while (frame_sample_index_ < nb_samples - && audio_buffer_write < audio_ibuffer_read+(audio_ibuffer_size>>1) - && audio_buffer_write < buffer_timeline_out) { - for (int i=0;ichannels;i++) { - int buffer_index = audio_buffer_write%audio_ibuffer_size; - - audio_ibuffer[buffer_index] += reinterpret_cast(frame->data[i])[frame_sample_index_]; - - audio_buffer_write++; - } - - frame_sample_index_++; - - frame_sample_index_ += sample_skip; - - if (audio_reset_) break; - } - -#ifdef AUDIOWARNINGS - if (audio_buffer_write >= buffer_timeline_out) dout << "timeline out at fsi" << frame_sample_index << "of frame ts" << frame_->pts; -#endif - - audio_write_lock.unlock(); - - if (audio_reset_) return; - - if (scrubbing_) { - if (audio_thread != nullptr) audio_thread->notifyReceiver(); - } - - if (frame_sample_index_ >= nb_samples) { - frame_sample_index_ = -1; - } else { - // assume we have no more data to send - break; - } - - // dout << "ended" << frame_sample_index << nb_bytes; - } - if (reached_end) { - frame->nb_samples = 0; - } - if (scrubbing_) { - break; - } - } - - // If there's a QObject waiting for audio to be rendered, wake it now - WakeAudioWakeObject(); -} - -bool Cacher::IsReversed() -{ - // Here, the Clip reverse and reversed playback speed cancel each other out to produce normal playback - return (clip->reversed() != playback_speed_ < 0); -} - -void Cacher::CacheVideoWorker() { - - // is this media a still image? - if (clip->media_stream()->infinite_length) { - - // for efficiency, we do slightly different things for a still image - - // if we already queued a frame, we don't actually need to cache anything, so we only retrieve a frame if not - if (queue_.size() == 0) { - - // retrieve a single frame - - // main thread waits until cacher starts fully, wake it up here - WakeMainThread(); - - AVFrame* still_image_frame; - - if (RetrieveFrameAndProcess(&still_image_frame) >= 0) { - - queue_.lock(); - queue_.append(still_image_frame); - queue_.unlock(); - - SetRetrievedFrame(still_image_frame); - } - - } - - } else { - // this media is not a still image and will require more complex caching - - // main thread waits until cacher starts fully, wake it up here - WakeMainThread(); - - // determine if this media is reversed, which will affect how the queue is constructed - bool reversed = IsReversed(); - - // get the timestamp we want in terms of the media's timebase - int64_t target_pts = seconds_to_timestamp(clip, playhead_to_clip_seconds(clip, playhead_)); - - // get the value of one second in terms of the media's timebase - int64_t second_pts = seconds_to_timestamp(clip, 1); // FIXME: possibly magic number? - - // check which range of frames we have in the queue - int64_t earliest_pts = INT64_MAX; - int64_t latest_pts = INT64_MIN; - int frames_greater_than_target = 0; - - for (int i=0;ipts); - latest_pts = qMax(latest_pts, queue_.at(i)->pts); - - // count upcoming frames - if (queue_.at(i)->pts > target_pts) { - frames_greater_than_target++; - } - } - - // If we have to seek ahead, we may want to re-use the frame we retrieved later in the pipeline. - AVFrame* decoded_frame; - bool have_existing_frame_to_use = false; - bool seeked_to_zero = false; - - // check if the frame is within this queue or if we'll have to seek elsewhere to get it - // (we check for one second of time after latest_pts, because if it's within that range it'll likely be faster to - // play up to that frame than seek to it) - if (target_pts < earliest_pts || target_pts > latest_pts + second_pts || queue_.size() == 0) { - // we need to seek to retrieve this frame - - int retrieve_code; - int64_t seek_ts = target_pts; - int64_t zero = 0; - - // Some formats don't seek reliably to the last keyframe, as a result we need to seek in a loop to ensure we - // get a frame prior to the timestamp - do { - - // if we already allocated a frame here, we'd better free it - if (have_existing_frame_to_use) { - av_frame_free(&decoded_frame); - } - - // If we already seeked to a timestamp of zero, there's no further we can go, so we have to exit the loop if so - seeked_to_zero = (seek_ts == 0); - - avcodec_flush_buffers(codecCtx); - av_seek_frame(formatCtx, clip->media_stream_index(), seek_ts, AVSEEK_FLAG_BACKWARD); - - retrieve_code = RetrieveFrameAndProcess(&decoded_frame); - - //qDebug() << "Target:" << target_pts << "Seek:" << seek_ts << "Frame:" << decoded_frame->pts; - - seek_ts = qMax(zero, seek_ts - second_pts); - - have_existing_frame_to_use = true; - } while (retrieve_code >= 0 && decoded_frame->pts > target_pts && !seeked_to_zero); - - // also we assume none of the frames in the queue are usable - queue_.lock(); - queue_.clear(); - queue_.unlock(); - - // reset upcoming frame count and latest pts for later calculations - frames_greater_than_target = 0; - latest_pts = INT64_MIN; - } - - // get values on old frames to remove from the queue - - // for FRAME_QUEUE_TYPE_SECONDS, this is used to store the maximum timestamp - // for FRAME_QUEUE_TYPE_FRAMES, this is used to store the maximum number of frames that can be added - int64_t minimum_ts; - - // check if we can add more frames to this queue or not - - // for FRAME_QUEUE_TYPE_SECONDS, this is used to store the maximum timestamp - // for FRAME_QUEUE_TYPE_FRAMES, this is used to store the maximum number of frames that can be added - int64_t maximum_ts; - - // Get queue configuration - int previous_queue_type, upcoming_queue_type; - double previous_queue_size, upcoming_queue_size; - - // For reversed playback, we flip the queue stats as "upcoming" frames are going to be played before the "previous" - // frames now - if (reversed) { - previous_queue_type = olive::config.upcoming_queue_type; - previous_queue_size = olive::config.upcoming_queue_size; - upcoming_queue_type = olive::config.previous_queue_type; - upcoming_queue_size = olive::config.previous_queue_size; - } else { - previous_queue_type = olive::config.previous_queue_type; - previous_queue_size = olive::config.previous_queue_size; - upcoming_queue_type = olive::config.upcoming_queue_type; - upcoming_queue_size = olive::config.upcoming_queue_size; - } - - // Determine "previous" queue statistics - if (previous_queue_type == olive::FRAME_QUEUE_TYPE_FRAMES) { - // get the maximum number of previous frames that can be in the queue - minimum_ts = qCeil(previous_queue_size); - } else { - // get the minimum frame timestamp that can be added to the queue - minimum_ts = qRound(target_pts - second_pts * previous_queue_size); - } - - // Determine "upcoming" queue statistics - if (upcoming_queue_type == olive::FRAME_QUEUE_TYPE_FRAMES) { - maximum_ts = qCeil(upcoming_queue_size); - } else { - // get the maximum frame timestamp that can be added to the queue - maximum_ts = qRound(target_pts + second_pts * upcoming_queue_size); - } - - // if we already have the maximum number of upcoming frames, don't bother running the retrieving any frames at all - bool start_loop = true; - if ((upcoming_queue_type == olive::FRAME_QUEUE_TYPE_FRAMES && frames_greater_than_target >= maximum_ts) - || (upcoming_queue_type == olive::FRAME_QUEUE_TYPE_SECONDS && latest_pts > maximum_ts)) { - start_loop = false; - } - - - if (start_loop) { - - interrupt_ = false; - do { - - // retrieve raw RGBA frame from decoder + filter stack - int retrieve_code = 0; - - // if we retrieved a perfectly good frame earlier by checking the seek, use that here - if (!have_existing_frame_to_use) { - retrieve_code = RetrieveFrameAndProcess(&decoded_frame); - } else { - have_existing_frame_to_use = false; - } - - if (retrieve_code < 0 && retrieve_code != AVERROR_EOF) { - - // for some reason we were unable to retrieve a frame, likely a decoder error so we report it - // 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) { - - // check if this frame exceeds the minimum timestamp - if (previous_queue_type == olive::FRAME_QUEUE_TYPE_SECONDS - && decoded_frame->pts < minimum_ts) { - - // if so, we don't need it - av_frame_free(&decoded_frame); - - } else { - - if (retrieved_frame == nullptr) { - if (decoded_frame->pts == target_pts) { - - // We retrieved the exact frame we're looking for - - SetRetrievedFrame(decoded_frame); - - } else if (decoded_frame->pts > target_pts) { - - if (queue_.size() > 0) { - - SetRetrievedFrame(queue_.last()); - - } else if (seeked_to_zero) { - - // If this flag is set but we still got a frame after the target timestamp, it means this was somehow - // the earliest frame we could get - SetRetrievedFrame(decoded_frame); - seeked_to_zero = false; - - } - - } - } - - // add the frame to the queue - queue_.lock(); - queue_.append(decoded_frame); - queue_.unlock(); - - // check the amount of previous frames in the queue by using the current queue size for if we need to - // remove any old entries (assumes the queue is chronological) - if (previous_queue_type == olive::FRAME_QUEUE_TYPE_FRAMES) { - - int previous_frame_count = 0; - - if (decoded_frame->pts < target_pts) { - // if this frame is before the target frame, make sure we don't add too many of them - previous_frame_count = queue_.size(); - } else { - // if this frame is after the target frame, clean up any previous frames before it - // TODO is there a faster way to do this? - - for (int i=0;ipts > target_pts) { - break; - } else { - previous_frame_count++; - } - } - - } - - // remove frames while the amount of previous frames exceeds the maximum - while (previous_frame_count > minimum_ts) { - queue_.lock(); - queue_.removeFirst(); - queue_.unlock(); - previous_frame_count--; - } - - } - - // check if the queue is full according to olive::CurrentConfig - if (upcoming_queue_type == olive::FRAME_QUEUE_TYPE_FRAMES) { - - // if this frame is later than the target, it's an "upcoming" frame - if (decoded_frame->pts > target_pts) { - - // we started a count of upcoming frames above, we can continue it here - frames_greater_than_target++; - - // compare upcoming frame count with maximum upcoming frames (maximum_ts) - if (frames_greater_than_target >= maximum_ts) { - break; - } - } - - } else if (decoded_frame->pts > maximum_ts) { // for `upcoming_queue_type == olive::FRAME_QUEUE_TYPE_SECONDS` - break; - } - - } - - - - } else { - - // if a frame has no timestamp (pts == AV_NOPTS_VALUE), we assume it's an invalid frame and don't use it - - qWarning() << clip->name() << "frame had no PTS value"; - av_frame_free(&decoded_frame); - - if (retrieve_code == AVERROR_EOF && retrieved_frame == nullptr && !queue_.isEmpty()) { - // if we reached the end of the file, it's not an error but there are no more frames to retrieve - // some formats EOF before the end of the duration that Olive calculates. In this event, we simply - // return the last frame we retrieved - // - // TODO: Check duration formula - - SetRetrievedFrame(queue_.last()); - - } else { - - SetRetrievedFrame(nullptr); - - } - - break; - - } - } while (!interrupt_); - - } - - } - - // For some reason we couldn't get the frame, we should wake up the RenderThread anyway - if (retrieved_frame == nullptr) { - qCritical() << "Couldn't retrieve an appropriate frame. This is an error and may mean this media is corrupt."; - SetRetrievedFrame(nullptr); - } -} - -void Cacher::Reset() { - // if we seek to a whole other place in the timeline, we'll need to reset the cache with new values - if (clip->media() == nullptr) { - if (clip->type() == olive::kTypeAudio) { - // a null-media audio clip is usually an auto-generated sound clip such as Tone or Noise - reached_end = false; - audio_target_frame = playhead_; - frame_sample_index_ = -1; - frame_->pts = 0; - } - } else { - - const FootageStream* ms = clip->media_stream(); - if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - // flush ffmpeg codecs - avcodec_flush_buffers(codecCtx); - reached_end = false; - - // seek (target_frame represents timeline timecode in frames, not clip timecode) - - int64_t timestamp = qRound64(playhead_to_clip_seconds(clip, playhead_) / av_q2d(stream->time_base)); - - bool temp_reverse = (playback_speed_ < 0); - if (clip->reversed() != temp_reverse) { - reverse_target_ = timestamp; - timestamp -= av_q2d(av_inv_q(stream->time_base)); -#ifdef AUDIOWARNINGS - dout << "seeking to" << timestamp << "(originally" << reverse_target << ")"; - } else { - dout << "reset called; seeking to" << timestamp; -#endif - } - av_seek_frame(formatCtx, ms->file_index, timestamp, AVSEEK_FLAG_BACKWARD); - audio_target_frame = playhead_; - frame_sample_index_ = -1; - } - } -} - -void Cacher::SetRetrievedFrame(AVFrame *f) -{ - if (retrieved_frame == nullptr) { - retrieve_lock_.lock(); - retrieved_frame = f; - retrieve_wait_.wakeAll(); - retrieve_lock_.unlock(); - } -} - -void Cacher::WakeMainThread() -{ - main_thread_lock_.lock(); - main_thread_wait_.wakeAll(); - main_thread_lock_.unlock(); -} - -Cacher::Cacher(Clip* c) : - clip(c), - frame_(nullptr), - pkt(nullptr), - formatCtx(nullptr), - opts(nullptr), - filter_graph(nullptr), - codecCtx(nullptr), - is_valid_state_(false) -{} - -void Cacher::OpenWorker() { - // set some defaults for the audio cacher - if (clip->type() == olive::kTypeAudio) { - audio_reset_ = false; - frame_sample_index_ = -1; - audio_buffer_write = 0; - } - reached_end = false; - - if (clip->media() == nullptr) { - if (clip->type() == olive::kTypeAudio) { - frame_ = av_frame_alloc(); - frame_->format = kDestSampleFmt; - frame_->channel_layout = clip->track()->sequence()->audio_layout(); - frame_->channels = av_get_channel_layout_nb_channels(frame_->channel_layout); - frame_->sample_rate = current_audio_freq(); - frame_->nb_samples = 2048; - av_frame_make_writable(frame_); - if (av_frame_get_buffer(frame_, 0)) { - qCritical() << "Could not allocate buffer for tone clip"; - } - audio_reset_ = true; - } - } else if (clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - // opens file resource for FFmpeg and prepares Clip struct for playback - Footage* m = clip->media()->to_footage(); - - // byte array for retrieving raw bytes from QString URL - QByteArray ba; - - // do we have a proxy? - if ((!olive::Global->is_exporting() || !olive::config.dont_use_proxies_on_export) - && m->proxy - && !m->proxy_path.isEmpty() - && QFileInfo::exists(m->proxy_path)) { - ba = m->proxy_path.toUtf8(); - } else { - ba = m->url.toUtf8(); - } - - const char* filename = ba.constData(); - const FootageStream* ms = clip->media_stream(); - - // for image sequences that don't start at 0, set the index where it does start - AVDictionary* format_opts = nullptr; - if (m->start_number > 0) { - av_dict_set(&format_opts, "start_number", QString::number(m->start_number).toUtf8(), 0); - } - - formatCtx = nullptr; - int errCode = avformat_open_input( - &formatCtx, - filename, - nullptr, - &format_opts - ); - if (errCode != 0) { - char err[1024]; - av_strerror(errCode, err, 1024); - qCritical() << "Could not open" << filename << "-" << err; - olive::MainWindow->statusBar()->showMessage(tr("Could not open %1 - %2").arg(filename, err)); - return; - } - - errCode = avformat_find_stream_info(formatCtx, nullptr); - if (errCode < 0) { - char err[1024]; - av_strerror(errCode, err, 1024); - qCritical() << "Could not open" << filename << "-" << err; - olive::MainWindow->statusBar()->showMessage(tr("Could not open %1 - %2").arg(filename, err)); - return; - } - - av_dump_format(formatCtx, 0, filename, 0); - - stream = formatCtx->streams[ms->file_index]; - codec = avcodec_find_decoder(stream->codecpar->codec_id); - codecCtx = avcodec_alloc_context3(codec); - avcodec_parameters_to_context(codecCtx, stream->codecpar); - - opts = nullptr; - - // enable multithreading on decoding - av_dict_set(&opts, "threads", "auto", 0); - - // enable extra optimization code on h264 (not even sure if they help) - if (stream->codecpar->codec_id == AV_CODEC_ID_H264) { - av_dict_set(&opts, "tune", "fastdecode", 0); - av_dict_set(&opts, "tune", "zerolatency", 0); - } - - // Open codec - if (avcodec_open2(codecCtx, codec, &opts) < 0) { - qCritical() << "Could not open codec"; - } - - // allocate filtergraph - filter_graph = avfilter_graph_alloc(); - if (filter_graph == nullptr) { - qCritical() << "Could not create filtergraph"; - } - char filter_args[512]; - - if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - snprintf(filter_args, sizeof(filter_args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", - stream->codecpar->width, - stream->codecpar->height, - stream->codecpar->format, - stream->time_base.num, - stream->time_base.den, - stream->codecpar->sample_aspect_ratio.num, - stream->codecpar->sample_aspect_ratio.den - ); - - avfilter_graph_create_filter(&buffersrc_ctx, avfilter_get_by_name("buffer"), "in", filter_args, nullptr, filter_graph); - avfilter_graph_create_filter(&buffersink_ctx, avfilter_get_by_name("buffersink"), "out", nullptr, nullptr, filter_graph); - - AVFilterContext* last_filter = buffersrc_ctx; - - char filter_args[100]; - - if (ms->video_interlacing != VIDEO_PROGRESSIVE) { - AVFilterContext* yadif_filter; - snprintf(filter_args, sizeof(filter_args), "mode=3:parity=%d", ((ms->video_interlacing == VIDEO_TOP_FIELD_FIRST) ? 0 : 1)); // there's a CUDA version if we start using nvdec/nvenc - avfilter_graph_create_filter(&yadif_filter, avfilter_get_by_name("yadif"), "yadif", filter_args, nullptr, filter_graph); - - avfilter_link(last_filter, 0, yadif_filter, 0); - last_filter = yadif_filter; - } - - AVPixelFormat possible_pix_fmts[] = { - AV_PIX_FMT_RGBA, - AV_PIX_FMT_RGBA64, - AV_PIX_FMT_NONE - }; - - AVPixelFormat pix_fmt = avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, - static_cast(stream->codecpar->format), - 1, - nullptr); - - if (pix_fmt == AV_PIX_FMT_RGBA) { - qDebug() << "This is an 8-bit image."; - media_pixel_format_ = olive::PIX_FMT_RGBA8; - } else { - qDebug() << "This is an HDR image."; - media_pixel_format_ = olive::PIX_FMT_RGBA16; - } - - const char* chosen_format = av_get_pix_fmt_name(pix_fmt); - snprintf(filter_args, sizeof(filter_args), "pix_fmts=%s", chosen_format); - - AVFilterContext* format_conv; - avfilter_graph_create_filter(&format_conv, avfilter_get_by_name("format"), "fmt", filter_args, nullptr, filter_graph); - avfilter_link(last_filter, 0, format_conv, 0); - - avfilter_link(format_conv, 0, buffersink_ctx, 0); - - avfilter_graph_config(filter_graph, nullptr); - - } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - if (codecCtx->channel_layout == 0) codecCtx->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); - - // set up cache - queue_.append(av_frame_alloc()); - - if (true) { - AVFrame* reverse_frame = av_frame_alloc(); - - reverse_frame->format = kDestSampleFmt; - reverse_frame->nb_samples = current_audio_freq()*10; - reverse_frame->channel_layout = clip->track()->sequence()->audio_layout(); - reverse_frame->channels = av_get_channel_layout_nb_channels(clip->track()->sequence()->audio_layout()); - av_frame_get_buffer(reverse_frame, 0); - - queue_.append(reverse_frame); - } - - snprintf(filter_args, sizeof(filter_args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%" PRIx64, - stream->time_base.num, - stream->time_base.den, - stream->codecpar->sample_rate, - av_get_sample_fmt_name(codecCtx->sample_fmt), - codecCtx->channel_layout - ); - - avfilter_graph_create_filter(&buffersrc_ctx, avfilter_get_by_name("abuffer"), "in", filter_args, nullptr, filter_graph); - avfilter_graph_create_filter(&buffersink_ctx, avfilter_get_by_name("abuffersink"), "out", nullptr, nullptr, filter_graph); - - enum AVSampleFormat sample_fmts[] = { kDestSampleFmt, static_cast(-1) }; - if (av_opt_set_int_list(buffersink_ctx, "sample_fmts", sample_fmts, -1, AV_OPT_SEARCH_CHILDREN) < 0) { - qCritical() << "Could not set output sample format"; - } - - int64_t channel_layouts[] = { AV_CH_LAYOUT_STEREO, static_cast(-1) }; - if (av_opt_set_int_list(buffersink_ctx, "channel_layouts", channel_layouts, -1, AV_OPT_SEARCH_CHILDREN) < 0) { - qCritical() << "Could not set output sample format"; - } - - int target_sample_rate = current_audio_freq(); - - double playback_speed_ = clip->speed().value * m->speed; - - if (qFuzzyCompare(playback_speed_, 1.0)) { - avfilter_link(buffersrc_ctx, 0, buffersink_ctx, 0); - } else if (clip->speed().maintain_audio_pitch) { - AVFilterContext* previous_filter = buffersrc_ctx; - AVFilterContext* last_filter = buffersrc_ctx; - - char speed_param[10]; - - double base = (playback_speed_ > 1.0) ? 2.0 : 0.5; - - double speedlog = log(playback_speed_) / log(base); - int whole2 = qFloor(speedlog); - speedlog -= whole2; - - if (whole2 > 0) { - snprintf(speed_param, sizeof(speed_param), "%f", base); - for (int i=0;itrack(); - - is_valid_state_ = true; -} - -void Cacher::CacheWorker() { - if (clip->type() == olive::kTypeVideo) { - // clip is a video track, start caching video - CacheVideoWorker(); - } else { - // clip is audio - CacheAudioWorker(); - } -} - -void Cacher::CloseWorker() { - retrieved_frame = nullptr; - queue_.lock(); - queue_.clear(); - queue_.unlock(); - - if (frame_ != nullptr) { - av_frame_free(&frame_); - frame_ = nullptr; - } - - if (pkt != nullptr) { - av_packet_free(&pkt); - pkt = nullptr; - } - - if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - if (filter_graph != nullptr) { - avfilter_graph_free(&filter_graph); - filter_graph = nullptr; - } - - if (codecCtx != nullptr) { - avcodec_close(codecCtx); - avcodec_free_context(&codecCtx); - codecCtx = nullptr; - } - - if (opts != nullptr) { - av_dict_free(&opts); - } - - // protection for get_timebase() - stream = nullptr; - - if (formatCtx != nullptr) { - avformat_close_input(&formatCtx); - } - } - - qInfo() << "Clip closed on track" << clip->track(); -} - -void Cacher::run() { - clip->cache_lock.lock(); - - OpenWorker(); - - clip->state_change_lock.unlock(); - - while (caching_) { - if (!queued_) { - wait_cond_.wait(&clip->cache_lock); - } - queued_ = false; - if (!caching_) { - break; - } else if (is_valid_state_) { - CacheWorker(); - } else { - // main thread waits until cacher starts fully, but the cacher can't run, so we just wake it up here - WakeMainThread(); - } - } - - is_valid_state_ = false; - - CloseWorker(); - - clip->state_change_lock.unlock(); - - clip->cache_lock.unlock(); -} - -void Cacher::Open() -{ - wait(); - - // set variable defaults for caching - caching_ = true; - queued_ = false; - - start((clip->type() == olive::kTypeVideo) ? QThread::HighPriority : QThread::TimeCriticalPriority); -} - -void Cacher::Cache(long playhead, bool scrubbing, QVector& nests, int playback_speed) -{ - - if (!is_valid_state_) { - return; - } - - if (clip->media_stream() != nullptr - && queue_.size() > 0 - && clip->media_stream()->infinite_length) { - retrieved_frame = queue_.at(0); - return; - } - - playhead_ = playhead; - nests_ = nests; - scrubbing_ = scrubbing; - playback_speed_ = playback_speed; - queued_ = true; - - bool wait_for_cacher_to_respond = true; - - if (clip->media() != nullptr) { - // see if we already have this frame - retrieve_lock_.lock(); - queue_.lock(); - retrieved_frame = nullptr; - int64_t target_pts = seconds_to_timestamp(clip, playhead_to_clip_seconds(clip, playhead_)); - for (int i=0;ipts == target_pts) { - - // the queue has a frame with the exact timestamp - - retrieved_frame = queue_.at(i); - wait_for_cacher_to_respond = false; - break; - } else if (i > 0 && queue_.at(i-1)->pts < target_pts && queue_.at(i)->pts > target_pts) { - - // the queue has a frame with a close timestamp that we'll assume is different due to a rounding error - - retrieved_frame = queue_.at(i-1); - wait_for_cacher_to_respond = false; - break; - } - } - queue_.unlock(); - retrieve_lock_.unlock(); - } - - if (wait_for_cacher_to_respond) { - main_thread_lock_.lock(); - } - - // wake up cacher - wait_cond_.wakeAll(); - - // if not, wait for cacher to respond - if (wait_for_cacher_to_respond) { - interrupt_ = true; - main_thread_wait_.wait(&main_thread_lock_, 2000); - } - - if (wait_for_cacher_to_respond) { - main_thread_lock_.unlock(); - } -} - -AVFrame *Cacher::Retrieve() -{ - if (!caching_) { - return nullptr; - } - - // for thread-safety, we lock a mutex to ensure this thread is never woken by anything out of sync - - retrieve_lock_.lock(); - - // check if there's a frame ready to be shown by the cacher - - if (retrieved_frame == nullptr) { - // wait for cacher to finish caching - - - if (clip->cache_lock.tryLock()) { - - // If the queue could lock, the cacher isn't running which means no frame is coming. This is an error. - qCritical() << "Cacher frame was null while the cacher wasn't running on clip" << clip->name(); - clip->cache_lock.unlock(); - - } else { - - // cacher is running, wait for it to give a frame - retrieve_wait_.wait(&retrieve_lock_); - - } - - } - - retrieve_lock_.unlock(); - - return retrieved_frame; -} - -void Cacher::Close(bool wait_for_finish) -{ - caching_ = false; - wait_cond_.wakeAll(); - - if (wait_for_finish) { - wait(); - } -} - -void Cacher::ResetAudio() -{ - // using audio_write_lock seems like a good idea, but hasn't been tested yet. If there are audio issues when seeking, - // try uncommenting them - -// audio_write_lock.lock(); - audio_reset_ = true; - frame_sample_index_ = -1; - audio_buffer_write = 0; -// audio_write_lock.unlock(); -} - -int Cacher::media_width() -{ - return stream->codecpar->width; -} - -int Cacher::media_height() -{ - return stream->codecpar->height; -} - -AVRational Cacher::media_time_base() -{ - return stream->time_base; -} - -ClipQueue *Cacher::queue() -{ - return &queue_; -} - -const olive::PixelFormat &Cacher::media_pixel_format() -{ - return media_pixel_format_; -} - -int Cacher::RetrieveFrameFromDecoder(AVFrame* f) { - int result = 0; - int receive_ret; - - // do we need to retrieve a new packet for a new frame? - av_frame_unref(f); - while ((receive_ret = avcodec_receive_frame(codecCtx, f)) == AVERROR(EAGAIN)) { - int read_ret = 0; - do { - if (pkt->buf != nullptr) { - av_packet_unref(pkt); - } - read_ret = av_read_frame(formatCtx, pkt); - } while (read_ret >= 0 && pkt->stream_index != clip->media_stream_index()); - - if (read_ret >= 0) { - int send_ret = avcodec_send_packet(codecCtx, pkt); - if (send_ret < 0) { - qCritical() << "Failed to send packet to decoder." << send_ret; - return send_ret; - } - } else { - if (read_ret == AVERROR_EOF) { - int send_ret = avcodec_send_packet(codecCtx, nullptr); - if (send_ret < 0) { - qCritical() << "Failed to send packet to decoder." << send_ret; - return send_ret; - } - } else { - qCritical() << "Could not read frame." << read_ret; - return read_ret; // skips trying to find a frame at all - } - } - } - if (receive_ret < 0) { - if (receive_ret != AVERROR_EOF) qCritical() << "Failed to receive packet from decoder." << receive_ret; - result = receive_ret; - } - - return result; -} - -int Cacher::RetrieveFrameAndProcess(AVFrame **f) -{ - // error codes from FFmpeg - int retrieve_code, read_code, send_code; - - // frame for FFmpeg to decode into - *f = av_frame_alloc(); - - // loop to pull frames from the AVFilter stack - while ((retrieve_code = av_buffersink_get_frame(buffersink_ctx, *f)) == AVERROR(EAGAIN)) { - - // retrieve frame from decoder - read_code = RetrieveFrameFromDecoder(frame_); - - if (read_code >= 0) { - - // we retrieved a decoded video frame, which we will send to the AVFilter stack to convert to RGBA (with other - // adjustments if necessary) - - if ((send_code = av_buffersrc_add_frame_flags(buffersrc_ctx, frame_, AV_BUFFERSRC_FLAG_KEEP_REF)) < 0) { - qCritical() << "Failed to add frame to buffer source." << send_code; - break; - } - - // we don't need the original frame to we free it here - av_frame_unref(frame_); - - } else { - - // AVERROR_EOF means we've reached the end of the file, not technically an error, but it's useful to know that - // there are no more frames in this file - if (read_code != AVERROR_EOF) { - qCritical() << "Failed to read frame." << read_code; - } - break; - } - } - - if (read_code == AVERROR_EOF) { - return AVERROR_EOF; - } - return retrieve_code; -} diff --git a/rendering/cacher.h b/rendering/cacher.h deleted file mode 100644 index c6e17424a..000000000 --- a/rendering/cacher.h +++ /dev/null @@ -1,602 +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 CACHER_H -#define CACHER_H - -#define __STDC_FORMAT_MACROS 1 -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include -} - -#include -#include -#include -#include -#include - -#include "rendering/clipqueue.h" -#include "rendering/pixelformats.h" - -class Clip; - -/** - * @brief The Cacher class - * - * For footage clips - usually the majority of clips - decoding can be strenuous on CPU and inconsistent in timing. As - * a result, we keep a memory cache of upcoming frames that we fill in a background thread so they can be retrieved from - * a rendering thread later. This class is the background thread filling up a clip's frame cache (also called a "queue" - * since video files are usually stored with frames in linear chronological order). It involves decoding routines to - * retrieve raw frames from the file (using libavformat/libavcodec), conversion routines to conform the raw frames to - * RGBA/S16LE for the rest of the workflow (using libavfilter/libswscale/libswresample), and memory handling routines - * for keeping the cache within limits defined by the user (see Config::upcoming_queue_type). - * - * Generally the Cacher workflow starts by calling Open() which will start the thread, open a file handle, and create a - * decoding instance. Open() is usually called directly from the parent Clip's Clip::Open() and thus expects the - * Clip::state_change_lock to be locked. It will unlock it when it's finished opening and is ready to start caching, - * meaning Clip::state_change_lock can be used to synchronize threads. - * - * --- - * - * **For video:** - * - * After the Cacher has finished opening, request a frame by calling Cache(). Cache() will tell the Cacher - * information about the current playback state, most importantly the current place in time according to the Sequence's - * playhead. Cache() determines whether the requested frame is already in the queue, and then signals the Cacher thread - * to cache ahead if there's room in the queue (and also remove old frames that are no longer necessary). To retrieve - * the requested frame, call Retrieve(). - * - * If Cache() found the frame already in the queue, Retrieve() will return immediately with this frame. Otherwise - * Retrieve() may block while the cacher retrieves it. Therefore it is recommended never to call Retrieve() from - * the main thread. Retrieve() may also return `nullptr` if there was an issue, e.g. the cacher failed to retrieve - * the frame. - * - * **For audio:** - * - * After the Cacher has finished opening, calling Cache() will handle most of the work. It will decode the audio, - * convert to the correct sample rate and format, reverse or adjust speed if necessary, and send it to the audio - * buffer ready to be played by the output device. It is important to continually call Cache() as it doesn't get - * signalled when more samples are available in the audio buffer. Instead, it'll check every time it's called and - * fill as much of the buffer as it can. - * - * If the user seeks, ResetAudio() must be called to signal the Cacher to interrupt the current audio stream and - * move somewhere else before continuing. - * - * --- - * - * Finally, when the Cacher/parent Clip are no longer in use, call Close() to free all memory and file handling - * allocated for the cacher. You can choose whether to wait for Close() and all of its child processes to complete - - * e.g. if you need to change something with the Clip or attached Footage that changes how it opens and want to be - * thread-safe - or let the Close thread finish up on its own. - * - * Cacher expects to be multithreaded and all of its public functions are thread-safe. - */ -class Cacher : public QThread -{ - Q_OBJECT -public: - /** - * @brief Cacher Constructor - * - * Create Cacher object. The thread is not started here. To start it, call Open(). - * - * @param c - */ - Cacher(Clip* c); - - /** - * @brief The main QThread loop - * - * Once the thread has started, all Cacher functions will be called from here until the Cacher closes at which point - * it will close and exit gracefully. - */ - void run(); - - /** - * @brief Open the cacher - * - * Starts the thread and all file/decode handlers. Really just sets some default values and starts the thread, which - * will in turn call OpenWorker() at the start of its functions. - * - * Make sure Clip::state_change_lock is LOCKED before calling this function as the opening process will try to unlock - * it when it's finished (leading to a crash if it's not already locked). - */ - void Open(); - - /** - * @brief Request a frame to be cached - * - * For video, this function is part 1 of the Cache()/Retrieve() workflow. It signals the thread to start caching and - * provides a few other details about the playback state. For optimization it'll also check the frame queue if it - * already contains the requested frame and use it if so, potentially speeding up Retrieve() later on. Otherwise - * it'll interrupt any currently caching operation and signal it to start again. - * While Retrieve() will block until the correct frame is retrieved, this function will return fairly quickly (either - * immediately if the frame was found in the queue, or once the cacher has restarted caching if not). This means - * Cache() can be called from another thread and then that other thread can do other work while the cacher is - * retrieving the frame, finally calling Retrieve() once the frame is absolutely necessary. - * - * For audio, this function will do all the work of signalling the thread to start caching and sending samples to - * the output audio buffer. It's used in tandem with ResetAudio() when the Timeline header is changed abruptly. - * - * @param playhead - * - * The current Timeline played position in frames - * - * @param scrubbing - * - * **TRUE** if the user is currently scrubbing. **FALSE** if not. - * - * @param nests - * - * A hierarchy of nested sequences, if the playback traversed any to get to this clip. - * - * @param playback_speed - * - * The current playback speed (controlled by Shuttle Left/Stop/Right) - */ - void Cache(long playhead, bool scrubbing, QVector& nests, int playback_speed); - - /** - * @brief Retrieve frame requested by Cache() - * - * Part 2 of the Cache()/Retrieve() workflow, only used for video. Whichever frame was requested by Cache(), this - * function will try to retrieve it. In most cases, this function will be pretty quick as the frame will be available - * immediately from Cache()'s optimization or the cacher thread will be close to retrieving the correct frame anyway. - * However it does block for however long it takes to retrieve the correct frame (if the cacher is running) so it's - * not recommended to call this from any main/GUI thread. - * - * @return - * - * The frame requested by Cache(), or `nullptr` if there was an error (e.g. the cacher wasn't running and no frame was - * available). - */ - AVFrame* Retrieve(); - - /** - * @brief Close the cacher and free any allocated memory - * - * When the Cacher thread is no longer needed, Close() should be called in order to free system resources. This will - * signal the thread to exit gracefully, but will not delete the thread object since the cacher may need to be - * re-opened later by Open(). - * - * @param wait_for_finish - * - * **TRUE** if this function should block the calling thread until the Clip has finished closing. Often necessary if - * the Clip is being closed specifically to make changes to it. - */ - void Close(bool wait_for_finish); - - /** - * @brief Interrupt and reset audio state - * - * Used in tandem with Cache(), only for audio clips. Cache() will decode and send audio continually as it's - * repeatedly called. If the audio stream needs to be interrupted and moved somewhere else for any reason - * (e.g. the user seeked somewhere else), then it's necessary to call ResetAudio() to signal the cacher to - * seek to the next place indicated by Cache(). - */ - void ResetAudio(); - - /** - * @brief Retrieve current media width - * - * In some situations, the actual media we're using may be a different resolution to how we're treating it (e.g. - * lower resolution proxies). While most functions will happily treat the media as its original resolution, some - * processes will need the absolute resolution from the file which can be acquired here. - * - * Only call after the thread has been opened by Open(). - * - * @return - * - * The true width of the current video file. - */ - int media_width(); - - /** - * @brief Retrieve current media height - * - * See media_width(). - * - * Only call after the thread has been opened by Open(). - * - * @return - * - * The true height of the current video file. - */ - int media_height(); - - /** - * @brief Retrieve media time base - * - * For some timing operations, it's necessary to use the source media's timebase. Similar to media_width() and - * media_height(), we need the accurate timebase from the file as a proxy's timebase may or may not be the same - * as the source file. - * - * Only call after the thread has been opened by Open(). - * - * @return - * - * The timebase of the file. - */ - AVRational media_time_base(); - - /** - * @brief Get cacher queue object - * - * @return - * - * A pointer to the cacher's internal frame queue - */ - ClipQueue* queue(); - - /** - * @brief Retrieve OpenGL information about this media's bit depth - * - * @return - * - * A olive::rendering::PixelFormat value corresponding to a member of olive::rendering::bit_depths. - */ - const olive::PixelFormat& media_pixel_format(); - -private: - /** - * @brief Reference to the parent clip. Set in the constructor and never changed during this object's lifetime. - */ - Clip* clip; - - /** - * @brief Frame queue - * - * Valid fames are cached into this, which also does memory handling when necessary. - */ - ClipQueue queue_; - - /** - * @brief Main wait condition - * - * Used with Clip::cache_lock as the main block while the the Cacher thread isn't running. Wake this condition - * to start caching. - */ - QWaitCondition wait_cond_; - - /** - * @brief Main thread wait condition - * - * Used with main_thread_lock_ to block Cache() while waiting for a response from the cacher thread. - */ - QWaitCondition main_thread_wait_; - - /** - * @brief Main thread mutex - * - * Used with main_thread_wait_ to block Cache() while waiting for a response from the cacher thread. - */ - QMutex main_thread_lock_; - - /** - * @brief Retrieve() wait condition - * - * Used with retrieve_lock_ to block Retrieve() if the cacher hasn't retrieved the correct frame yet. - */ - QWaitCondition retrieve_wait_; - - /** - * @brief Retrieve() mutex - * - * Used with retrieve_wait_ to block Retrieve() if the cacher hasn't retrieved the correct frame yet. - */ - QMutex retrieve_lock_; - - /** - * @brief Set and used by CacheAudioWorker if the decoder receives an EOF. - * - * Deprecated. CacheAudioWorker() is functional but probably should be rewritten. - */ - bool reached_end; - - /** - * @brief Current Sequence playhead set by Cache() - */ - long playhead_; - - /** - * @brief Current Sequence scrubbing state set by Cache() - */ - bool scrubbing_; - - /** - * @brief Current Sequence playback speed set by Cache() - */ - int playback_speed_; - - /** - * @brief Current nested Sequence hierarchy set by Cache() - */ - QVector nests_; - - /** - * @brief Signal cache to continue operation after one cycle rather than wait for another signal - * - * Each cycle of the cacher thread (see run()) will set this to false in the beginning. Each call of Cache() will set - * this to **TRUE**. If this variable is **TRUE**, the cacher won't wait for another signal before starting the next - * cache cycle, and will instead just start it. - * - * Used if Cache() is called and interrupts the cacher while it's already running so that the cacher will restart - * itself automatically rather than wait for the next cache signal. - */ - bool queued_; - - /** - * @brief Interrupt the current cache cycle - * - * A cache cycle will cache several frames at a time. Since decoding can be strenuous and time consuming, the - * cycle can be interrupted if it needs to abruptly start caching somewhere else. Best used in tandem with - * queued_ to automatically start the next cache cycle. - */ - bool interrupt_; - - // ffmpeg media handling - /** - * @brief FFmpeg format/file context - used for media decoding - */ - AVFormatContext* formatCtx; - - /** - * @brief FFmpeg decoder context - used for media decoding - */ - AVCodecContext* codecCtx; - - /** - * @brief FFmpeg stream - used for media decoding - */ - AVStream* stream; - - /** - * @brief FFmpeg packet - used for media decoding - */ - AVPacket* pkt; - - /** - * @brief FFmpeg frame - used for media decoding - * - * This is usually used as a raw decoded frame before the RGBA conversion/AVFilter stack. Converted/filtered frames go - * into Cacher::queue. - */ - AVFrame* frame_; - - /** - * @brief Retrieved frame reference for Retrieve() - * - * If a frame was found by either Cache() or CacheVideoWorker(), it's set here. If no frame is ready yet, this is set - * to `nullptr`. - */ - AVFrame* retrieved_frame = nullptr; - - // converters/filters - /** - * @brief FFmpeg filter stack - * - * Used for conversion from the media's pixel format to RGBA for OpenGL. Also any other FFmpeg filters are implemented - * here if necessary (e.g. yadif for deinterlacing). GLSL effects are preferred when available since FFmpeg filters - * aren't always fast enough for realtime playback. - */ - AVFilterGraph* filter_graph; - - /** - * @brief FFmpeg buffer source - * - * Raw decoded frames are added to this for conversion/filtering - */ - AVFilterContext* buffersrc_ctx; - - /** - * @brief FFmpeg buffer sink - * - * Converted/filtered frames are retrieved from here and sent to Cacher::queue. - */ - AVFilterContext* buffersink_ctx; - - /** - * @brief FFmpeg codec reference - */ - AVCodec* codec; - - /** - * @brief Options set by the cacher for FFmpeg's decoders (settings like multithreading or other optimizations) - */ - AVDictionary* opts; - - // audio playback variables - /** - * @brief Internal audio reset variable - * - * Set by AudioReset() and read by CacheAudioWorker() when the audio state needs to be interrupted and reset. - */ - bool audio_reset_; - - /** - * @brief Internal reverse target variable - * - * Used by CacheAudioWorker() to stitch audio frames together when reversing. Stores the current frame's timestamp - * so it knows how much to decode up to when it backtracks and decodes the next samples. - */ - int64_t reverse_target_; - - /** - * @brief Internal frame sample index variable - * - * Used by CacheAudioWorker() to mark which part of the audio frame to read from - */ - int frame_sample_index_; - - /** - * @brief Internal audio buffer write variable - * - * Used by CacheAudioWorker() to mark which part of the audio buffer to write to - */ - qint64 audio_buffer_write; - - /** - * @brief Internal variable that holds the playhead the last time the audio state was reset - */ - long audio_target_frame; - - /** - * @brief Main while loop condition to determine whether thread should continue looping - * - * Open() sets this to **TRUE**, Close() sets this to **FALSE**. If it's false, the main loop in run() will exit and - * the thread will exit cleanly. It's not recommended to set this variable directly, use Open() and Close() instead. - */ - bool caching_; - - /** - * @brief Internal variable for whether the current Cacher state is valid or not - * - * If there was an error opening the Cacher for any reason, this will be false. - */ - bool is_valid_state_; - - /** - * @brief Internal function for opening the file handles and decoder - * - * After the thread has started, it'll call this function to start all resources necessary for caching. Any - * FFmpeg decoding variables and filters are set up here. - * - * This is - * fundamentally different from Open(), this is only meant to be called within the cacher thread and never from - * outside and doesn't start the thread like Open() does. - */ - void OpenWorker(); - - /** - * @brief Internal function for starting a cache cycle - * - * This used to have more function, but now just differentiates between CacheVideoWorker() for video clips and - * CacheAudioWorker() for audio clips. - */ - void CacheWorker(); - - /** - * @brief Internal function for closing cacher - * - * Called if the main thread loop in run() exits by setting caching_ to **FALSE**. Free's up handles and memory - * allocated by OpenWorker(). - */ - void CloseWorker(); - - /** - * @brief Internal function for resetting audio state - * - * This used to be a common function, but is now simply a legacy function for CacheAudioWorker(). Resets and - * flushes decoders and seeks to the correct timestamp. - */ - void Reset(); - - /** - * @brief Internal function for setting retrieved_frame and waking up any threads waiting for it - * - * @param f - * - * The frame to set as the retrieved frame. - */ - void SetRetrievedFrame(AVFrame* f); - - /** - * @brief Internal function to wake an external calling thread - * - * In some situations, Cache() may wait for the cacher to respond before returning. This is to assist in thread - * synchronization, making sure the cacher has started working and has locked any resources it needs before any - * other threads can access them (e.g. with a function like Retrieve() ). This must be called at the start of - * any CacheVideoWorker() or CacheAudioWorker() control paths to ensure the render thread doesn't get stuck. - */ - void WakeMainThread(); - - /** - * @brief Retrieve frame from decoder - * - * Retrieves the next decoded frame from the decoder. Depending on the source media, this frame may or may not be - * suitable for usage later in the pipeline as it may or may not be the correct pixel/sample format. For a suitable - * frame for the pipeline, use RetrieveFrameAndProcess() instead (which in turn uses this function anyway). - * - * @param f - * - * Frame buffer to decode frame into - * - * @return - * - * FFmpeg error code (>= 0 on success, a negative error code on failure) - */ - int RetrieveFrameFromDecoder(AVFrame* f); - - /** - * @brief Retrieve frame from decoder and run it through filter stack - * - * Retrieves the next decoded frame and runs it through the AVFilter stack to create an RGBA frame compatible with - * the rest of the pipeline and OpenGL. Use this function if you need a ready-made frame. - * - * @param f - * - * A pointer to an AVFrame object. It does not need to be allocated, as this function allocates an AVFrame itself. - * You'll also need to free it later with av_frame_free() (though ClipQueue will do this automatically if the frame is - * added to it). - * - * @return - * - * FFmpeg error code (>= 0 on success, a negative error code on failure) - */ - int RetrieveFrameAndProcess(AVFrame **f); - - /** - * @brief Internal video caching function - * - * Performs one video cache cycle. Seeks the media and cleans old frames from the queue if necessary. Decodes frames - * and adds them to the queue (after calculating whether they're necessary). - */ - void CacheVideoWorker(); - - /** - * @brief Internal audio caching function - * - * Perform one audio cache cycle. Retrieves audio from decoder, reverses and changes speed if necessary, and sends - * audio to the audio buffer which will later be sent to the audio output device. - */ - void CacheAudioWorker(); - - /** - * @brief Internal function using the Cacher's known information to determine whether this media is playing in reverse - */ - bool IsReversed(); - - /** - * @brief Internal struct holding bit depth information for the current media - */ - olive::PixelFormat media_pixel_format_; -}; - -#endif // CACHER_H diff --git a/rendering/clipqueue.cpp b/rendering/clipqueue.cpp deleted file mode 100644 index 031ac402d..000000000 --- a/rendering/clipqueue.cpp +++ /dev/null @@ -1,105 +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 "clipqueue.h" - - -ClipQueue::ClipQueue() -{ - -} - -ClipQueue::~ClipQueue() -{ - clear(); -} - -void ClipQueue::lock() -{ - queue_lock.lock(); -} - -bool ClipQueue::tryLock() -{ - return queue_lock.tryLock(); -} - -void ClipQueue::unlock() -{ - queue_lock.unlock(); -} - -void ClipQueue::append(AVFrame *frame) -{ - queue.append(frame); -} - -AVFrame *ClipQueue::at(int i) -{ - return queue.at(i); -} - -AVFrame *ClipQueue::first() -{ - return queue.first(); -} - -AVFrame *ClipQueue::last() -{ - return queue.last(); -} - -void ClipQueue::removeFirst() -{ - removeAt(0); -} - -void ClipQueue::removeLast() -{ - removeAt(queue.size()-1); -} - -void ClipQueue::removeAt(int i) -{ - av_frame_free(&queue[i]); - queue.removeAt(i); -} - -void ClipQueue::clear() -{ - while (queue.size() > 0) { - removeAt(0); - } -} - -int ClipQueue::size() -{ - return queue.size(); -} - -bool ClipQueue::isEmpty() -{ - return queue.isEmpty(); -} - -bool ClipQueue::contains(AVFrame *frame) -{ - return queue.contains(frame); -} diff --git a/rendering/clipqueue.h b/rendering/clipqueue.h deleted file mode 100644 index 91d3649e7..000000000 --- a/rendering/clipqueue.h +++ /dev/null @@ -1,185 +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 CLIPQUEUE_H -#define CLIPQUEUE_H - -extern "C" { -#include -} - -#include -#include - -/** - * @brief The ClipQueue class - * - * A fairly simple wrapper for a QVector and QMutex that cleans up AVFrames automatically when removing them. - */ -class ClipQueue { -public: - /** - * @brief ClipQueue Constructor - */ - ClipQueue(); - - /** - * @brief ClipQueue Destructor - * - * Automatically clears queue freeing any memory consumed by any AVFrames - */ - ~ClipQueue(); - - // Thread safety (QMutex compatible) - /** - * @brief Lock queue mutex - * - * Used for multithreading to ensure queue is only accessed by one thread at a time. See QMutex::lock() for more - * information. - */ - void lock(); - - /** - * @brief Try to lock queue mutex - * - * Used for multithreading to ensure queue is only accessed by one thread at a time. Tries to lock, but doesn't block - * the calling thread and wait if it can't lock it. See QMutex::tryLock() for more information. - * - * @return - * - * **TRUE** if the lock succeeded, **FALSE** if not. - */ - bool tryLock(); - - /** - * @brief Unlock queue mutex - * - * Used for multithreading to ensure queue is only accessed by one thread at a time. See QMutex::unlock() for more - * information. - */ - void unlock(); - - // Array handling (QVector compatible) - /** - * @brief Add a frame to the end of the queue - * - * @param frame - * - * The frame to add - */ - void append(AVFrame* frame); - - /** - * @brief Retrieve a frame at a certain index - * - * @param i - * - * Index to retrieve frame from - * - * @return - * - * AVFrame at this index - */ - AVFrame* at(int i); - - /** - * @brief Retrieve first frame in the queue - * - * @return - * - * The first AVFrame in the queue - */ - AVFrame* first(); - - /** - * @brief Retrieve last frame in the queue - * - * @return - * - * The last AVFrame in the queue - */ - AVFrame* last(); - - /** - * @brief Remove first frame in the queue - * - * Frees all memory occupied by this frame and removes it from the queue - */ - void removeFirst(); - - /** - * @brief Remove last frame in the queue - * - * Frees all memory occupied by this frame and removes it from the queue - */ - void removeLast(); - - /** - * @brief Remove frame in the queue at a certain index - * - * Frees all memory occupied by this frame and removes it from the queue - * - * @param i - * - * Index to remove a frame at - */ - void removeAt(int i); - - /** - * @brief Clear entire queue - * - * Frees all memory occupied by all frames and clears the entire queue - */ - void clear(); - - /** - * @brief Retrieve current size of the queue - * - * @return - * - * Current the current size of the queue. All indexes in the queue are guaranteed to be valid references to an - * AVFrame. - */ - int size(); - - /** - * @brief Returns whether the queue is empty of not. - * - * @return - * - * **TRUE** if the queue is empty and contains no frames, **FALSE** if not. - */ - bool isEmpty(); - - /** - * @brief Returns whether the queue contains a frame or not - * - * @return - * - * **TRUE** if the queue contains the specified frame, **FALSE** if not. - */ - bool contains(AVFrame* frame); - -private: - QVector queue; - QMutex queue_lock; -}; - -#endif // CLIPQUEUE_H diff --git a/rendering/exportthread.cpp b/rendering/exportthread.cpp deleted file mode 100644 index bd8d3edcd..000000000 --- a/rendering/exportthread.cpp +++ /dev/null @@ -1,705 +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 "exportthread.h" - -extern "C" { -#include -#include -#include -#include -} - -#include -#include -#include -#include -#include - -#include "global/global.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, - QObject *parent) : - QThread(parent), - params_(params), - vcodec_params_(vparams), - interrupt_(false), - fmt_ctx(nullptr), - video_stream(nullptr), - vcodec(nullptr), - vcodec_ctx(nullptr), - video_frame(nullptr), - sws_ctx(nullptr), - audio_stream(nullptr), - acodec(nullptr), - audio_frame(nullptr), - sws_frame(nullptr), - swr_frame(nullptr), - acodec_ctx(nullptr), - swr_ctx(nullptr), - vpkt_alloc(false), - apkt_alloc(false), - c_filename(nullptr) -{ - // Create offscreen surface for rendering while exporting - surface.create(); -} - -bool ExportThread::Encode(AVFormatContext* ofmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream) { - ret = avcodec_send_frame(codec_ctx, frame); - if (ret < 0) { - qCritical() << "Failed to send frame to encoder." << ret; - export_error = tr("failed to send frame to encoder (%1)").arg(QString::number(ret)); - return false; - } - - while (ret >= 0) { - ret = avcodec_receive_packet(codec_ctx, packet); - if (ret == AVERROR(EAGAIN)) { - return true; - } else if (ret < 0) { - if (ret != AVERROR_EOF) { - qCritical() << "Failed to receive packet from encoder." << ret; - export_error = tr("failed to receive packet from encoder (%1)").arg(QString::number(ret)); - } - return false; - } - - packet->stream_index = stream->index; - - av_packet_rescale_ts(packet, codec_ctx->time_base, stream->time_base); - - av_interleaved_write_frame(ofmt_ctx, packet); - av_packet_unref(packet); - } - return true; -} - -bool ExportThread::SetupVideo() { - // if video is disabled, no setup necessary - if (!params_.video_enabled) return true; - - // find video encoder - vcodec = avcodec_find_encoder(static_cast(params_.video_codec)); - if (!vcodec) { - qCritical() << "Could not find video encoder"; - export_error = tr("could not video encoder for %1").arg(QString::number(params_.video_codec)); - return false; - } - - // create video stream - video_stream = avformat_new_stream(fmt_ctx, vcodec); - video_stream->id = 0; - if (!video_stream) { - qCritical() << "Could not allocate video stream"; - export_error = tr("could not allocate video stream"); - return false; - } - - // allocate context - // vcodec_ctx = video_stream->codec; - vcodec_ctx = avcodec_alloc_context3(vcodec); - if (!vcodec_ctx) { - qCritical() << "Could not allocate video encoding context"; - export_error = tr("could not allocate video encoding context"); - return false; - } - - // setup context - vcodec_ctx->codec_id = static_cast(params_.video_codec); - vcodec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; - vcodec_ctx->width = params_.video_width; - vcodec_ctx->height = params_.video_height; - vcodec_ctx->sample_aspect_ratio = {1, 1}; - vcodec_ctx->pix_fmt = static_cast(vcodec_params_.pix_fmt); - vcodec_ctx->framerate = av_d2q(params_.video_frame_rate, INT_MAX); - if (params_.video_compression_type == COMPRESSION_TYPE_CBR) { - vcodec_ctx->bit_rate = qRound(params_.video_bitrate * 1000000); - } - vcodec_ctx->time_base = av_inv_q(vcodec_ctx->framerate); - video_stream->time_base = vcodec_ctx->time_base; - - if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { - vcodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - } - - // Some codecs require special settings so we set that up here - switch (vcodec_ctx->codec_id) { - - /// H.264 specific settings - case AV_CODEC_ID_H264: - case AV_CODEC_ID_H265: - switch (params_.video_compression_type) { - case COMPRESSION_TYPE_CFR: - av_opt_set(vcodec_ctx->priv_data, "crf", QString::number(static_cast(params_.video_bitrate)).toUtf8(), AV_OPT_SEARCH_CHILDREN); - break; - } - break; - default: - break; - } - - // Set export to be multithreaded - AVDictionary* opts = nullptr; - if (vcodec_params_.threads == 0) { - av_dict_set(&opts, "threads", "auto", 0); - } else { - av_dict_set(&opts, "threads", QString::number(vcodec_params_.threads).toUtf8(), 0); - } - - // Open video encoder - ret = avcodec_open2(vcodec_ctx, vcodec, &opts); - if (ret < 0) { - qCritical() << "Could not open output video encoder." << ret; - export_error = tr("could not open output video encoder (%1)").arg(QString::number(ret)); - return false; - } - - // Copy video encoder parameters to output stream - ret = avcodec_parameters_from_context(video_stream->codecpar, vcodec_ctx); - if (ret < 0) { - qCritical() << "Could not copy video encoder parameters to output stream." << ret; - export_error = tr("could not copy video encoder parameters to output stream (%1)").arg(QString::number(ret)); - return false; - } - - // Create raw AVFrame that will contain the RGBA buffer straight from compositing - video_frame = av_frame_alloc(); - av_frame_make_writable(video_frame); - video_frame->format = AV_PIX_FMT_RGBA; - video_frame->width = params_.sequence->width(); - video_frame->height = params_.sequence->height(); - av_frame_get_buffer(video_frame, 0); - - av_init_packet(&video_pkt); - - // Set up conversion context - sws_ctx = sws_getContext( - params_.sequence->width(), - params_.sequence->height(), - AV_PIX_FMT_RGBA, - params_.video_width, - params_.video_height, - vcodec_ctx->pix_fmt, - SWS_BILINEAR, - nullptr, - nullptr, - nullptr - ); - - return true; -} - -bool ExportThread::SetupAudio() { - // if video is disabled, no setup necessary - if (!params_.audio_enabled) return true; - - // Find encoder for this codec - acodec = avcodec_find_encoder(static_cast(params_.audio_codec)); - if (!acodec) { - qCritical() << "Could not find audio encoder"; - export_error = tr("could not audio encoder for %1").arg(QString::number(params_.audio_codec)); - return false; - } - - // Allocate audio stream - audio_stream = avformat_new_stream(fmt_ctx, acodec); - if (audio_stream == nullptr) { - qCritical() << "Could not allocate audio stream"; - export_error = tr("could not allocate audio stream"); - return false; - } - - // Set audio stream's ID to 1 - audio_stream->id = 1; - - // set sample rate to use for project - audio_rendering_rate = params_.audio_sampling_rate; - - // Allocate encoding context - acodec_ctx = avcodec_alloc_context3(acodec); - if (!acodec_ctx) { - qCritical() << "Could not find allocate audio encoding context"; - export_error = tr("could not allocate audio encoding context"); - return false; - } - - // Set up encoding context - acodec_ctx->codec_id = static_cast(params_.audio_codec); - acodec_ctx->codec_type = AVMEDIA_TYPE_AUDIO; - acodec_ctx->sample_rate = params_.audio_sampling_rate; - acodec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; // change this to support surround/mono sound in the future (this is what the user sets the output audio to) - acodec_ctx->channels = av_get_channel_layout_nb_channels(acodec_ctx->channel_layout); - acodec_ctx->sample_fmt = acodec->sample_fmts[0]; - acodec_ctx->bit_rate = params_.audio_bitrate * 1000; - - acodec_ctx->time_base.num = 1; - acodec_ctx->time_base.den = params_.audio_sampling_rate; - audio_stream->time_base = acodec_ctx->time_base; - - if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { - acodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - } - - // Open encoder - ret = avcodec_open2(acodec_ctx, acodec, nullptr); - if (ret < 0) { - qCritical() << "Could not open output audio encoder." << ret; - export_error = tr("could not open output audio encoder (%1)").arg(QString::number(ret)); - return false; - } - - // Copy parameters from the codec context (set up above) to the output stream - ret = avcodec_parameters_from_context(audio_stream->codecpar, acodec_ctx); - if (ret < 0) { - qCritical() << "Could not copy audio encoder parameters to output stream." << ret; - export_error = tr("could not copy audio encoder parameters to output stream (%1)").arg(QString::number(ret)); - return false; - } - - // init audio resampler context - swr_ctx = swr_alloc_set_opts( - nullptr, - acodec_ctx->channel_layout, - acodec_ctx->sample_fmt, - acodec_ctx->sample_rate, - params_.sequence->audio_layout(), - AV_SAMPLE_FMT_S16, - acodec_ctx->sample_rate, - 0, - nullptr - ); - swr_init(swr_ctx); - - // initialize raw audio frame - audio_frame = av_frame_alloc(); - audio_frame->sample_rate = acodec_ctx->sample_rate; - audio_frame->nb_samples = acodec_ctx->frame_size; - - if (audio_frame->nb_samples == 0) { - // FIXME: Magic number. I don't know what to put here and truthfully I don't even know if it matters. - audio_frame->nb_samples = 256; - } - - // TODO change this to support surround/mono sound in the future (this is whatever format they're held in the internal buffer) - audio_frame->channel_layout = AV_CH_LAYOUT_STEREO; - - audio_frame->format = AV_SAMPLE_FMT_S16; - audio_frame->channels = av_get_channel_layout_nb_channels(audio_frame->channel_layout); - av_frame_make_writable(audio_frame); - ret = av_frame_get_buffer(audio_frame, 0); - if (ret < 0) { - qCritical() << "Could not allocate audio buffer." << ret; - export_error = tr("could not allocate audio buffer (%1)").arg(QString::number(ret)); - return false; - } - aframe_bytes = av_samples_get_buffer_size(nullptr, audio_frame->channels, audio_frame->nb_samples, static_cast(audio_frame->format), 0); - - av_init_packet(&audio_pkt); - - // init converted audio frame - swr_frame = av_frame_alloc(); - swr_frame->channel_layout = acodec_ctx->channel_layout; - swr_frame->channels = acodec_ctx->channels; - swr_frame->sample_rate = acodec_ctx->sample_rate; - swr_frame->format = acodec_ctx->sample_fmt; - swr_frame->nb_samples = acodec_ctx->frame_size; - av_frame_get_buffer(swr_frame, 0); - - av_frame_make_writable(swr_frame); - - return true; -} - -bool ExportThread::SetupContainer() { - - // Set up output context (using the filename as the format specification) - - avformat_alloc_output_context2(&fmt_ctx, nullptr, nullptr, c_filename); - if (fmt_ctx == nullptr) { - - // Failed to create the output format context. Exit the export and throw an error. - - qCritical() << "Could not create output context"; - export_error = tr("could not create output format context"); - return false; - } - - ret = avio_open(&fmt_ctx->pb, c_filename, AVIO_FLAG_WRITE); - if (ret < 0) { - - // Failed to get a valid write handle for the exported file. Exit the export and throw an error. - - qCritical() << "Could not open output file." << ret; - export_error = tr("could not open output file (%1)").arg(QString::number(ret)); - return false; - } - - return true; -} - -void ExportThread::Export() -{ - // Copy filename from QString to const char - QByteArray ba = params_.filename.toUtf8(); - c_filename = new char[ba.size()+1]; - strcpy(c_filename, ba.data()); - - // Set up file container - if (!SetupContainer()) { - return; - } - - // If video is enabled, set it up in the container now - if (!SetupVideo()) { - return; - } - - // If audio is enabled, set it up in the container now - if (!SetupAudio()) { - return; - } - - // Write the container header based on what's been set up above - ret = avformat_write_header(fmt_ctx, nullptr); - if (ret < 0) { - - // FFmpeg failed to write the header, so cancel the export and throw an error - - qCritical() << "Could not write output file header." << ret; - export_error = tr("could not write output file header (%1)").arg(QString::number(ret)); - - return; - } - - // Count audio samples in file (used for calculating PTS) - long file_audio_samples = 0; - - // Set up timing variables, used for determining rendering ETA - qint64 frame_start_time, frame_time, avg_time, eta, total_time = 0; - - // Frame counters - used for generating encoding statistics (e.g. average frame time, ETA, etc.) - long remaining_frames, frame_count = 1; - - // Use Sequence Viewer's render thread - TODO separate this into a new render thread for background rendering - RenderThread* renderer = panel_sequence_viewer->viewer_widget()->get_renderer(); - - // Override connection from RenderThread - disconnect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget(), SLOT(queue_repaint())); - connect(renderer, SIGNAL(ready()), this, SLOT(wake())); - - // Loop from now (set to the beginning frame earlier) to the end of the frame - while (params_.sequence->playhead <= params_.end_frame && !interrupt_) { - - // Start timing how long this frame will take - frame_start_time = QDateTime::currentMSecsSinceEpoch(); - - // If we're exporting audio, run compose_audio() which will write mixed audio to the internal audio buffer - if (params_.audio_enabled) { - waiting_for_audio_ = true; - SetAudioWakeObject(this); - olive::rendering::compose_audio(nullptr, params_.sequence, 1, true); - } - - // If we're exporting video, trigger a render on the RenderThread - if (params_.video_enabled) { - do { - // TODO optimize by rendering the next frame while encoding the last - renderer->start_render(nullptr, params_.sequence, 1, nullptr, video_frame->data[0], video_frame->linesize[0]/4); - - // Wait for RenderThread to return - waitCond.wait(&mutex); - - if (interrupt_) { - return; - } - - // If the RenderThread failed, do another render - } while (renderer->did_texture_fail()); - - if (interrupt_) { - return; - } - - } - - // Get the current sequence playhead in seconds (used for timestamp calculations later on) - double timecode_secs = double(params_.sequence->playhead - params_.start_frame) / params_.sequence->frame_rate(); - - // If we're exporting video, construct an AVFrame in the destination codec's pixel format to convert the raw RGBA - // OpenGL buffer to - if (params_.video_enabled) { - - // - // - I'm not sure why, but we have to alloc/free sws_frame every frame, or it breaks GIF exporting. - // - (i.e. GIFs get stuck on the first frame) - // - The same problem/solution can be seen here: https://stackoverflow.com/a/38997739 - // - Perhaps this is the intended way to use swscale, but it seems inefficient. - // - Anyway, here we are. - // - - // Construct destination pixel format frame - sws_frame = av_frame_alloc(); - sws_frame->format = vcodec_ctx->pix_fmt; - sws_frame->width = params_.video_width; - sws_frame->height = params_.video_height; - av_frame_get_buffer(sws_frame, 0); - - // 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(vcodec_ctx->time_base)); - - // Send frame to encoder - if (!Encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream)) { - return; - } - - av_frame_free(&sws_frame); - sws_frame = nullptr; - } - - // If we're exporting audio, copy audio from the buffer into an AVFrame for encoding - if (params_.audio_enabled) { - - if (waiting_for_audio_ && !interrupt_) { - waitCond.wait(&mutex); - } - - // Make sure nothing is writing while we're retrieving - audio_write_lock.lock(); - - // Check if the count of encoded samples exceeds the current Sequence playhead, in which case we don't need to - // encode any audio at this moment - while (!interrupt_ && file_audio_samples <= (timecode_secs*params_.audio_sampling_rate)) { - - // Copy samples from audio buffer to AVFrame - int adjusted_read = audio_ibuffer_read%audio_ibuffer_size; - int copylen = qMin(aframe_bytes, audio_ibuffer_size-adjusted_read); - memcpy(audio_frame->data[0], audio_ibuffer+adjusted_read, copylen); - memset(audio_ibuffer+adjusted_read, 0, copylen); - audio_ibuffer_read += copylen; - - // If we reached the end of the buffer without reaching the end of the frame, do another copy from the start - // of the buffer - if (copylen < aframe_bytes) { - int remainder_len = aframe_bytes-copylen; - memcpy(audio_frame->data[0]+copylen, audio_ibuffer, remainder_len); - memset(audio_ibuffer, 0, remainder_len); - audio_ibuffer_read += remainder_len; - } - - // Convert raw audio samples to the destination codec's sample format - swr_convert_frame(swr_ctx, swr_frame, audio_frame); - - // The timestamp is set to the current count of audio samples (since the audio stream's timebase is - swr_frame->pts = file_audio_samples; - - // Send frame to encoder - if (!Encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream)) { - return; - } - - // Increment by the frame's number of samples - file_audio_samples += swr_frame->nb_samples; - } - - audio_write_lock.unlock(); - - } - - // Generating encoding statistics (e.g. the time it took to encode this frame/estimated remaining time) - frame_time = (QDateTime::currentMSecsSinceEpoch()-frame_start_time); - total_time += frame_time; - remaining_frames = (params_.end_frame - params_.sequence->playhead); - avg_time = (total_time/frame_count); - eta = (remaining_frames*avg_time); - - // Emit a signal for the percent of the sequence that's been encoded so far - emit ProgressChanged(qRound((double(params_.sequence->playhead - params_.start_frame) / double(params_.end_frame - params_.start_frame)) * 100.0), eta); - - // Increment sequence playhead - params_.sequence->playhead++; - - // Increment frame count (used for generating encoding statistics above) - frame_count++; - } - - // Restore original connection from RenderThread - disconnect(renderer, SIGNAL(ready()), this, SLOT(wake())); - connect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget(), SLOT(queue_repaint())); - - if (interrupt_) { - return; - } - - if (params_.video_enabled) vpkt_alloc = true; - if (params_.audio_enabled) apkt_alloc = true; - - olive::Global->set_export_state(false); - - // If audio is enabled, flush the rest of the audio out of swresample - if (params_.audio_enabled) { - - do { - - swr_convert_frame(swr_ctx, swr_frame, nullptr); - if (swr_frame->nb_samples == 0) break; - swr_frame->pts = file_audio_samples; - if (!Encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream)) { - return; - } - file_audio_samples += swr_frame->nb_samples; - - } while (swr_frame->nb_samples > 0); - - } - - if (interrupt_) { - return; - } - - // Flush remaining packets out of video and audio encoders by sending a null frame - if (params_.video_enabled) { - Encode(fmt_ctx, vcodec_ctx, nullptr, &video_pkt, video_stream); - } - if (params_.audio_enabled) { - Encode(fmt_ctx, acodec_ctx, nullptr, &audio_pkt, audio_stream); - } - - // Write container trailer - ret = av_write_trailer(fmt_ctx); - if (ret < 0) { - qCritical() << "Could not write output file trailer." << ret; - export_error = tr("could not write output file trailer (%1)").arg(QString::number(ret)); - return; - } - - emit ProgressChanged(100, 0); -} - -void ExportThread::Cleanup() -{ - if (fmt_ctx != nullptr) { - avio_closep(&fmt_ctx->pb); - avformat_free_context(fmt_ctx); - } - - if (acodec_ctx != nullptr) { - avcodec_close(acodec_ctx); - avcodec_free_context(&acodec_ctx); - } - - if (audio_frame != nullptr) { - av_frame_free(&audio_frame); - } - - if (apkt_alloc) { - av_packet_unref(&audio_pkt); - } - - if (vcodec_ctx != nullptr) { - avcodec_close(vcodec_ctx); - avcodec_free_context(&vcodec_ctx); - } - - if (video_frame != nullptr) { - av_frame_free(&video_frame); - } - - if (vpkt_alloc) { - av_packet_unref(&video_pkt); - } - - if (sws_ctx != nullptr) { - sws_freeContext(sws_ctx); - } - - if (swr_ctx != nullptr) { - swr_free(&swr_ctx); - } - - if (swr_frame != nullptr) { - av_frame_free(&swr_frame); - } - - if (sws_frame != nullptr) { - av_frame_free(&sws_frame); - } - - delete [] c_filename; -} - -void ExportThread::run() { - // Ensure sequence isn't currently playing - panel_sequence_viewer->pause(); - - // Seek to the first frame we're exporting - panel_sequence_viewer->seek(params_.start_frame); - - // Lock mutex (used for thread synchronizations) - mutex.lock(); - - // Run export function (which will return if there's a failure) - Export(); - - mutex.unlock(); - - // Clean up anything that was allocated in Export() (whether it succeeded or not) - Cleanup(); -} - -const QString &ExportThread::GetError() { - return export_error; -} - -bool ExportThread::WasInterrupted() -{ - return interrupt_; -} - -void ExportThread::Interrupt() -{ - mutex.lock(); - interrupt_ = true; - waitCond.wakeAll(); - mutex.unlock(); -} - -void ExportThread::play_wake() -{ - mutex.lock(); - waiting_for_audio_ = false; - waitCond.wakeAll(); - mutex.unlock(); -} - -void ExportThread::wake() { - mutex.lock(); - waitCond.wakeAll(); - mutex.unlock(); -} diff --git a/rendering/exportthread.h b/rendering/exportthread.h deleted file mode 100644 index 170107188..000000000 --- a/rendering/exportthread.h +++ /dev/null @@ -1,141 +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 EXPORTTHREAD_H -#define EXPORTTHREAD_H - -extern "C" { -#include -} - -#include -#include -#include -#include - -#include "timeline/sequence.h" - -struct AVFormatContext; -struct AVCodecContext; -struct AVFrame; -struct AVPacket; -struct AVStream; -struct AVCodec; -struct SwsContext; -struct SwrContext; - -enum CompressionType { - COMPRESSION_TYPE_CBR, - COMPRESSION_TYPE_CFR, - COMPRESSION_TYPE_TARGETSIZE, - COMPRESSION_TYPE_TARGETBR -}; - -// structs that store parameters passed from the export dialogs to this thread - -struct ExportParams { - - // export parameters - Sequence* sequence; - QString filename; - bool video_enabled; - int video_codec; - int video_width; - int video_height; - double video_frame_rate; - int video_compression_type; - double video_bitrate; - bool audio_enabled; - int audio_codec; - int audio_sampling_rate; - int audio_bitrate; - long start_frame; - long end_frame; -}; - -struct VideoCodecParams { - int pix_fmt; - int threads; -}; - -class ExportThread : public QThread { - Q_OBJECT -public: - ExportThread(const ExportParams& params, const VideoCodecParams& vparams, QObject* parent = nullptr); - virtual void run() override; - - const QString& GetError(); - - bool WasInterrupted(); -signals: - void ProgressChanged(int value, qint64 remaining_ms); -public slots: - void Interrupt(); - - void play_wake(); -private: - bool Encode(AVFormatContext* ofmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream); - bool SetupVideo(); - bool SetupAudio(); - bool SetupContainer(); - void Export(); - void Cleanup(); - - QOffscreenSurface surface; - bool interrupt_; - - // params imported from dialogs - ExportParams params_; - VideoCodecParams vcodec_params_; - - AVFormatContext* fmt_ctx; - AVStream* video_stream; - AVCodec* vcodec; - AVCodecContext* vcodec_ctx; - AVFrame* video_frame; - AVFrame* sws_frame; - SwsContext* sws_ctx; - AVStream* audio_stream; - AVCodec* acodec; - AVFrame* audio_frame; - AVFrame* swr_frame; - AVCodecContext* acodec_ctx; - AVPacket video_pkt; - AVPacket audio_pkt; - SwrContext* swr_ctx; - - bool vpkt_alloc; - bool apkt_alloc; - - int aframe_bytes; - int ret; - char* c_filename; - - QMutex mutex; - QWaitCondition waitCond; - - QString export_error; - - bool waiting_for_audio_; -private slots: - void wake(); -}; - -#endif // EXPORTTHREAD_H diff --git a/rendering/framebuffercollection.cpp b/rendering/framebuffercollection.cpp deleted file mode 100644 index 502cb549b..000000000 --- a/rendering/framebuffercollection.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "framebuffercollection.h" - -FramebufferCollection::FramebufferCollection() -{ - -} - -void FramebufferCollection::Create(QOpenGLContext* ctx, - int width, - int height, - int count) -{ - Q_ASSERT(count > 1); - - fbo_.resize(count); - for (int i=0;i - -#include "framebufferobject.h" - -class FramebufferCollection -{ -public: - FramebufferCollection(); - - void Create(QOpenGLContext *ctx, int width, int height, int count); - void Destroy(); - - GLuint CurrentTexture(); - const FramebufferObject& CurrentFramebuffer(); - const FramebufferObject& NextFramebuffer(); - bool TextureBelongsToCollection(GLuint tex); - - bool IsCreated(); -private: - QVector fbo_; - int fbo_index_; -}; - -#endif // FRAMEBUFFERCOLLECTION_H diff --git a/rendering/framebufferobject.cpp b/rendering/framebufferobject.cpp deleted file mode 100644 index 9ab25bf07..000000000 --- a/rendering/framebufferobject.cpp +++ /dev/null @@ -1,155 +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 "framebufferobject.h" - -#include -#include -#include - -#include "global/config.h" -#include "global/global.h" -#include "pixelformats.h" - -FramebufferObject::FramebufferObject() : - buffer_(0), - texture_(0), - ctx_(nullptr) -{} - -FramebufferObject::~FramebufferObject() -{ - Destroy(); -} - -bool FramebufferObject::IsCreated() -{ - return ctx_ != nullptr; -} - -void FramebufferObject::Create(QOpenGLContext *ctx, int width, int height) -{ - // free any previous textures - Destroy(); - - // set context to new context provided - ctx_ = ctx; - - QOpenGLFunctions* f = ctx->functions(); - - // create framebuffer object - f->glGenFramebuffers(1, &buffer_); - - // create texture - f->glGenTextures(1, &texture_); - - // bind framebuffer for attaching - f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer_); - - // bind texture - f->glBindTexture(GL_TEXTURE_2D, texture_); - - // allocate storage for texture - const olive::PixelFormatInfo& bit_depth = olive::pixel_formats.at(olive::Global->effective_bit_depth()); - - ctx->functions()->glTexImage2D( - GL_TEXTURE_2D, - 0, - bit_depth.internal_format, - width, - height, - 0, - bit_depth.pixel_format, - bit_depth.pixel_type, - nullptr - ); - - // set texture filtering to bilinear - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // attach texture to framebuffer - ctx->extraFunctions()->glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0 - ); - - // clear new texture - ctx->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - - // release texture - f->glBindTexture(GL_TEXTURE_2D, 0); - - // release framebuffer - f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -void FramebufferObject::Destroy() -{ - if (ctx_ != nullptr) { - ctx_->functions()->glDeleteFramebuffers(1, &buffer_); - - ctx_->functions()->glDeleteTextures(1, &texture_); - } - - ctx_ = nullptr; -} - -void FramebufferObject::BindBuffer() const -{ - if (ctx_ == nullptr) { - return; - } - ctx_->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer_); -} - -void FramebufferObject::ReleaseBuffer() const -{ - if (ctx_ == nullptr) { - return; - } - ctx_->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -void FramebufferObject::BindTexture() const -{ - if (ctx_ == nullptr) { - return; - } - ctx_->functions()->glBindTexture(GL_TEXTURE_2D, texture_); -} - -void FramebufferObject::ReleaseTexture() const -{ - if (ctx_ == nullptr) { - return; - } - ctx_->functions()->glBindTexture(GL_TEXTURE_2D, 0); -} - -const GLuint &FramebufferObject::buffer() const -{ - return buffer_; -} - -const GLuint &FramebufferObject::texture() const -{ - return texture_; -} diff --git a/rendering/framebufferobject.h b/rendering/framebufferobject.h deleted file mode 100644 index fda654de9..000000000 --- a/rendering/framebufferobject.h +++ /dev/null @@ -1,50 +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 FRAMEBUFFEROBJECT_H -#define FRAMEBUFFEROBJECT_H - -#include - -class FramebufferObject -{ -public: - FramebufferObject(); - ~FramebufferObject(); - - bool IsCreated(); - void Create(QOpenGLContext* ctx, int width, int height); - void Destroy(); - - const GLuint& buffer() const; - const GLuint& texture() const; - - void BindBuffer() const; - void ReleaseBuffer() const; - - void BindTexture() const; - void ReleaseTexture() const; -private: - QOpenGLContext* ctx_; - GLuint buffer_; - GLuint texture_; -}; - -#endif // FRAMEBUFFEROBJECT_H diff --git a/rendering/imagecache.cpp b/rendering/imagecache.cpp deleted file mode 100644 index 6f2c473ce..000000000 --- a/rendering/imagecache.cpp +++ /dev/null @@ -1,296 +0,0 @@ -#include "imagecache.h" - -#include - -#include "decoders/pixelformatconverter.h" -#include "global/config.h" -#include "global/global.h" - -ImageCache::ImageCache() : - ctx_(nullptr), - width_(0), - height_(0) -{ - -} - -ImageCache::~ImageCache() -{ - buffer_array_mutex_.lock(); - - Clear(); - - buffer_array_mutex_.unlock(); -} - -void ImageCache::SetParameters(QOpenGLContext *ctx, int width, int height) -{ - buffer_array_mutex_.lock(); - - ctx_ = ctx; - - if (ctx_ != nullptr) { - Q_ASSERT(width > 0 && height > 0); - - width_ = width; - height_ = height; - } - - Clear(); - - buffer_array_mutex_.unlock(); -} - -int ImageCache::RequestBuffer(Ref* r, const BufferType& type, int width, int height) -{ - if (type == kTexBuf && (ctx_ == nullptr || width_ == 0 || height_ == 0)) { - qWarning() << "A texture cache request was made without valid parameters [" << ctx_ << width_ << "," << height_ << "]"; - return -1; - } - - buffer_array_mutex_.lock(); - - int buffer = RequestBufferInternal(r, type, width, height); - - buffer_array_mutex_.unlock(); - - return buffer; -} - -int ImageCache::RequestBufferInternal(Ref *r, const BufferType& type, int width, int height) -{ - Q_ASSERT(type != kInvalidBuf); - - QList& relinquished = (type == kMemBuf) ? img_relinquished_ : tex_relinquished_; - QList& refs = (type == kMemBuf) ? img_refs_ : tex_refs_; - QList& access_times = (type == kMemBuf) ? img_access_times_ : tex_access_times_; - - // Try to return a relinquished buffer - if (!relinquished.isEmpty()) { - - if (type == kTexBuf) { - - int buf_index = relinquished.takeFirst(); - - refs.replace(buf_index, r); - - return buf_index; - - } else if (type == kMemBuf) { - - // Check for a relinquished buffer with the desired size - - // - // TODO consider a database for sorting through these buffers - // - for (int i=0;iRelinquish(); - refs.replace(least_recent_access, r); - return least_recent_access; - } - - // Otherwise, just generate a new buffer - int index = -1; - switch (type) { - case kMemBuf: - index = img_buffers_.size(); - img_buffers_.append(MemoryBuffer()); - img_buffers_.last().Create(width_, height_, olive::Global->effective_bit_depth()); - break; - case kTexBuf: - index = tex_buffers_.size(); - tex_buffers_.append(FramebufferObject()); - tex_buffers_.last().Create(ctx_, width_, height_); - break; - default: - Q_ASSERT(false); - } - - refs.append(r); - access_times.append(time(nullptr)); - - return index; -} - -void ImageCache::RelinquishBuffer(int index, const BufferType &type) -{ - buffer_array_mutex_.lock(); - - switch (type) { - case kMemBuf: - img_refs_.replace(index, nullptr); - img_relinquished_.append(index); - break; - case kTexBuf: - tex_refs_.replace(index, nullptr); - tex_relinquished_.append(index); - break; - default: - qFatal("Invalid buffer type on ImageCache::RelinquishBuffer"); - } - - buffer_array_mutex_.unlock(); -} - -void *ImageCache::Buffer(int index, const BufferType &type) -{ - switch (type) { - case kMemBuf: - img_access_times_.replace(index, time(nullptr)); - return &img_buffers_[index]; - case kTexBuf: - tex_access_times_.replace(index, time(nullptr)); - return &tex_buffers_[index]; - default: - qFatal("Invalid buffer type on ImageCache::Buffer"); - } -} - -bool ImageCache::OutOfMemory() -{ - // TODO actually check if we have any memory or not - return false; -} - -void ImageCache::Clear() -{ - for (int i=0;iRelinquish(); - } - - for (int i=0;iRelinquish(); - } - - img_refs_.clear(); - tex_refs_.clear(); - - img_buffers_.clear(); - tex_buffers_.clear(); - - img_relinquished_.clear(); - tex_relinquished_.clear(); -} - -ImageCache::Ref::Ref(ImageCache *cache) : - buffer_type_(kInvalidBuf), - cache_(cache), - buffer_(-1), - width_(-1), - height_(-1) -{ -} - -ImageCache::Ref::~Ref() -{ - Relinquish(); -} - -void *ImageCache::Ref::BufferInternal() -{ - // If we don't have a buffer yet, request one - if (buffer_ == -1) { - Request(); - } - - // If we didn't receive one, return null - if (buffer_ == -1) { - return nullptr; - } - - // Otherwise, return the buffer we received - return cache_->Buffer(buffer_, buffer_type_); -} - -void ImageCache::Ref::Relinquish() -{ - if (buffer_ == -1) { - return; - } - - cache_->RelinquishBuffer(buffer_, buffer_type_); - buffer_ = -1; -} - -void ImageCache::Ref::Request() -{ - // Check if we already have a buffer, in which case we don't need to request a new one - if (buffer_ != -1) { - return; - } - - // Check if we have a valid buffer type to request - if (buffer_type_ == kInvalidBuf) { - qWarning() << "Tried to request an invalid buffer type"; - return; - } - - buffer_ = cache_->RequestBuffer(this, buffer_type_, width_, height_); -} - -ImageCache::ImgRef::ImgRef(ImageCache *cache) : - Ref(cache) -{ - buffer_type_ = kMemBuf; -} - -void ImageCache::ImgRef::SetSize(int w, int h) -{ - width_ = w; - height_ = h; - - Relinquish(); -} - -MemoryBuffer *ImageCache::ImgRef::buffer() -{ - return static_cast(BufferInternal()); -} - -ImageCache::TexRef::TexRef(ImageCache *cache) : - Ref(cache) -{ - buffer_type_ = kTexBuf; -} - -FramebufferObject *ImageCache::TexRef::buffer() -{ - return static_cast(BufferInternal()); -} diff --git a/rendering/imagecache.h b/rendering/imagecache.h deleted file mode 100644 index 07a4050e0..000000000 --- a/rendering/imagecache.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef MEMORYCACHE_H -#define MEMORYCACHE_H - -#include -#include - -#include "framebufferobject.h" -#include "memorybuffer.h" - -class ImageCache -{ -public: - - enum BufferType { - kInvalidBuf, - kMemBuf, // RAM (CPU) buffer - kTexBuf // VRAM (GPU) buffer - }; - - class Ref { - public: - Ref(ImageCache* cache); - ~Ref(); - - void Relinquish(); - protected: - void* BufferInternal(); - - BufferType buffer_type_; - - int width_; - int height_; - private: - void Request(); - - ImageCache* cache_; - int buffer_; - }; - - class ImgRef : public Ref { - public: - ImgRef(ImageCache* cache); - - void SetSize(int w, int h); - - MemoryBuffer* buffer(); - - }; - - class TexRef : public Ref { - public: - TexRef(ImageCache* cache); - FramebufferObject* buffer(); - }; - - ImageCache(); - ~ImageCache(); - - void SetParameters(QOpenGLContext* ctx, int width, int height); - -private: - int RequestBuffer(Ref *r, const BufferType& type, int width, int height); - int RequestBufferInternal(Ref *r, const BufferType& type, int width, int height); - - void RelinquishBuffer(int index, const BufferType& type); - - void *Buffer(int index, const BufferType &type); - - bool OutOfMemory(); - - void Clear(); - - QList img_buffers_; - QList img_refs_; - QList img_access_times_; - QList img_relinquished_; - - QList tex_buffers_; - QList tex_refs_; - QList tex_access_times_; - QList tex_relinquished_; - - QOpenGLContext* ctx_; - - int width_; - int height_; - - QMutex buffer_array_mutex_; -}; - -#endif // MEMORYCACHE_H diff --git a/rendering/memorybuffer.cpp b/rendering/memorybuffer.cpp deleted file mode 100644 index 9a54f4662..000000000 --- a/rendering/memorybuffer.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "memorybuffer.h" - -#include - -#include "decoders/pixelformatconverter.h" - -MemoryBuffer::MemoryBuffer() -{ -} - -void MemoryBuffer::Create(int width, int height, const olive::PixelFormat &format) -{ - width_ = width; - height_ = height; - format_ = format; - - data_.resize(olive::pix_fmt_conv->GetBufferSize(format, width, height)); -} - -const int &MemoryBuffer::width() const -{ - return width_; -} - -const int &MemoryBuffer::height() const -{ - return height_; -} - -const olive::PixelFormat &MemoryBuffer::format() const -{ - return format_; -} - -uint8_t *MemoryBuffer::data() -{ - return data_.data(); -} - -const uint8_t *MemoryBuffer::const_data() const -{ - return data_.constData(); -} diff --git a/rendering/memorybuffer.h b/rendering/memorybuffer.h deleted file mode 100644 index 9d6db5fe3..000000000 --- a/rendering/memorybuffer.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MEMORYBUFFER_H -#define MEMORYBUFFER_H - -#include - -#include "pixelformats.h" - -class MemoryBuffer -{ -public: - MemoryBuffer(); - - void Create(int width, int height, const olive::PixelFormat& format); - - const int& width() const; - const int& height() const; - const olive::PixelFormat& format() const; - uint8_t* data(); - const uint8_t* const_data() const; - -private: - QVector data_; - int width_; - int height_; - olive::PixelFormat format_; -}; - -#endif // MEMORYBUFFER_H diff --git a/rendering/pixelformats.cpp b/rendering/pixelformats.cpp deleted file mode 100644 index 2bca7b024..000000000 --- a/rendering/pixelformats.cpp +++ /dev/null @@ -1,60 +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 "pixelformats.h" - -#include - -namespace olive { - -QVector pixel_formats; - -void InitializePixelFormats() { - - pixel_formats.resize(PIX_FMT_COUNT); - - pixel_formats[PIX_FMT_RGBA8].name = QCoreApplication::translate("bitdepths", "8-bit"); - pixel_formats[PIX_FMT_RGBA8].internal_format = GL_RGBA8; - pixel_formats[PIX_FMT_RGBA8].pixel_format = GL_RGBA; - pixel_formats[PIX_FMT_RGBA8].pixel_type = GL_UNSIGNED_BYTE; - pixel_formats[PIX_FMT_RGBA8].bytes_per_pixel = 4; - - pixel_formats[PIX_FMT_RGBA16].name = QCoreApplication::translate("bitdepths", "16-bit Integer"); - pixel_formats[PIX_FMT_RGBA16].internal_format = GL_RGBA16; - pixel_formats[PIX_FMT_RGBA16].pixel_format = GL_RGBA; - pixel_formats[PIX_FMT_RGBA16].pixel_type = GL_UNSIGNED_SHORT; - pixel_formats[PIX_FMT_RGBA16].bytes_per_pixel = 8; - - pixel_formats[PIX_FMT_RGBA16F].name = QCoreApplication::translate("bitdepths", "Half-Float (16-bit)"); - pixel_formats[PIX_FMT_RGBA16F].internal_format = GL_RGBA16F; - pixel_formats[PIX_FMT_RGBA16F].pixel_format = GL_RGBA; - pixel_formats[PIX_FMT_RGBA16F].pixel_type = GL_HALF_FLOAT; - pixel_formats[PIX_FMT_RGBA16F].bytes_per_pixel = 8; - - pixel_formats[PIX_FMT_RGBA32F].name = QCoreApplication::translate("bitdepths", "Full-Float (32-bit)"); - pixel_formats[PIX_FMT_RGBA32F].internal_format = GL_RGBA32F; - pixel_formats[PIX_FMT_RGBA32F].pixel_format = GL_RGBA; - pixel_formats[PIX_FMT_RGBA32F].pixel_type = GL_FLOAT; - pixel_formats[PIX_FMT_RGBA32F].bytes_per_pixel = 16; - -} - -} - diff --git a/rendering/pixelformats.h b/rendering/pixelformats.h deleted file mode 100644 index b9086b6f7..000000000 --- a/rendering/pixelformats.h +++ /dev/null @@ -1,65 +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 BITDEPTHS_H -#define BITDEPTHS_H - -#include -#include -#include - -namespace olive { - -/** - * @brief The PixelFormat enum - * - * Olive's internal supported pixel formats. With the exception of OLIVE_PIX_FMT_COUNT, these must all - * be defined in InitializePixelFormats(). - */ -enum PixelFormat { - PIX_FMT_RGBA8, - PIX_FMT_RGBA16, - PIX_FMT_RGBA16F, - PIX_FMT_RGBA32F, - PIX_FMT_COUNT -}; - -/** - * @brief The PixelFormatInfo struct - * - * A struct of information pertaining to each enum PixelFormat. Primarily this is a means of retrieving OpenGL texture - * information for different pixel formats/bit depths. Using the values in pixel_formats is always recommended over - * manually using OpenGL constants (e.g. GL_RGBA or GL_RGBA32F) directly. - */ -struct PixelFormatInfo { - QString name; - GLint internal_format; - GLenum pixel_format; - GLenum pixel_type; - int bytes_per_pixel; -}; - -extern QVector pixel_formats; - -void InitializePixelFormats(); - -} - -#endif // BITDEPTHS_H diff --git a/rendering/qopenglshaderprogramptr.h b/rendering/qopenglshaderprogramptr.h deleted file mode 100644 index a89993ffd..000000000 --- a/rendering/qopenglshaderprogramptr.h +++ /dev/null @@ -1,29 +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 QOPENGLSHADERPROGRAMPTR_H -#define QOPENGLSHADERPROGRAMPTR_H - -#include -#include - -using QOpenGLShaderProgramPtr = std::shared_ptr; - -#endif // QOPENGLSHADERPROGRAMPTR_H diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp deleted file mode 100644 index df5cf94be..000000000 --- a/rendering/renderfunctions.cpp +++ /dev/null @@ -1,850 +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 "renderfunctions.h" - -extern "C" { -#include -} - -#include -#include -#include -#include -#include -#include - -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "project/media.h" -#include "nodes/oldeffectnode.h" -#include "project/footage.h" -#include "effects/transition.h" -#include "ui/collapsiblewidget.h" -#include "rendering/audio.h" -#include "global/math.h" -#include "global/timing.h" -#include "global/config.h" -#include "panels/timeline.h" -#include "qopenglshaderprogramptr.h" -#include "shadergenerators.h" - -GLfloat olive::rendering::blit_vertices[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - - -1.0f, -1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f -}; - -GLfloat olive::rendering::blit_texcoords[] = { - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - - 0.0, 0.0, - 0.0, 1.0, - 1.0, 1.0 -}; - -GLfloat olive::rendering::flipped_blit_texcoords[] = { - 0.0, 1.0, - 1.0, 1.0, - 1.0, 0.0, - - 0.0, 1.0, - 0.0, 0.0, - 1.0, 0.0 -}; - -void PrepareToDraw(QOpenGLFunctions* f) { - f->glGenerateMipmap(GL_TEXTURE_2D); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); -} - -void olive::rendering::Blit(QOpenGLShaderProgram* pipeline, bool flipped, QMatrix4x4 matrix) { - - QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions(); - PrepareToDraw(func); - - QOpenGLVertexArrayObject m_vao; - m_vao.create(); - m_vao.bind(); - - QOpenGLBuffer m_vbo; - m_vbo.create(); - m_vbo.bind(); - m_vbo.allocate(blit_vertices, 18 * sizeof(GLfloat)); - m_vbo.release(); - - QOpenGLBuffer m_vbo2; - m_vbo2.create(); - m_vbo2.bind(); - m_vbo2.allocate(flipped ? flipped_blit_texcoords : blit_texcoords, 12 * sizeof(GLfloat)); - m_vbo2.release(); - - pipeline->bind(); - - pipeline->setUniformValue("mvp_matrix", matrix); - pipeline->setUniformValue("texture", 0); - - GLuint vertex_location = pipeline->attributeLocation("a_position"); - m_vbo.bind(); - func->glEnableVertexAttribArray(vertex_location); - func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, 0); - m_vbo.release(); - - GLuint tex_location = pipeline->attributeLocation("a_texcoord"); - m_vbo2.bind(); - func->glEnableVertexAttribArray(tex_location); - func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, 0); - m_vbo2.release(); - - func->glDrawArrays(GL_TRIANGLES, 0, 6); - - pipeline->release(); - -} - -void draw_clip(QOpenGLContext* ctx, - QOpenGLShaderProgram* pipeline, - GLuint fbo, - GLuint texture, - bool clear) { - ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); - - if (clear) { - ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - } - - ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture); - - olive::rendering::Blit(pipeline); - - ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); - - ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -GLuint draw_clip(QOpenGLContext* ctx, - QOpenGLShaderProgram* pipeline, - const FramebufferObject& fbo, - GLuint texture, - bool clear) { - - fbo.BindBuffer(); - - if (clear) { - ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - } - - ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture); - - olive::rendering::Blit(pipeline); - - ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); - - fbo.ReleaseBuffer(); - - return fbo.texture(); - -} - -void process_effect(QOpenGLContext* ctx, - QOpenGLShaderProgram* pipeline, - Clip* c, - OldEffectNode* e, - double timecode, - GLTextureCoords& coords, - GLuint& composite_texture, - bool& fbo_switcher, - bool& texture_failed, - int data) { - if (e->IsEnabled()) { - if (e->Flags() & OldEffectNode::CoordsFlag) { - e->process_coords(timecode, coords, data); - } - bool can_process_shaders = ((e->Flags() & OldEffectNode::ShaderFlag) && olive::runtime_config.shaders_are_enabled); - if (can_process_shaders || (e->Flags() & OldEffectNode::SuperimposeFlag)) { - - if (!e->is_open()) { - e->open(); - } - - if (can_process_shaders && e->is_shader_linked()) { - for (int i=0;igetIterations();i++) { - e->process_shader(timecode, coords, i); - composite_texture = draw_clip(ctx, e->GetShaderPipeline(), c->fbo.at(fbo_switcher), composite_texture, true); - fbo_switcher = !fbo_switcher; - } - } - if (e->Flags() & OldEffectNode::SuperimposeFlag) { - GLuint superimpose_texture = e->process_superimpose(ctx, timecode); - - if (superimpose_texture == 0) { - qWarning() << "Superimpose texture was nullptr, retrying..."; - texture_failed = true; - } else if (composite_texture == 0) { - // if there is no previous texture, just return the superimposes texture - // UNLESS this is a shader-extended superimpose effect in which case, - // we'll need to draw it below - composite_texture = superimpose_texture; - } else { - // if the source texture is not already a framebuffer texture, - // we'll need to make it one before drawing a superimpose effect on it - if (composite_texture != c->fbo.at(0).texture() && composite_texture != c->fbo.at(1).texture()) { - draw_clip(ctx, pipeline, c->fbo.at(!fbo_switcher), composite_texture, true); - } - - composite_texture = draw_clip(ctx, pipeline, c->fbo.at(!fbo_switcher), superimpose_texture, false); - } - } - } - } -} - -GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) { - GLuint final_fbo = params.type == olive::kTypeVideo ? params.main_buffer->buffer() : 0; - - Sequence* s = params.seq; - long playhead = s->playhead; - - if (!params.nests.isEmpty()) { - - for (int i=0;imedia()->to_sequence().get(); - playhead += params.nests.at(i)->clip_in(true) - params.nests.at(i)->timeline_in(true); - playhead = rescale_frame_number(playhead, params.nests.at(i)->track()->sequence()->frame_rate(), s->frame_rate()); - } - - if (params.type == olive::kTypeVideo && !params.nests.last()->fbo.isEmpty()) { - params.nests.last()->fbo.at(0).BindBuffer(); - params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - final_fbo = params.nests.last()->fbo.at(0).buffer(); - } - - } - - int audio_track_count = 0; - - QVector current_clips; - - // loop through clips, find currently active, and sort by track - QVector sequence_clips = s->GetAllClips(); - for (int i=0;itype() == params.type) { - - bool clip_is_active = false; - - // is the clip a "footage" clip? - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* m = c->media()->to_footage(); - - // does the clip have a valid media source? - if (!m->invalid && !(c->type() == olive::kTypeAudio && !is_audio_device_set())) { - - // is the media process and ready? - if (m->ready) { - const FootageStream* ms = c->media_stream(); - - // does the media have a valid media stream source and is it active? - if (ms != nullptr && c->IsActiveAt(playhead)) { - - // open if not open - if (!c->IsOpen()) { - c->Open(); - } - - clip_is_active = true; - - // increment audio track count - if (c->type() == olive::kTypeAudio) audio_track_count++; - - } else if (c->IsOpen()) { - - // close the clip if it isn't active anymore - c->Close(false); - - } - } else { - - // media wasn't ready, schedule a redraw - params.texture_failed = true; - - } - } - } else { - // if the clip is a nested sequence or null clip, just open it - - if (c->IsActiveAt(playhead)) { - if (!c->IsOpen()) { - c->Open(); - } - clip_is_active = true; - } else if (c->IsOpen()) { - c->Close(false); - } - } - - // if the clip is active, added it to "current_clips", sorted by track - if (clip_is_active) { - bool added = false; - - // track sorting is only necessary for video clips - // audio clips are mixed equally, so we skip sorting for those - if (params.type == olive::kTypeVideo) { - - // insertion sort by track - for (int j=0;jtrack() < c->track()) { - current_clips.insert(j, c); - added = true; - break; - } - } - - } - - if (!added) { - current_clips.append(c); - } - } - } - } - } - - QMatrix4x4 projection; - - if (params.type == olive::kTypeVideo) { - // set default coordinates based on the sequence, with 0 in the direct center - - params.ctx->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - int half_width = s->width()/2; - int half_height = s->height()/2; - - projection.ortho(-half_width, half_width, -half_height, half_height, -1, 1); - } - - // loop through current clips - - for (int i=0;istate_change_lock.lock(); - } else { - got_mutex = c->state_change_lock.tryLock(); - } - - if (got_mutex && c->IsOpen()) { - // if clip is a video clip - if (c->type() == olive::kTypeVideo) { - - // textureID variable contains texture to be drawn on screen at the end - GLuint textureID = 0; - - // store video source dimensions - int video_width = c->media_width(); - int video_height = c->media_height(); - - // prepare framebuffers for backend drawing operations - if (c->fbo.isEmpty()) { - // create 3 fbos for nested sequences, 2 for most clips - int fbo_count = (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2; - - c->fbo.resize(fbo_count); - - for (int j=0;jfbo[j].Create(params.ctx, video_width, video_height); - } - } - - bool convert_frame_to_internal = false; - - // if media is footage - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - - // retrieve video frame from cache and store it in c->texture - c->Cache(qMax(playhead, c->timeline_in(true)), false, params.nests, params.playback_speed); - if (!c->Retrieve()) { - params.texture_failed = true; - } else { - // retrieve ID from c->texture - textureID = c->texture; - } - - if (textureID == 0) { - - qWarning() << "Failed to create texture"; - - } else { - - convert_frame_to_internal = true; - - } - } - - // if clip should actually be shown on screen in this frame - if (playhead >= c->timeline_in(true) - && playhead < c->timeline_out(true)) { - - // simple bool for switching between the two framebuffers - bool fbo_switcher = false; - - params.ctx->functions()->glViewport(0, 0, video_width, video_height); - - if (c->media() != nullptr) { - if (c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - - // for a nested sequence, run this function again on that sequence and retrieve the texture - - // add nested sequence to nest list - params.nests.append(c); - - // compose sequence - textureID = compose_sequence(params); - - // remove sequence from nest list - params.nests.removeLast(); - - // compose_sequence() would have written to this clip's fbo[0], so we switch to fbo[1] - fbo_switcher = !fbo_switcher; - - } else if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - - // Convert frame from source to linear colorspace - if (olive::config.enable_color_management) - { - - // Convert texture to sequence's internal format - if (textureID != c->fbo.at(0).texture() && textureID != c->fbo.at(1).texture()) { - textureID = draw_clip(params.ctx, params.pipeline, c->fbo.at(fbo_switcher), textureID, true); - fbo_switcher = !fbo_switcher; - } - - // Check if this clip has an OCIO shader set up or not - if (c->ocio_shader == nullptr) { - - - // Set default input colorspace - QString input_cs = OCIO::ROLE_SCENE_LINEAR; - - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - input_cs = c->media()->to_footage()->Colorspace(); - } - - // Try to get a shader based on the input color space to scene linear - try { - OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); - OCIO::ConstProcessorRcPtr processor = config->getProcessor(input_cs.toUtf8(), - OCIO::ROLE_SCENE_LINEAR); - - c->ocio_shader = olive::shader::SetupOCIO(params.ctx, - c->ocio_lut_texture, - processor, - c->media()->to_footage()->alpha_is_associated); - } catch (OCIO::Exception& e) { - qWarning() << e.what(); - } - } - - // Ensure we got a shader, and if so, blit with it - if (c->ocio_shader != nullptr) { - textureID = olive::rendering::OCIOBlit(c->ocio_shader.get(), - c->ocio_lut_texture, - c->fbo.at(fbo_switcher), - textureID); - - fbo_switcher = !fbo_switcher; - } - - } - } - } - - // set up default coordinates for drawing the clip - GLTextureCoords coords; - coords.vertex_top_left = QVector3D(-video_width/2, -video_height/2, 0.0f); - coords.vertex_top_right = QVector3D(video_width/2, -video_height/2, 0.0f); - coords.vertex_bottom_left = QVector3D(-video_width/2, video_height/2, 0.0f); - coords.vertex_bottom_right = QVector3D(video_width/2, video_height/2, 0.0f); - coords.texture_top_left = QVector2D(0.0f, 0.0f); - coords.texture_top_right = QVector2D(1.0f, 0.0f); - coords.texture_bottom_left = QVector2D(0.0f, 1.0f); - coords.texture_bottom_right = QVector2D(1.0f, 1.0f); - coords.opacity = 1.0; - - // == EFFECT CODE START == - - // get current sequence time in seconds (used for effects) - double timecode = get_timecode(c, playhead); - - // run through all of the clip's effects - for (int j=0;jeffects.size();j++) { - - OldEffectNode* e = c->effects.at(j).get(); - process_effect(params.ctx, params.pipeline, c, e, timecode, coords, textureID, fbo_switcher, params.texture_failed, kTransitionNone); - - } - - // if the clip has an opening transition, process that now - if (c->opening_transition != nullptr) { - int transition_progress = playhead - c->timeline_in(true); - if (transition_progress < c->opening_transition->get_length()) { - process_effect(params.ctx, params.pipeline, c, c->opening_transition.get(), double(transition_progress)/double(c->opening_transition->get_length()), coords, textureID, fbo_switcher, params.texture_failed, kTransitionOpening); - } - } - - // if the clip has a closing transition, process that now - if (c->closing_transition != nullptr) { - int transition_progress = playhead - (c->timeline_out(true) - c->closing_transition->get_length()); - if (transition_progress >= 0 && transition_progress < c->closing_transition->get_length()) { - process_effect(params.ctx, params.pipeline, c, c->closing_transition.get(), double(transition_progress)/double(c->closing_transition->get_length()), coords, textureID, fbo_switcher, params.texture_failed, kTransitionClosing); - } - } - - // == EFFECT CODE END == - - - // Check whether the parent clip is auto-scaled - if (c->autoscaled() - && (video_width != s->width() - && video_height != s->height())) { - float width_multiplier = float(s->width()) / float(video_width); - float height_multiplier = float(s->height()) / float(video_height); - float scale_multiplier = qMin(width_multiplier, height_multiplier); - - coords.matrix.scale(scale_multiplier, scale_multiplier); - } - - // Configure effect gizmos if they exist - if (params.gizmos != nullptr) { - // set correct gizmo coords at this matrix - params.gizmos->gizmo_draw(timecode, coords); - - // convert gizmo coords to screen coords - params.gizmos->gizmo_world_to_screen(coords.matrix, projection); - } - - - - if (textureID > 0) { - - // set viewport to sequence size - params.ctx->functions()->glViewport(0, 0, s->width(), s->height()); - - - - // == START RENDER CLIP IN CONTEXT OF SEQUENCE == - - - - // use clip textures for nested sequences, otherwise use main frame buffers - GLuint back_buffer_1; - GLuint back_buffer_2; - GLuint backend_tex_1; - GLuint backend_tex_2; - GLuint comp_texture; - if (params.nests.size() > 0) { - back_buffer_1 = params.nests.last()->fbo[1].buffer(); - back_buffer_2 = params.nests.last()->fbo[2].buffer(); - backend_tex_1 = params.nests.last()->fbo[1].texture(); - backend_tex_2 = params.nests.last()->fbo[2].texture(); - comp_texture = params.nests.last()->fbo[0].texture(); - } else { - back_buffer_1 = params.backend_buffer1->buffer(); - back_buffer_2 = params.backend_buffer2->buffer(); - backend_tex_1 = params.backend_buffer1->texture(); - backend_tex_2 = params.backend_buffer2->texture(); - comp_texture = params.main_buffer->texture(); - } - - // render a backbuffer - params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, back_buffer_1); - - params.ctx->functions()->glClearColor(0.0, 0.0, 0.0, 0.0); - params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - - // bind final clip texture - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, textureID); - - // set texture filter to bilinear - PrepareToDraw(params.ctx->functions()); - - // draw clip on screen according to gl coordinates - params.pipeline->bind(); - - params.pipeline->setUniformValue("mvp_matrix", projection * coords.matrix); - params.pipeline->setUniformValue("texture", 0); - params.pipeline->setUniformValue("opacity", coords.opacity); - - GLfloat vertices[] = { - coords.vertex_top_left.x(), coords.vertex_top_left.y(), 0.0f, - coords.vertex_top_right.x(), coords.vertex_top_right.y(), 0.0f, - coords.vertex_bottom_right.x(), coords.vertex_bottom_right.y(), 0.0f, - - coords.vertex_top_left.x(), coords.vertex_top_left.y(), 0.0f, - coords.vertex_bottom_left.x(), coords.vertex_bottom_left.y(), 0.0f, - coords.vertex_bottom_right.x(), coords.vertex_bottom_right.y(), 0.0f, - }; - - GLfloat texcoords[] = { - coords.texture_top_left.x(), coords.texture_top_left.y(), - coords.texture_top_right.x(), coords.texture_top_right.y(), - coords.texture_bottom_right.x(), coords.texture_bottom_right.y(), - - coords.texture_top_left.x(), coords.texture_top_left.y(), - coords.texture_bottom_left.x(), coords.texture_bottom_left.y(), - coords.texture_bottom_right.x(), coords.texture_bottom_right.y(), - }; - - QOpenGLVertexArrayObject vao; - vao.create(); - vao.bind(); - - QOpenGLBuffer vertex_buffer; - vertex_buffer.create(); - vertex_buffer.bind(); - vertex_buffer.allocate(vertices, 18 * sizeof(GLfloat)); - vertex_buffer.release(); - - QOpenGLBuffer texcoord_buffer; - texcoord_buffer.create(); - texcoord_buffer.bind(); - texcoord_buffer.allocate(texcoords, 12 * sizeof(GLfloat)); - texcoord_buffer.release(); - - GLuint vertex_location = params.pipeline->attributeLocation("a_position"); - vertex_buffer.bind(); - params.ctx->functions()->glEnableVertexAttribArray(vertex_location); - params.ctx->functions()->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, 0); - vertex_buffer.release(); - - GLuint tex_location = params.pipeline->attributeLocation("a_texcoord"); - texcoord_buffer.bind(); - params.ctx->functions()->glEnableVertexAttribArray(tex_location); - params.ctx->functions()->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, 0); - texcoord_buffer.release(); - - params.ctx->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); - - params.pipeline->setUniformValue("opacity", 1.0f); - - params.pipeline->release(); - - // release final clip texture - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); - - params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - - - // == END RENDER CLIP IN CONTEXT OF SEQUENCE == - - - - // - // - // PROCESS POST-SHADERS - // - // - - - - // copy front buffer to back buffer (only if we're using a blending mode) - /* - if (coords.blendmode >= 0) { - draw_clip(params.ctx, params.pipeline, back_buffer_2, comp_texture, true); - } - */ - - - - // == START FINAL DRAW ON SEQUENCE BUFFER == - - - - - // bind front buffer as draw buffer - params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, final_fbo); - - // Check if we're using a blend mode (< 0 means no blend mode) - //if (coords.blendmode < 0) { - - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_1); - - olive::rendering::Blit(params.pipeline); - - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); - - //} else { - - /* - - // load background texture into texture unit 0 - params.ctx->functions()->glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_2); - - // load foreground texture into texture unit 1 - params.ctx->functions()->glActiveTexture(GL_TEXTURE0 + 1); // Texture unit 1 - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_1); - - // bind and configure blending mode shader - params.blend_mode_program->bind(); - params.blend_mode_program->setUniformValue("blendmode", coords.blendmode); - params.blend_mode_program->setUniformValue("opacity", coords.opacity); - params.blend_mode_program->setUniformValue("background", 0); - params.blend_mode_program->setUniformValue("foreground", 1); - - params.ctx->functions()->glClear(GL_COLOR_BUFFER_BIT); - - olive::rendering::Blit(params.pipeline); - - // release blend mode shader - params.blend_mode_program->release(); - - // unbind texture from texture unit 1 - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); - - // unbind texture from texture unit 0 - params.ctx->functions()->glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 - params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); - - */ - - //} - - // unbind framebuffer - params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - - - - // == END FINAL DRAW ON SEQUENCE BUFFER == - } - } - } else if (c->type() == olive::kTypeAudio) { - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - params.nests.append(c); - compose_sequence(params); - params.nests.removeLast(); - } else { - // Check whether cacher is currently active, if not activate it now - - bool got_mutex2 = false; - - if (params.wait_for_mutexes) { - c->cache_lock.lock(); - got_mutex2 = true; - } else { - got_mutex2 = c->cache_lock.tryLock(got_mutex2); - } - - if (got_mutex2) { - - c->cache_lock.unlock(); - - c->Cache(playhead, - (params.viewer != nullptr && !params.viewer->playing), - params.nests, - params.playback_speed); - - } - } - } - } else { - params.texture_failed = true; - } - - if (got_mutex) { - c->state_change_lock.unlock(); - } - } - - if (audio_track_count == 0) { - WakeAudioWakeObject(); - } - - if (!params.nests.isEmpty() && !params.nests.last()->fbo.isEmpty()) { - // returns nested clip's texture - return params.nests.last()->fbo[0].texture(); - } - - return 0; -} - -void olive::rendering::compose_audio(Viewer* viewer, Sequence* seq, int playback_speed, bool wait_for_mutexes) { - ComposeSequenceParams params; - params.viewer = viewer; - params.ctx = nullptr; - params.seq = seq; - params.type = olive::kTypeAudio; - params.gizmos = nullptr; - params.wait_for_mutexes = wait_for_mutexes; - params.playback_speed = playback_speed; - compose_sequence(params); -} - -GLuint olive::rendering::OCIOBlit(QOpenGLShaderProgram *pipeline, - GLuint lut, - const FramebufferObject& fbo, - GLuint texture) -{ - if (pipeline == nullptr) { - return 0; - } - - QOpenGLContext* ctx = QOpenGLContext::currentContext(); - QOpenGLExtraFunctions* xf = ctx->extraFunctions(); - - xf->glActiveTexture(GL_TEXTURE2); - xf->glBindTexture(GL_TEXTURE_3D, lut); - xf->glActiveTexture(GL_TEXTURE0); - - pipeline->bind(); - - pipeline->setUniformValue("tex2", 2); - - //textureID = draw_clip(params.ctx, pipeline, c->fbo.at(fbo_switcher), textureID, true); - GLuint textureID = draw_clip(ctx, pipeline, fbo, texture, true); - - pipeline->release(); - - xf->glActiveTexture(GL_TEXTURE2); - xf->glBindTexture(GL_TEXTURE_3D, 0); - xf->glActiveTexture(GL_TEXTURE0); - - return textureID; -} diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h deleted file mode 100644 index 09a8082d6..000000000 --- a/rendering/renderfunctions.h +++ /dev/null @@ -1,247 +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 RENDERFUNCTIONS_H -#define RENDERFUNCTIONS_H - -#include -#include -#include -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -#include "timeline/sequence.h" -#include "nodes/oldeffectnode.h" -#include "panels/viewer.h" - -/** - * @brief The ComposeSequenceParams struct - * - * Struct sent to the compose_sequence() function. - */ -struct ComposeSequenceParams { - - /** - * @brief Reference to the Viewer class that's calling compose_sequence() - * - * Primarily used for calling Viewer::play_wake() when appropriate. - */ - Viewer* viewer; - - /** - * @brief The OpenGL context to use while rendering. - * - * For video rendering, this must be a valid OpenGL context. For audio, this variable is never accessed. - * - * \see ComposeSequenceParams::video - */ - QOpenGLContext* ctx; - - /** - * @brief The OpenGL pipeline used for rendering - * - * \see olive::rendering::GetPipeline(). - */ - QOpenGLShaderProgram* pipeline; - - /** - * @brief The sequence to compose - * - * In addition to clips, sequences also contain the playhead position so compose_sequence() knows which frame - * to render. - */ - Sequence* seq; - - /** - * @brief Array to store the nested sequence hierarchy - * - * Should be left empty. This array gets passed around compose_sequence() as it calls itself recursively to - * handle nested sequences. - */ - QVector nests; - - /** - * @brief Set compose mode to video or audio - * - * Accepts olive::kTypeVideo to render video, olive::kTypeAudio if this function should render audio. - */ - olive::TrackType type; - - /** - * @brief Set to the Effect whose gizmos were chosen to be drawn on screen - * - * The currently active Effect that compose_sequence() will update the gizmos of. - */ - OldEffectNode* gizmos; - - /** - * @brief A variable that compose_sequence() will set to **TRUE** if any of the clips couldn't be shown. - * - * A footage item or shader may not be ready at the time this frame is drawn. If compose_sequence() couldn't draw - * any of the clips in the scene, this variable is set to **TRUE** indicating that the image rendered is a - * "best effort", but not the actual image. - * - * This variable should be checked after compose_sequence() and a repaint should be triggered if it's **TRUE**. - * - * \note This variable is probably bad design and is a relic of an earlier rendering backend. There may be a better - * way to communicate this information. - * - * Additionally, since - * compose_sequence() for video will now always run in a separate thread anyway, there's no real issue with - * stalling it to wait for footage to complete opening or whatever may be lagging behind. A possible side effect - * of this though is that the preview may become less responsive if it's stuck trying to render one frame. With - * the current system, the preview may show incomplete frames occasionally but at least it will show something. - * This may be preferable. See ComposeSequenceParams::single_threaded for a similar function that could be - * removed. - */ - bool texture_failed; - - /** - * @brief Run all cachers in the same thread that compose_sequence() is in - * - * Standard behavior is that all clips cache frames in their own thread and signals are sent between - * compose_sequence() and the clip's cacher thread regarding which frames to display and cache without stalling - * the compose_sequence() thread. Setting this to **TRUE** will run all cachers in the same thread creating a - * technically more "perfect" connection between them that will also stall the compose_sequence() thread. Used - * when rendering as timing isn't as important as creating output frames as quickly as possible. - * - * \note Exporting should probably be rewritten without this. While running all the cachers in one thread makes - * it easier to synchronize everything, export performance could probably benefit from keeping them in separate - * threads and syncing up with them. See ComposeSequenceParams::texture_failed for a similar function that could - * be removed. - */ - bool wait_for_mutexes; - - /** - * @brief Set the current playback speed (adjusted with Shuttle Left/Right) - * - * Only used for audio rendering to determine how many samples to skip in order to play audio at the correct speed. - * - * \see ComposeSequenceParams::video - */ - int playback_speed; - - /** - * @brief Premultiply alpha shader - * - * Used only for video rendering. Never accessed with audio rendering. - * - * compose_sequence()'s internal composition - * expects premultipled alpha, but it will pre-emptively multiply any footage that is not set as already - * premultiplied (see Footage::alpha_is_premultiplied) using this shader. Must be compiled and linked beforehand. - * See RenderThread::premultiply_program for how this is properly set up. - */ - QOpenGLShaderProgram* premultiply_program; - - /** - * @brief The OpenGL framebuffer object that the final texture to be shown is rendered to. - * - * Used only for video rendering. Never accessed with audio rendering. - * - * When compose_sequence() is rendering the final image, this framebuffer will be bound. - */ - const FramebufferObject* main_buffer; - - /** - * @brief Backend OpenGL framebuffer 1 used for further processing before rendering to main_buffer - * - * In some situations, compose_sequence() will do some processing through shaders that requires "ping-ponging" - * between framebuffers. backend_buffer1 and backend_buffer2 are used for this purpose. - */ - const FramebufferObject* backend_buffer1; - - /** - * @brief Backend OpenGL framebuffer 2 used for further processing before rendering to main_buffer - * - * In some situations, compose_sequence() will do some processing through shaders that requires "ping-ponging" - * between framebuffers. backend_buffer1 and backend_buffer2 are used for this purpose. - */ - const FramebufferObject* backend_buffer2; -}; - -namespace olive { -namespace rendering { -/** - * @brief Compose a frame of a given sequence - * - * For any given Sequence, this function will render the current frame indicated by Sequence::playhead. Will - * automatically open and close clips (memory allocation and file handles) as necessary, communicate with the - * Clip::cacher objects to retrieve upcoming frames and store them in memory, run Effect processing functions, and - * finally composite all the currently active clips together into a final texture. - * - * Will sometimes render a frame incomplete or inaccurately, e.g. if a video file hadn't finished opening by the time - * of the render or a clip's cacher didn't have the requested frame available at the time of the render. If so, - * the `texture_failed` variable of `params` will be set to **TRUE**. Check this after calling compose_sequence() and - * if it is **TRUE**, compose_sequence() should be called again later to attempt another render (unless the Sequence - * is being played, in which case just play the next frame rather than redrawing an old frame). - * - * @param params - * - * A struct of parameters to use while rendering. - * - * @return A reference to the OpenGL texture resulting from the render. Will usually be equal to - * ComposeSequenceParams::main_attachment unless it's rendering a nested sequence, in which case it'll be a reference - * to one of the textures referenced by Clip::fbo. Can be used directly to draw the rendered frame. - */ -GLuint compose_sequence(ComposeSequenceParams ¶ms); - -/** - * @brief Convenience wrapper function for compose_sequence() to render audio - * - * Much of the functionality provided (and parameters required) by compose_sequence() is only useful/necessary for - * video rendering. For audio rendering, this function is easier to handle and will correctly set up - * compose_sequence() to render audio without the cumbersome effort of setting up a ComposeSequenceParams object. - * - * @param viewer - * - * The Viewer object calling this function - * - * @param seq - * - * The Sequence whose audio to render. - * - * @param playback_speed - * - * The current playback speed (controlled by Shuttle Left/Right) - * - * @param - * - * Whether to wait for media to open or simply fail if the media is not yet open. This should usually be **FALSE**. - */ -void compose_audio(Viewer* viewer, Sequence *seq, int playback_speed, bool wait_for_mutexes); -} -} - -void UpdateOCIOGLState(const ComposeSequenceParams ¶ms); - -namespace olive { - namespace rendering { - extern GLfloat blit_vertices[]; - extern GLfloat blit_texcoords[]; - extern GLfloat flipped_blit_texcoords[]; - void Blit(QOpenGLShaderProgram* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); - GLuint OCIOBlit(QOpenGLShaderProgram *pipeline, - GLuint lut, - const FramebufferObject& fbo, - GLuint texture); - } -} - -#endif // RENDERFUNCTIONS_H diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp deleted file mode 100644 index e9d1c818a..000000000 --- a/rendering/renderthread.cpp +++ /dev/null @@ -1,387 +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 "renderthread.h" - -#include -#include -#include -#include -#include -#include - -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -#include "timeline/sequence.h" -#include "effects/effectloaders.h" -#include "global/config.h" -#include "rendering/renderfunctions.h" -#include "rendering/shadergenerators.h" - -RenderThread::RenderThread() : - gizmos(nullptr), - share_ctx(nullptr), - ctx(nullptr), - seq(nullptr), - tex_width(-1), - tex_height(-1), - queued(false), - texture_failed(false), - ocio_lut_texture(0), - ocio_shader(nullptr), - running(true), - ocio_config_date(0), - front_buffer_switcher(false), - pipeline_program(nullptr) -{ - surface.create(); -} - -RenderThread::~RenderThread() { - surface.destroy(); -} - -void RenderThread::run() { - wait_lock_.lock(); - - while (running) { - if (!queued) { - wait_cond_.wait(&wait_lock_); - } - if (!running) { - break; - } - queued = false; - - if (share_ctx != nullptr) { - if (ctx != nullptr) { - ctx->makeCurrent(&surface); - - // if the sequence size has changed, we'll need to reinitialize the textures - if (seq->width() != tex_width || seq->height() != tex_height) { - delete_buffers(); - - // cache sequence values for future checks - tex_width = seq->width(); - tex_height = seq->height(); - } - - // create any buffers that don't yet exist - if (!composite_buffer.IsCreated()) { - composite_buffer.Create(ctx, seq->width(), seq->height()); - } - if (!front_buffer_1.IsCreated()) { - front_buffer_1.Create(ctx, seq->width(), seq->height()); - } - if (!front_buffer_2.IsCreated()) { - front_buffer_2.Create(ctx, seq->width(), seq->height()); - } - if (!back_buffer_1.IsCreated()) { - back_buffer_1.Create(ctx, seq->width(), seq->height()); - } - if (!back_buffer_2.IsCreated()) { - back_buffer_2.Create(ctx, seq->width(), seq->height()); - } - - // If there's no pipeline shader, create it now - if (pipeline_program == nullptr) { - delete_shaders(); - - pipeline_program = olive::shader::GetPipeline(); - } - - // If there's no OpenColorIO shader or the configuration has changed, (re-)create it now - if (olive::config.enable_color_management && ocio_shader == nullptr) { - destroy_ocio(); - - set_up_ocio(); - } - - // draw frame - paint(); - - front_buffer_switcher = !front_buffer_switcher; - - emit ready(); - } - } - } - - delete_ctx(); - - wait_lock_.unlock(); -} - -QMutex *RenderThread::get_texture_mutex() -{ - // return the mutex for the opposite texture being drawn to by the renderer - return front_buffer_switcher ? &front_mutex2 : &front_mutex1; -} - -const GLuint &RenderThread::get_texture() -{ - // return the opposite texture to the texture being drawn to by the renderer - return front_buffer_switcher ? front_buffer_2.texture() : front_buffer_1.texture(); -} - -void RenderThread::set_up_ocio() -{ - - OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); - - // Get current OCIO display from Config (or defaults if there is no setting) - QString display = olive::config.ocio_display; - if (display.isEmpty()) { - display = config->getDefaultDisplay(); - } - - QString view = olive::config.ocio_view; - if (view.isEmpty()) { - view = config->getDefaultView(display.toUtf8()); - } - - // Get current display stats - OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create(); - transform->setInputColorSpaceName(OCIO::ROLE_SCENE_LINEAR); - transform->setDisplay(display.toUtf8()); - transform->setView(view.toUtf8()); - - if (!olive::config.ocio_look.isEmpty()) { - transform->setLooksOverride(olive::config.ocio_look.toUtf8()); - transform->setLooksOverrideEnabled(true); - } - - try { - - // Using the current configuration, try to get an OCIO processor with a corresponding input and output colorspace - OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform); - - // Create a OCIO shader with this processor - ocio_shader = olive::shader::SetupOCIO(ctx, ocio_lut_texture, processor, true); - - } catch(OCIO::Exception & e) { - qCritical() << e.what(); - return; - } -} - -void RenderThread::destroy_ocio() -{ - // Destroy LUT texture - if (ocio_lut_texture > 0) { - ctx->functions()->glDeleteTextures(1, &ocio_lut_texture); - } - ocio_lut_texture = 0; - ocio_shader = nullptr; -} - -void RenderThread::paint() { - // set up compose_sequence() parameters - ComposeSequenceParams params; - params.viewer = nullptr; - params.ctx = ctx; - params.seq = seq; - params.type = olive::kTypeVideo; - params.texture_failed = false; - params.wait_for_mutexes = true; - params.playback_speed = playback_speed_; - params.pipeline = pipeline_program.get(); - params.backend_buffer1 = &back_buffer_1; - params.backend_buffer2 = &back_buffer_2; - params.main_buffer = &composite_buffer; - - // get currently selected gizmos - gizmos = seq->GetSelectedGizmo(); - params.gizmos = gizmos; - - QOpenGLFunctions* f = ctx->functions(); - - f->glEnable(GL_BLEND); - - // bind composite framebuffer for drawing - f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, composite_buffer.buffer()); - - // Clear framebuffer to nothing - f->glClearColor(0.0, 0.0, 0.0, 0.0); - f->glClear(GL_COLOR_BUFFER_BIT); - - // Compose the current frame - olive::rendering::compose_sequence(params); - - // Copy composite buffer to front buffer - // First lock the appropriate mutex for exclusivity - QMutex& active_mutex = front_buffer_switcher ? front_mutex1 : front_mutex2; - active_mutex.lock(); - - FramebufferObject& buffer = front_buffer_switcher ? front_buffer_1 : front_buffer_2; - - // Blit the composite buffer to one of the front buffers - - // If we're color managing, conver the linear composited frame to display color space - if (olive::config.enable_color_management && ocio_shader != nullptr) { - - olive::rendering::OCIOBlit(ocio_shader.get(), - ocio_lut_texture, - buffer, - composite_buffer.texture()); - - } else { - - // If we're not color managing, just blit normally - buffer.BindBuffer(); - f->glClear(GL_COLOR_BUFFER_BIT); - composite_buffer.BindTexture(); - olive::rendering::Blit(pipeline_program.get()); - composite_buffer.ReleaseTexture(); - buffer.ReleaseBuffer(); - - } - - // flush changes - f->glFinish(); - - f->glDisable(GL_BLEND); - - texture_failed = params.texture_failed; - - active_mutex.unlock(); - - if (!save_fn.isEmpty()) { - if (texture_failed) { - // texture failed, try again - queued = true; - } else { - f->glBindFramebuffer(GL_READ_FRAMEBUFFER, composite_buffer.buffer()); - QImage img(tex_width, tex_height, QImage::Format_RGBA8888_Premultiplied); - f->glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - img.save(save_fn); - f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - save_fn = ""; - } - } - - if (pixel_buffer != nullptr) { - - // set main framebuffer to the current read buffer - f->glBindFramebuffer(GL_READ_FRAMEBUFFER, composite_buffer.buffer()); - - // store pixels in buffer - f->glReadPixels(0, - 0, - pixel_buffer_linesize == 0 ? tex_width : pixel_buffer_linesize, - tex_height, - GL_RGBA, - GL_UNSIGNED_BYTE, - pixel_buffer); - - // release current read buffer - f->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - - pixel_buffer = nullptr; - } - - // release - f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -void RenderThread::start_render(QOpenGLContext *share, - Sequence* s, - int playback_speed, - const QString& save, - GLvoid* pixels, - int pixel_linesize, - int idivider) { - Q_UNUSED(idivider); - - seq = s; - - playback_speed_ = playback_speed; - - // stall any dependent actions - texture_failed = true; - - if (share != nullptr && (ctx == nullptr || ctx->shareContext() != share_ctx)) { - share_ctx = share; - delete_ctx(); - ctx = new QOpenGLContext(); - ctx->setFormat(share_ctx->format()); - ctx->setShareContext(share_ctx); - ctx->create(); - ctx->moveToThread(this); - } - - save_fn = save; - pixel_buffer = pixels; - pixel_buffer_linesize = pixel_linesize; - - queued = true; - - wait_cond_.wakeAll(); -} - -bool RenderThread::did_texture_fail() { - return texture_failed; -} - -void RenderThread::cancel() { - running = false; - wait_cond_.wakeAll(); - 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() { - composite_buffer.Destroy(); - front_buffer_1.Destroy(); - front_buffer_2.Destroy(); - back_buffer_1.Destroy(); - back_buffer_2.Destroy(); -} - -void RenderThread::delete_shaders() { - pipeline_program = nullptr; -} - -void RenderThread::delete_ctx() { - if (ctx != nullptr) { - delete_shaders(); - delete_buffers(); - destroy_ocio(); - } - - delete ctx; - ctx = nullptr; -} diff --git a/rendering/renderthread.h b/rendering/renderthread.h deleted file mode 100644 index e741060b2..000000000 --- a/rendering/renderthread.h +++ /dev/null @@ -1,116 +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 RENDERTHREAD_H -#define RENDERTHREAD_H - -#include -#include -#include -#include -#include -#include -#include - -#include "timeline/sequence.h" -#include "nodes/oldeffectnode.h" -#include "rendering/framebufferobject.h" -#include "qopenglshaderprogramptr.h" - -class RenderThread : public QThread { - Q_OBJECT -public: - RenderThread(); - ~RenderThread(); - void run(); - - QMutex* get_texture_mutex(); - const GLuint& get_texture(); - - OldEffectNode* gizmos; - void paint(); - void start_render(QOpenGLContext* share, - Sequence *s, - int playback_speed, - const QString &save = nullptr, - GLvoid *pixels = nullptr, - int pixel_linesize = 0, - int idivider = 0); - bool did_texture_fail(); - void cancel(); - void wait_until_paused(); - -public slots: - // cleanup functions - void delete_ctx(); - void delete_buffers(); - void delete_shaders(); - void destroy_ocio(); -signals: - void ready(); -private: - - // OpenColorIO functions - void set_up_ocio(); - - // OpenColorIO variables - GLuint ocio_lut_texture; - QOpenGLShaderProgramPtr ocio_shader; - qint64 ocio_config_date; - - FramebufferObject front_buffer_1; - QMutex front_mutex1; - - FramebufferObject front_buffer_2; - QMutex front_mutex2; - - FramebufferObject composite_buffer; - - bool front_buffer_switcher; - - QWaitCondition wait_cond_; - QMutex wait_lock_; - - QWaitCondition main_thread_wait_cond_; - QMutex main_thread_lock_; - - QOffscreenSurface surface; - QOpenGLContext* share_ctx; - QOpenGLContext* ctx; - QOpenGLShaderProgramPtr pipeline_program; - - FramebufferObject back_buffer_1; - FramebufferObject back_buffer_2; - - Sequence* seq; - - int playback_speed_; - int divider; - int tex_width; - int tex_height; - bool queued; - bool texture_failed; - bool running; - QString save_fn; - GLvoid *pixel_buffer; - int pixel_buffer_linesize; -}; - -#endif // RENDERTHREAD_H diff --git a/rendering/shadergenerators.cpp b/rendering/shadergenerators.cpp deleted file mode 100644 index 8964fcc84..000000000 --- a/rendering/shadergenerators.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include "shadergenerators.h" - -#include - -QOpenGLShaderProgramPtr olive::shader::GetPipeline(const QString& function_name, const QString& shader_code) -{ - QOpenGLShaderProgramPtr program = std::make_shared(); - - // Generate vertex shader - QString vert_shader = "#version 110\n" - "\n" - "#ifdef GL_ES\n" - "precision mediump int;\n" - "precision mediump float;\n" - "#endif\n" - "\n" - "uniform mat4 mvp_matrix;\n" - "\n" - "attribute vec4 a_position;\n" - "attribute vec2 a_texcoord;\n" - "\n" - "varying vec2 v_texcoord;\n" - "\n" - "void main() {\n" - " gl_Position = mvp_matrix * a_position;\n" - " v_texcoord = a_texcoord;\n" - "}\n"; - - // Generate fragment shader - QString frag_shader = "#version 110\n" - "\n" - "#ifdef GL_ES\n" - "precision mediump int;\n" - "precision mediump float;\n" - "#endif\n" - "\n" - "uniform sampler2D texture;\n" - "uniform float opacity;\n" - "uniform bool color_only;\n" - "uniform vec4 color_only_color;\n" - "varying vec2 v_texcoord;\n" - "\n"; - - // Finish the function with the main function - - // Check if additional code was passed to this function, add it here - if (shader_code.isEmpty()) { - - // If not, just add a pure main() function - - frag_shader.append("\n" - "void main() {\n" - " if (color_only) {\n" - " gl_FragColor = color_only_color;" - " } else {\n" - " vec4 color = texture2D(texture, v_texcoord)*opacity;\n" - " gl_FragColor = color;\n" - " }\n" - "}\n"); - - } else { - - // If additional code was passed, add it and reference it in main(). - // - // The function in the additional code is expected to be `vec4 function_name(vec4 color)`. The texture coordinate can be - // acquired through `v_texcoord`. - - frag_shader.append(shader_code); - - frag_shader.append(QString("\n" - "void main() {\n" - " vec4 color = %1(texture2D(texture, v_texcoord))*opacity;\n" - " gl_FragColor = color;\n" - "}\n").arg(function_name)); - - } - - - - - // Add shaders to program - program->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_shader); - program->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_shader); - program->link(); - - // Set opacity default to 100% - program->bind(); - program->setUniformValue("opacity", 1.0f); - program->release(); - - return program; -} - -QString olive::shader::GetAlphaDisassociateFunction(const QString &function_name) -{ - return QString("vec4 %1(vec4 col) {\n" - " if (col.a > 0.0) {\n" - " return vec4(col.rgb / col.a, col.a);" - " }\n" - " return col;\n" - "}\n").arg(function_name); -} - -QString olive::shader::GetAlphaReassociateFunction(const QString &function_name) -{ - return QString("vec4 %1(vec4 col) {\n" - " if (col.a > 0.0) {\n" - " return vec4(col.rgb * col.a, col.a);" - " }\n" - " return col;\n" - "}\n").arg(function_name); -} - -QString olive::shader::GetAlphaAssociateFunction(const QString &function_name) -{ - return QString("vec4 %1(vec4 col) {\n" - " return vec4(col.rgb * col.a, col.a);\n" - "}\n").arg(function_name); -} - -// copied from source code to OCIODisplay -const int OCIO_LUT3D_EDGE_SIZE = 32; - -// copied from source code to OCIODisplay, expanded from 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE -const int OCIO_NUM_3D_ENTRIES = 98304; - -QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx, - GLuint& lut_texture, - OCIO::ConstProcessorRcPtr processor, - bool alpha_is_associated) -{ - - QOpenGLExtraFunctions* xf = ctx->extraFunctions(); - - // Create LUT texture - xf->glGenTextures(1, &lut_texture); - - // Bind LUT - xf->glBindTexture(GL_TEXTURE_3D, lut_texture); - - // Set texture parameters - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - // Allocate storage for texture - xf->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB, - OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, - 0, GL_RGB,GL_FLOAT, nullptr); - - // - // SET UP GLSL SHADER - // - - OCIO::GpuShaderDesc shaderDesc; - const char* ocio_func_name = "OCIODisplay"; - shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0); - shaderDesc.setFunctionName(ocio_func_name); - shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE); - - // - // COMPUTE 3D LUT - // - - GLfloat* ocio_lut_data = new GLfloat[OCIO_NUM_3D_ENTRIES]; - processor->getGpuLut3D(ocio_lut_data, shaderDesc); - - // Upload LUT data to texture - xf->glTexSubImage3D(GL_TEXTURE_3D, 0, - 0, 0, 0, - OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, - GL_RGB, GL_FLOAT, ocio_lut_data); - - delete [] ocio_lut_data; - - // Create OCIO shader code - QString shader_text(processor->getGpuShaderText(shaderDesc)); - - QString shader_call; - - // Enforce alpha association - if (alpha_is_associated) { - - // If alpha is already associated, we'll need to disassociate and reassociate - shader_text.append("\n"); - - QString disassociate_func_name = "disassoc"; - shader_text.append(GetAlphaDisassociateFunction(disassociate_func_name)); - - QString reassociate_func_name = "reassoc"; - shader_text.append(GetAlphaReassociateFunction(reassociate_func_name)); - - // Make OCIO call pass through disassociate and reassociate function - shader_call = QString("%3(%1(%2(col), tex2));").arg(ocio_func_name, - disassociate_func_name, - reassociate_func_name); - - } else { - - // If alpha is not already associated, we can just associate after OCIO - - // Add associate function - QString associate_func_name = "assoc"; - shader_text.append(GetAlphaAssociateFunction(associate_func_name)); - - // Make OCIO call pass through associate function - shader_call = QString("%2(%1(col, tex2));").arg(ocio_func_name, associate_func_name); - - } - - // Add process() function, which GetPipeline() will call if specified - QString process_function_name = "process"; - shader_text.append(QString("\n" - "uniform sampler3D tex2;\n" - "\n" - "vec4 %2(vec4 col) {\n" - " return %1\n" - "}\n").arg(shader_call, process_function_name)); - - - // Get pipeline-based shader to inject OCIO shader into - QOpenGLShaderProgramPtr shader = olive::shader::GetPipeline(process_function_name, shader_text); - - // Release LUT - xf->glBindTexture(GL_TEXTURE_3D, 0); - - return shader; -} diff --git a/rendering/shadergenerators.h b/rendering/shadergenerators.h deleted file mode 100644 index d10c5b025..000000000 --- a/rendering/shadergenerators.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef SHADERGENERATORS_H -#define SHADERGENERATORS_H - -#include "qopenglshaderprogramptr.h" -#include "framebufferobject.h" -#include -namespace OCIO = OCIO_NAMESPACE::v1; - -namespace olive { -namespace shader { - -QOpenGLShaderProgramPtr GetPipeline(const QString &function_name = QString(), const QString &shader_code = QString()); - -QOpenGLShaderProgramPtr SetupOCIO(QOpenGLContext *ctx, - GLuint &lut_texture, - OCIO::ConstProcessorRcPtr processor, - bool alpha_is_associated); - -QString GetAlphaDisassociateFunction(const QString& function_name); -QString GetAlphaReassociateFunction(const QString& function_name); -QString GetAlphaAssociateFunction(const QString& function_name); - -} -} - -#endif // SHADERGENERATORS_H diff --git a/snap/gui/olive-editor.desktop b/snap/gui/olive-editor.desktop deleted file mode 100644 index 5734c00af..000000000 --- a/snap/gui/olive-editor.desktop +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Version=1.0 -Name=Olive -Comment=Professional open-source NLE video editor -Exec=olive-editor -Icon=${SNAP}/meta/gui/olive-editor.png -Terminal=false -Type=Application -Categories=AudioVideo;Recorder; -StartupNotify=true \ No newline at end of file diff --git a/snap/gui/olive-editor.png b/snap/gui/olive-editor.png deleted file mode 100644 index 477abe40beb72ea6a6fc9f4ac08306426d9219d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83647 zcmd3Ng;!L4wDuXg8|ji1Nh#@+?nb3kT9FbMhHmKw=`Lw0=`KO(mhP5j?%}=n`yalw zU>#tFIlsO4v->$=>Z)?s7~~iL0AMS~%V+`s0{9~WfQABIE@;!z$AS7 zh5%_9qyT`S_CZ=&UERj%vy+RBlQXS?v^1^rCnu{9_LczPF`ubrt*y2DO!R8`LP{wV zmZ0RMNsLCTDHQ=Die+M@L&sALrOTNk*6754^9G4xAUhQC>sMGLu?8DfIL0jM23_vg zfV|M~p}RG&JiF=EtF6(;`Wdn9^7G8vanueptR#6J4L%rFi4-;dYCwNa-`WO;gdYZj zGk}LyYeDDoKo0?~p&}wLpLd}C1Rx&2G0}hymGllS$`Cm2o>c042rLlN@j3Rj5*myM zkofXdst}Nng}^dXn6!XwB*0|Y+-x0CX9rA}eYbuCu*~aJF9`51fsPoG9ShJBT87F1 zHo`#pxNi6xK%WaBvQp|11ZLR*E(JX+dEk2^&@qOGSp%S90bClPK`#I#FTiAgp56lp zOa+K!&-6r2UsmF6vx1sRtr2Nr5PakJ4vqaIs-7MPHOrU+$x9-BQv}mA363t$RI*oo zytu39BLI*cOAJbT{@^i&Q#m%q|Fr?fn0>Du1^(R3Z2fU_yv$hw0M?8S!Wi2szB@$^4;{JjEz zvlge$KP+g7Fq?q2ad-H!_=8+FBLK5fi2DctMluW>+C#PC{b&FnlkLa)U6SIWla#Fk zg|ZWQu@m#≫P9ObH=r9Sb{{IG{h&nuRQ#6qVGP%$>9tZKu@qDPkLl}xdw{o|dbiPJ*wefmuA1$UiS*-^fogH>ru&W$@xl{o5p%E#-B&#LI#EJexZ(C}rV;}?HlP!#eiH*s6O zw<}FbPSP)vFViTK+i&BqJS@sAY|U1dJH*pTWd~hsR*O!nTn{; zWhF(W-i;R1_W6@E{x1UC^Z^}+Z%bso9x0F7d584k7w?&t7So$cnSPUo&SYxCj zy?h^?M5s9X7fv;#4Z9_z3rrJDlh*=cn zLxYd0wHb+ZV{c{mQG8pxPqRP^A2PMlf6G~uSU0%@oQFn)Dftg`B#UvRQ}itjv~4JUzWivo_GR)i zGrcyw>#%sC>WKg7!%@g$)(CIbi*E)zF2A}5q*paIC&V$c61nVF%Asn~YJS%B+w`2~ zoUwWpGv6Bv+)J-ak4eP-iG9ji7h4w*Sbnu^U_2tw(KygJtk&)H%{XX9+Ls<~0sjJ@ z0E%FY5NpIRKS{rL2zS?Cyy@D%iVH1R{;Qcgl#I-7k|dUl_OI~Y?5v=(890ckpu5^m z8H*kJfD@z+-I@M{YPw|_(GA674hjj<3l{(C9I8(~!JW+KKCvk6vLbUUlO(g8Zq2PG zSjDc$$0}CJVJk8((9GK`-p65OFfyf|sjpzKL@CI@TFLKd|8wR3@I2&i=3mTpFOn3_ z0YhicoUyKpprU6b90Y7aNfOGTs;?7HB=J~_pG7jB5xO&e#qjK+>au>$Il(^>IxGF2 zm0I;oo>k>b+(B$BpC>~vPXXIzQy_CmOsg`s@>06cw`XZ?v<|OCh1$3S;$mYyN|n;7 z#5Y*)S#Mdn4VPO6)jak(Ml^C#C!!A8)y9+~8?a+ENEPmAzh#+WMXj;6)U#?I4I2_n zD*N_w^l+qhXdy-*<2Va`NYF*F7S~V^tfa?IrN7lyZYx+L^3ihvW1SfJWw0(vxyX<3 z23ChDwX#FK>OpMq=YkGIM`g-t%JNR(uJ%g2GOTp>I_b{AutL@0<6%GIB;o@qJx;?+)1N7- zNl|Uh=;@dHayb1oKOZxX-Py7Ev2~&{`u@^8%Xn_=UZJmCQDY0uyG44Huc7{?aig-P z;!2LlZD&{uWj?O6b<&LdA0=o z#QZQe+%o6Rd{oh@)@pnqaVR+_y%aJf{_b&c_IT0Pw!=O9d}2}V3MD9D{4w@28dn-Q zIyHJY7(00X+iNjF!N2049(M1Gq{l7BnZA)c<~|Nrl04&tUQg}Mj7_9WE&#Z40l=OK00^Z30Ettaajz@@5#Cdf zk<|8>KQMI9AksO5|C|vuJ?F4TV!)Iq;)0RUTlIY2+x7gCa*0*+*vez3TC|-iI-YSk z5*|v1h$4}Y!P7F#VZWT2dUSP{_j~`_5qb*`h4E;SyY-i5@XNTp^j3GO5zQP+Di96- zxlCxxH%9FY1iJtIjTHF5zv7t!|GkO_z5t<>34OYv;iJI*_xfDs|A#kn0skuj9$goJ z2TJmEw$ECz3pG4+G8vL|hjeDy=(~ztJumR${z>-Di;Y-(BoF!w*;I}5W|xuoV)aP! zAIE#1Z$}3Toi9H@n7nPI_^nQA7ZXuZzL|*k{5qO+-yo9v1s3Ad4JO$Web^XP&05to z?eWm?Cw04Nle(t13zW`*7e%|!^4*(@f*|hc9#T7Xq5@f+sl)JGdpk!* zqu;Z$KcJ8IH|JTNTd5eh$j9}h3ndDq1U=l*7y;RKV?|W^ZS{=tT*Nv+7qG*Rv2w`g z$^zY%f|y*NtaYA`i~DLGFSlJ`AR)92)`-Z*(&Sua9eE7irkgBo6dj$MQdXijk_-fruPJ3&h@`Z%2;aVatFEUP;{2NO zm?xdge1Sf8AZ=@Fi)N`PZRyeY z%WlEL)vS56)~i>q{+-`=)1%QLJJV%752O_kAZco98WZEH^=35yx6*|hEhR)U zo5>#s&0K;M)IDBYUszk*{8Q$q>IU#Lh2#M4sofeVXdtq7kg8f zWMpI~H{Mc%n7beQp5z6EEiEep?-daojM9iMmS4Kp3`%;eS7r1t86~j%LtXD8xJK_i zmcPEd9~TNJCKix$5wCgcxGah+!P&f%3yo)16JzG#IpQdy=!aw|8J@ z$e(Q(A&KO9kNK-;ndde(HWHSWjG%B6i;D+~Ou40ddwqRrlk)WVpR}0B=hEWztLqn7d@B(UQ*DPHh@=KuB3>SN8e;t)#>yYuVbt~|CqEylhRq{C z5N($wOy)TYC#S$U+I3^s+DY!&*%>ou(?(pQXe5Mq*)kM?7z8>O(45++X3hdd2YgOC zQKNT$7mXK)WjTq^_4L1d$jyCDL_&heX&f4(8jho_tDBpf+hv8t)%P64N@o)LJL;eJ zXT##ti9ZRt@zjx7L8F-hpK*JSHxDW7JuecpR9~d=JIrH)I_xKqs_`sXX>oT-NJ_#e z;FOUk;X!#4yR?+Gh+BQ-&!3A&R2pyRyJ61u_hT=784a{0ND)BDp-61&-tz`Ga*E#W z{D9p_kR(*JqIjz#!N)TbHrbEO$0uR}*d zX4TgIY$n?s{k%IW$e_#i z$VPy*#r;2#nKkYSfZa}1nvD4><8}%Q1L`5Ky8skyDOx-{X1&lDY7TaGcKsGNcF?It zUBh$Bmw$X*9|2Y8{jB^1#)b6cKd{Q|>#Q$(C751UM?NnK>IAYUj<+^8OioripXaE7 zxug-@R!Ry*VNci zCx*+*!v(zzeK2`3Fr*7OH85ho>f0+TE29y*T6Cd7zzZ`+3#I%|-L$>oD?I5mu=_0d z{dUcAn-@G0FV2$Xv8LwL#nIBc|30Hm5xnnr*L~e(Je%Uu(%Tv1$FpSpV3_J51aQZaWxc`uzFXD)M!APD=lh(g@Qtaww|6j2%ti` z>{8pCp~RP*E&t~2+5<)9BqR@HWxDV{Add3^1d-=TIGdbVzK=JEIHDK7;5+yCR@-fV z|NeFK`6*?KCYk`B>zR^DCLq*Ho9h2C-W8$CnSdpIlNRtgUF#>9!=Rd zu-lZ2I!gKT4u)}obYT5}bJ3+;Zsb^$CjolrWNfO5t z^rN)6tI>$j0K_ld_wBSaG)(g-aYDKyz-WA)%>2#6tPS&dw!{W17}iLE${}%T!zv^R z5G>fs?khf5me$r;NH8mF>%8o2pyi-OsZo$~A-yrLxrBTwYHD_(4v|lV&&I}4LRtwC z%uRLGvOhjAG2LTi*3G zn5y_gv0pChmdEpi+5Y5^zs!L>lmYi%fib!-iCx4^xjqLn#!McrM?s)sk!ci7$*fv= zkqGO8TB#59jtpFVv>NC)1~)s2OPE0hK`f&$-n1`52QIhW28Z)lFs9250)~bZ*Bklu zbaj_~mOZycD=8qV(j8@tAES9e*ZPHs1tT>Q$GxJ6X~&9cb2@L{6T!HKA&zsmz>Z4`4h-z zH=SKr*!Noe-S%j@`}C6gN}IgiBfdVJUy7;UHwz>*#B2%*0G;9HP3HrcZ65ony$-VG z=H{3YX$>p#tKNL*oX@nYF101**L9HbacNVTOIQ512batx7B4!9nu)At>4wqxMt)CO z_SK|j{E&IYl5dxdhMotEP#|+jBdPWt%OGAjXcx{WwpSbJIP9kkWwWw=dga3P-I+F+ z7`r>hpAJplFrewThR^^xX#3_>e@u?5vNB9MsD5@oBRU3Rb~-tr;PFs+*1rB#xbUE1 z!7-Y`(x;%HfKk2x+YX!W)QMTJY3yiR#EszFvyA3E5zTO99bhgOY7nk55_`7 zo8(2~G>cK(Zs&QXKn_&O`t^(0yc?$niO}PCXrB-#J}@G*^uU0}2V& z5y6^2s6La028TYuVuR+-yU4!qyOnllQiv!uHt6XBJODxH<+)KimIO7Qt@bpwz~aeg zF47DHo4JPoR9smrE32Z1Ozbt3@-oAa&CTKJLNjbqQkH@w&7z)vlrZcwfq87NAP5#C zHRsKE$&P40LzphD|FfnD3doBTz`XaylfIjej!X3wZS5+8JCa0{EMSiU8?qmda&Tu~ zBF-C+$dtmD*!<)(;U?Oa=`d1pz`tOzb*;@EAkhHJ?_m|F)XQZg|EYzwm{#Ge(wBtFO_T z7RMOw7}u{X3dK1-tX1uKj?+gO(3%d4v_AO6J8x|y!Xp7|Bftr7mH;WrHN1Z8TDee$ z9tba$*+wgNLzK`U=1TN~naso)ayQ%a25-18b9MGbQD_(#ge4_C_V9Sn=|5XpZLPr)H%PEhgqNJkY}oqa4wb4upA+x~ zrAx3N7Z4?opNK(n06HR>=wm`fNtU`Rw7Qv$nvjwW>^zwM_!>2av(9~wO0`|qOBqrG z2fk%2OKQHgSGakwxe4IsD;PIm^(wo%t#UP|LQAK2e(V_mkWy+}HF{O&4Jj-hxUe=G z;V|cJw%{GA84_Bm|KRA@z=+Pz&p#%1+6wHV;{KJ&a- zp`6-U>V=$%jq=PLm4XhuS3r#umoYlUdQ+*%;0uht-v3zn!&Qs5D7+J{WzvQ zueYrKb>$_rzlL22KRi%^K}A6;Y!4$Nc~!#RV+->Do>&g0|J|D)W|svz}gbPy$a|Y!4C}rPT)GduLxu>sQlXQj-wz= zh(e=`Z)>fv!7c#;fF<(OQ*ZkB?zr6;#~p!g2C1{s@hL20k^?xK$K{8~ltU}-S4-|R zV)nD&nbGL{GBPMHj#p@!nlkeetPL(-jjX()c~{opulPsvp7M_xqb;jv3OCej_*P(A z?uC!@cX1KhhY$B@@M7+5UAx$xl!H(VK$7WCQyW}AI4ynK>C3%|22nSP8jM+sHdn!a z#I<#1oYE9<)JU}iQWUfF?)#cUZOZJd{9KltNhY=K%`~!vR2^;Oq)=B6@dF+qkj4orMT{Dxbm77(BkcuaCwt z8OW%k^xb(~>JRVqERp!}5=FQ;1|(Z1VqZ&!0)-)Mwm*I+95$)4GFy`8-k^RccAX`JoMjAqi0=s$pkrXl95{<}$ z*rZC*%T#%S)Z$jCVevI3j`>qbTUm($G`MV!S&xg|9Z-Cx&wdy3l(*l2d3z{p{7k^? z;VcxNzUC>GUU`eH$Y;AqJc7ZTt>mqL*33g>p?dsMOETN+a^W>2&e_b&0>OPoJ)Bn8 zllEiPT{O9LkMO>D=}5Fk|FuFc1o~I>26J}~MN*0dSe;{GVdY&VM)|&p&P7PP@&@G5eN#|D}u;|=f4c4D!A;bis z9Y&15Hlv<;DF`BMr$>A0j{6{Ea^&lc80lrEzzuL;XtLVjH!ybe!+sHr?z!P_QW_np z-%7EAc`@Xo!a{sD+n1TZMC;M{`-9*&itsr~&Oc&MGd}pK;$NP=3PN_9!&zb!3HRya zFabbuR{dm;XlLuv<(s$(E+j>9#gswD@`1t=F+7uWz<|tT7*YKPC8U>{+WF_$iM0vb z@T$LOGVDZ&YG&+5P7cIwrjkzzp+3v!-&|b?4b+1y1nKnzj3bi-43(;mK##^_!v&TzR!U|)={ugSB!?zquEwF+C|#^eLHNJ= z%Jg5~;7KIpHtxE(BhoTO7{3g$U}K~sMQq8QRO4z`Ay1%9+NK!>Lf;<8q3!VEVKI(x zLrxg|y*0Dr`F@=|E=d8UrD>rM8rA{qt-sl(sHRf8fjBL0BG!PpvO%rY=%${b>lEB1 z2x;*Qp*jC4vZ&ev9t?Ma1`poN+sD3pB}J7StgOvMzzYtJKJfIy%AVz=20>MNK2dwY zw!dqyH1C6FoHh_hxuHd-Cahon=3GRjh*N%qCeQjN6ydse(Fhb!*CJ#mqDTt;Kn(m$ zjYPZa$q~znzW z3h!9Ho`2TMgkw`AkEoWE_1HRWre~9vQ7~=KyKlijZan;b84BeNV0_zuY`u@W8b@oh z1?({TJLUj78V+Frg*Dqm?F1ibA>o(aHoNMSBG)Dt!-q3;Gg0H1#Z^`ClW5<2&?~wi zrazJ~(mWxVOJI*C!OR2vwYa4~_qA$mFD_;|UjuO@fQJ^DWJ%T?j4f?sWYj`)HTFyO zzUGpIO~0{2^8_W*>Cc%kQTuNR=iz^i__rq~;;t+{$&tPS(c&1>%*&tKHP#~;#Bj87 zejyY5!Uo?ctk!E?%2smxs&U&3`G*d=2OR=O1ew_C4}`@oKm=hm7~!?3@3vhx?X1_p z@@x@Yj0Npk-5p~84T3XT{ctThg=MaVY$e%!C0Wieu zIw}1VzW5~_!P$D!rN*GZIyg4g7egm4lpnA%zA0{gRN53;jIY(X(CUMDmV6k#GK+&$ znF?=^5tm!ca#|$B-E)@)L~0)tykCn^w`84c1?8L9Tu7lUo?*9=V|nUeGS~t?DqJdv zxY96Rgo}PumqQ|YQ=J1*wp6EgD{wl)*xC2_6Cy1~9X{y8+<13s2iA>yQ)L>)#<*`Z zhG@JFs_DTlQ44al(ZQib_jGDAfFb+d(s>X{V&t*r2YH&SO+qy+5s z*)9bXWj80QF<{vCTrx%#>S>(?`(^*WQfzg1D&Ho*J*kGCrxCVI;I_6w*JXqVftzZ= zfOYYt{$u`s_Szl(&T{f;SW?5o0(u_4$$Fr2=YX5TbubjZMkLa4@yK&Q{M>A+HRy8D z*<91eNA&6w0uhRp2fXy(d!A>c+DkSpV=ww9@}fIeTmNCZoDp?JR`<=-TGKpDJ=udq z1-T{@BcH+~0wQggvadL>Lag_m`w@nSb4^3nqo=M8lMF!VJa%fIOht=WEyFf8eZ0Mi zu^9Bf6|`B|+H8@0$oMNTBbW{S3C&WwcNyMtXM(4u-ZH#hYiT%P{D;n4A|t-`fcasZ zyOV&E{Xz=ieGAsBt8F7$32kD(06{z~{^FHB{A`&JB#~|iJ~69S{d3#~}`^-fPEBy7h_ET|NGnJHukbK8nk{tL^(Y+QKB(#@^boI(tPBH^Y!eX}h1WH3$byZ!kq z^||nKtvStW#{y^}H*M2PDD!yx#Mw;5(9Gbz6FJg%p3Augh5WE+RH~{bs)&mGpl!~4 z(TQvs;x>ve9lo-yg;K5DCfOh^B&dth4k-k}|65H2e+1n+~D2GvV`AaZ*h zC9?aJ{;QK70bQlCx>c*`4j-Lat;fvG1LT2fF1%9ls$Bvg=5GpL5 zTU?r#WF5Q-ZdboANs}>$`m+6#@JL2)CPNhQl>kdEleb+oG|!yRuWyVH)J=jQ`gLc~ zQb<_5wDctXkzy$Hm~w7`_}P{3o6f5Az&1kIc^hLVLG}p?9e}*l%^h$}<9*Wk8x@Dr zgBj4&)bs~|T)$8a{c$VJw)|su>r$x(Ngl?aFmckZwA4PhR^@dCDx^LvI$&8~XxQEB zaPz^7#e3U}o7v%+*8%#mvAkDwfIgbU;`)ir^9@U`*DetIeQmi=3D;lf(&P8rrC^iH zcZWLL>Ld3WwvEUY7V!ETK+oLq0ZW;b7sC8iqKlYs^?>4kT_)5H zLG_;`F!2EsQeY&{4-fv<(ga_aJ7!^t`Mm%Ek3&3S22wETNPV(dXvk&DY*NT zj$Yg3TomjpKd?b9l-#592o6ujFTScj(o{W?wmaOaXl;opXx%3G5A5GaU7AagldwL3zy|NfEyju2hy51|R zg8nvl(Ggd!XZFGnMS(c4{VOsWg7;B4iCA<6qN^chAC}x38{V_>Yddho-;Inw1)Kk< z(O*wUA&v!#HwHP)ce|gg6N~4}=bQIjnY$gje7WS#hQB^HRm}WXdBBLV>lutSjv9j& zvx$XxvcD9EGB@~mjKc9#-7~Rvq5DP%i-x}pC(xk-r%}NPSe;FT;|@*? z5{5sV*E|JQyw49vT{7&Wt{AE?^r}5ME{>HMiD(tDhbH-V{ zeS1+c-UJL;7Oc?qCI%()-Dnv}pLw$wKtW7_hrmNxvT!01f5lt1UVjcB`Hp;Q7ns#( zw`>Tkgs8vv^3#yHB-*#}H?B1#dlO7+mv?rrh)1R+rMXEWfQudg_LV~5Xz=NvYC8;$ zw`L=Ee*|3wyLy(4ntjkZq;Jj-pjMgiNHQL`1#r=2%owO1u)(}kQvxNlsz?i>x)ip@ zcpt~;bxxf+OY1ApC!VLe5{z`B03~uO&YDmBfx*X`z7lwY?()W0JC})fuvcfY;!oIN zg>ul@v$&yZ(}fU*)j2^{s}TpP!5>VT5++}+XaQ5VF1D`FprFz(*RZ!gxf!*~p3_dd z1Tf3!)ZIuuC(tfMAlh<~B}HRY4@D?d<9%n>@HaIps}tQ^wF9;Y`5=HmY7UmP*z>UcJFMl-T+Ema^>-93> z_h&aLZJ!&G){b-U8CmB<+nrQ(MCfyMopk0gq&2OaouJRQh#iMM$zIIQ#$kt0WbSwbbUG_!nCA*%2p#Yv7c)V# zSlwYEHP95FJyMbsqH(!Qe|z;(omSExVHC|IGAFkIAsTwgQmB^lwe9XGb9&!&WQ~}Z z_)J5N>hd30f#KfXpN}_w8NtBtmGuh8|K%VJw*TYI_kt96*LN4Y@jj=$B)&3eg9lS( zdMzH0#`f0;SsZtNG#^EJn6z9(W7*Y=&vs3Lxxa|cnvjLpkkCy0Ul#DZKhujL>gO| z@%fq>`Jc8nu!Rm@mlX}GA1 zzKZcx%&>s%|5T|?aYe-&7NWPVLobRbA?z=H>1Wh+9_muF3<1CGSDlBlt{zA8+mnsH z>>9MMi1RWtqk@Yy#g;Q)mt6{dt)^!+Y^e@jj5Jx_i@M=86U_phU!e)}6jv$e5=68k zwQs5>nmF-$os>oLu~D*hN)vK@CMnS6=Zet(t{s)!FWfcHD>}6i!IVPB4<<_xRzD%3 zO-UhI4MaoKUy$ltav@A{af35cDMr>5qqoJISRdd~u1vI&XvMjSNVaru9NHA4T;EQu zc3omlP}+87F=b>nxNM!@aM}E#EjOq|0ewXJY45*1{(3#K_Pw*zqh~Y=?tvQ}AUBy+ zJ8is$1;9aa!$%ce-RVa^3E*jG$VIBWU)|QQ0roQQ%eqYoLd&f$h6#!pcK1V%9`=8w zs=dQi961b?k-Tt-ME-Ip&H`b`1flhSh3CMq@7hW$Q+CRX#A<3HJ6LV>dl+rR^*)!p zbaoa;-j@5Hnw8hM&&43?#JHlHS#)wYXVSMOQgcm}&et~k);(>wmv^%bRE=ME@=f|O zOe$u!adO8Q^N|>12Y#@ukgX^{G-#7G2U&+vmP&Q}YLx#bgZ?e@a8t%zb+nTED|4 z9`7A2;WHP4XzjBqhp6En1eWJb%GIT2#NTdrOX|it!L7HInaR_!+?QNuK9kVH#!+|v zZTi(wu=;kiOt0W}_|AVQIutVN3H5^fH_#a!RRJw^y$~^5XCBXvFMEDpZy`SVmdVOL zG8NB;0pU~qZH!6P_GbM31qQ?#`#U=)OkCJm;pE((=$+tw{NBj)JW?x?p^rv1XFlJK zTJuk4sx`>?cgp06+9R#$>zV&F8tf{X593AY_!213MM7pYCi;0jAfHs#317R8Fs6m)wuK{-VP}u zkz8JG-yN~Iy6TWe7W*2;9M0$~{08_wOHN6SX*=%k?e^a+>iYcj_&gj!zCB^oKhc1v zoiWbDEf&DFaNp6txS;TtRf*Uj)3UdGk?72nV%;Ws*)2EEl-8Ia)g^*EhXHCAt$*vd>r>(VY7Qo;A`aA?_@=6Wk?y;kuNeDnaFKZ&FJH5Z-0@@v{>sUaF; z)>>!ZUwR5mi|O?qzlvperNAT{%OrBst8pu}=I)EUG%cql7;SV_l}=~!4t1ED3k&ia zZB;6+k4=feOzT=TphJIr{Nt7ol;gs{Wg~bG+hZd{4o`#rLwXh}HhJLU;(PhH1Te2( ziR03)#^OpW1p9#-G|}}($IC~Q3mT7u>i$ZQ@RN}e8|w!)3kESBOM$cQI6Up}~D<7VE7WAIzQ=g(}yj#v)v9c)&z zNasJ?zesrhH}|kQ^oPe6^94~)g(*SWFVCtL9_+oa`}u>-XmyKWzK$a=8=3|LjmJcO0!ATsTh&?BUm@~^F|z=a*o!KEMX zIYd!O$@)F$#9H9&`5*}4$(7v*H;JVUfAqomw5~!W6?SN~N!<1htwZIe(M{7fN>f=kwNP^x zvzLQfRON;_k!Cf6C(;|Tw8q5)zu^KHHO}#4*`+(MbcS^GJGAe=umD6!-3$h@oqeTI z9u~{=A5<{dI5<#%8jyn`S_8H{$sK>gPFZme_+=&B2OuY`S3K*FPe~6m5YJaqQu6Kk zBPRzG|DBtCb&XL;;*BCpH64QLyfV-9@np{M^lHfPeBOjX7x^lf}e#xrtb z5|4Ji=glYRyBL%B>yx_p8{Fy5^$%MwBQjiKYK1zcJ+*7JFwX@wL`Ivq<;Zh@?vHPc zo2aAV2|xFqMlm@c?H~{jUXW~bn@dk4aWr-V7{;M<;mk!>v>k(coPPpfM(#1WRZ4EH zxgfSLo;UHl3f8N7*T{6Q#=bwJy!AVTByU9fI`Y%pL!aI9;@YavyGfeWxz6#D`!=R; z(=7kANij;Y8;n(N^H{XKy*(81f3xPkEhk-= z$9}yiJMSZ*VTM0lOp>L6_kSN@sB_~_v=we}G`Ni*(GGo>ls&&|Cx&;=57oOprxBfg z6Pk#ughoQ+5@UN(ARrRb&c3yEJ+&2u7V)S5;@g@^_WH$lb4IiJpzqB1XGCfq;z1ki z{yTDPR4TLyd#A~z3`fuB-q*+_oqJt`|!^Nrh%pGT8Z8_0p{&NpH3l9x zze9%;Q5RZ-k%z5+UpS}2#dpUYf@+S#oh$I@sJNNdm*Y9;fNi1incGG4Ks0+7EOB2l zG~jo4#;-MKq0LFV9}-tvk9r~bh0{omvX@HgbjnT{u`wNIN(dq7GZoYLxf(+S)-Sg0c-|T;=2Vm{Gqab&bpJk4>J^INYGxImNKzj6zoZbz(AnGXkw1GLB&=| zS91J#%Q1cMK0c|*2h8RmA9G-IRMZ0;0{43aBING;X*OfYei;lb#yu)m!VTT#7@wfx zzEho1$9pq3S3^isbw7*pQP9)}S{-|>9(C zSHp|L<@Xm%rRil_V(r!z7TM+H;FEe*BPqgebC$`JGFKSR?ASyo61O?NRXDz~$?d*` zQV1Zcm4%&MW%#tU`T|>fO7FvlSX{u?q@=g0)r0Vldxs^A3}mKTov^d}s9WgP*!s8^ zs_M(1eAM2pK5q@rk53-o?Yp|asWK#vcJuj6@^<6vD)Or6ZOQ{uXj@~bpu6A_pJO#0 z#QP@Oe)~;zEGpUOT_Fs0BdxF2P$(0-i}!~QFFv`rNTQ)HdTwXJx3FOPnTRcv7!oZp zXVJ(H!@&L1Fz*p0+1#NZ_|-|mIXOJ>iCu}4ia6y2F1S&vC3m{XkomOLZ2QNG3li~Xnj8iAaIyM0;MVx|v(+(!oszX>QhE_<+=goX^@IbPHgmNF79Tk?4G5v>N ziFZZq)>01lc5=DVNhQPc33W4D^Ja}BkGc$8_0|=2cyvp8`ic#7Jpn}lub1-xjmvz? z!ruw|iRa3e*$EQ$d{h8Soh$j=3yAr=c2(CG6-xx2sjattCTA!B)^H<7{{dgt>Pe?u z{>2D#fFxL&nSpeL6y6V$51l5?D_dJu$Z!8XhGTb_omnObyju^?z|U`5pqxvOn7^_o;grmz-3%6A+^iK!y%S^RDG6b zyR3$oZQKqYe_COwlhrPpA00PUxOt%By*6Kzp00}Nw!q-`xt`ItahJoKL%<wk032m6aG|JecrdSRQVx<0jHUl@Dn?J zK6Nk<)~$flq4)K zQ+`*=OIbYLPf^Ohy18Pciir^uACH(du6G8mYVLdSF`R1<-N@*( zYndT^dl%a@uboYfvLypJ5Mz?!+Iy!WPWStaRcwtZ-0K56#|wXDn#4T553()06d)=Z zJVA}9j>a>yUi>7;b4ujcJVVx>6+XzKGh`GRGiJfo^KDVS#kXi1%Eq0f%BkB?{6Mx% z`uZ02M8$su4`N>FQdm(1D;;lR4Ku^DU`0%1Nf|on-lO5F@nCS{oD(hBZUE`z;9P+8 zwexB(A}WrzXjJ8Fq|TrhZ)i=31_!Iv<+-sm^b{g^NYR)% zu0u5>c#Pag{jnjOe~9jFw7?j@I+F$kDpYa_6kPw(QD<(i@uBuU$NY52hgakdtI%oA z8yM65P@soI8d|;G069i;K~KfhR^fZtgIGXXezd25c-15wGlE z-2HM&kA?^fB?M&d7Kxm4mIt4nhDWojW$8yk`CsbfYLr9ykG~Pje1%$hui&3Y@11Rj z7T`-|zv43;7oXsg$aVIuDVEMXF0!QoIooykA5WUc4Kfa|1r>D&m&a4i?eA#keVMeQ z&v~p|vHxtF2+eT3Q-lvQs}}B)oala{Ndnf%MNC zNW3G?bd%cWMUz1AhFi_8fMi%#LV%t+esVpf?UC>g-;C{n&zFAI3e3dbJ-M*n1G&(# zExEA41MBbieq5RL(YxhPk?yRIAvVy;>g5Rt60CupN1^B-V&PV1nz5DU{L!e&Tyf(; z`;h)wb!fpk+kLCmF$dAZHwO-eMeh>MKy#(~(dyd_C5G8;%XgS=FhwN3DB;tiGk2~1 zOalM=dvBlvWWIi+Kd|(BwJ6;BS&=B4XAAf-^^kr72cNO=&KTc*IWjgTndD~mI zue)A!DIPFDzE6~Rec+4nd_Pa^xmzD=W=^Me$nZzILvy!PJWY8&15Ynj+*m^$h10O zr+!VkdKD4aigLFna->DD20Wt3BP7iL}{axjGS}dZ(p}oHq zA}^{&%))!yS4DetdOz{g6&N<`yO{7>PxmQa%#Z{H1pzRPJXynC37}cIQKE^EoI!QW zm;QXk_wKMUi%mfj>gLwaIg;?|#&N;DxV+-eTh&jSKB|+{Jj)v_#}SEFyOCGtNa9<~ zETsQK(pg7E^}SvE4l{J8bR!}1r8|a@mPR_HJEdz#K|n%U8l=0Cl#~uZ5D*X~B&C~q zufKP#S!@2Cd*{S+_OtirL@YYkEmN+k-+Ct7ZG3PVHyyZ+#Q2lz2TWc$P5qi=F#io7 z%%-9?cpYKj2Wb(>n!?whh^}CA3#(WZp=DdYeidah`IyT}5wps^_?qR(I3XkmQT@ z2q}wNgLq!N>(9Zyb@zTlaK-%;Z>p4@>f&g>DxaIU?{m+v3BmZCN@2TReT%0xHmvo% zhbM>7uqX|$tw9TDIa>GdbNv;tI9tc^Y3IxI3nuxvHu9qb#9YC$C@I!-CIKLHyf%K{ zb9dA+mB`F41O|*EOto0dTyH5kw5!L1-xtna8Z&yAtx4bSj{n{vZU3+}^+P^f@jzvtI*|5L zd>P@mfdIN~yx24Aoyxj8g4EPh(1kMvwkbN0zK0;q14>`D|NK*95kTV%FmF8EL9V0l zX#62SN=i!cIq>~^^b{DW`X8m7VzN>gFXVBaaT zT1|nQ$9P{-&fE~wo8kDz=EhU?Cij00=ZH5?Fz7MgAeupj$$~-wL{9rs9LxM8>%~n* z`FNVJo&TdKQzZ}b^d6w^MOTsPCH+vV_=Ei!8yno)TX1iGzwrpHq@+wdCj`{@*$}n= zUSuYeVC+t)AOz@Ukd4aD!8=A?(ezjbUHCuip8BRiIoF-CRL<@f93m+=_eS6JH3(?uw zPU*Q0`DdjC-9ROJGs5XV9+2N^ym8`|NTF5V&6#B8EsE6;j;(L=c@FL&Md;0%l6@DM z-h)ruu6sV5E<{|#U&Unu$!!}drKhcf%Q|F1OhY`X5er~0OGs~T{H`maAHZDMpY#pU z@k%+NeeJE6`lA^w2?K1l?%0z)Wukv=SPK+7jD#IO55^}}ep(Dg{n~LdM3s;$;<+tW z=K*2FBS92=sDqBu2#*WHhnMf@B>c|@f$2)U+7#N}zC&zHT{F}XR(rC-#+?7Wta3${ z??1zl_vTOOHPaU{po=X&vGF474T8@?hNcyc!jnRi$Peh^WZDVFveJLWF8!xLQQoBK zM=7tOGcWUwr1gJ)rH7INd2i&#N^>)JqYvfQ81$wXz7Xm9SssJjI_uQul|wn)@1;oa z$}Q6+$MQ4l(rPe$2u_E$HI0&UUiz?CGWki^z1lDzHeEMcMU-==n*i|NeSdZLz+zxv zz+Qc)m-$Y_aeEPySvVQf=zcAB@vU~s)0qT9&sn}lzvDcDLYCG6L_g8QP(nktCEFrn zIfjBQU3}8q-;jll8%g)l38`e|Ee=D3lSykFExL^)l+d&Xi~|dr^ALv1i6wt7 zL{*zw<3_>otVZEZg1q<3({#)syz`md9J+se+_80u5V)F}nlk=+>1bYEqkU<0OP+0N z!~BiPKqK0`0iGROh*4EuZ`X)AR!T_cM<*w9PA;}KdgU7`MnX*VD^c?F0}o8Bd6@`G z84RIFLi_ii!%2gQL+8alu$WfBv4;egY+9n)N2$zJ&WPl)8*UCdxO&#MXU+J4laMLU z$J4&|X}QEww%r&|uI~yK>;8G~tUQ%aQ2FNPR=C)Ih!2cy{T>ieB2a;UNCm$B^XDjm zkpMSf7t9ZgcJqVv&U{ww0Zp+lGs0DcQDy%8y%`Mp#8v{%^>5lJxEe zJ<0tbCplJ(V>7cAwtX3>CNYI+&MA-gq;V8;LM@DgM;1!=-wk;{`e9CkOX$PxML(EZ z{HJ0E9(P@FWeT~j%B!`q=is95ex(LhL*6^w@>veWJ%c3bus%NMoDe%?IjWAD+1`JR zUmv!w^qW5+9+F1J@!@3GbM=Y;*J0FP+AwMs6=&)B{-xs0$2$!QTO1MS1IokS(Iq{4 z+pij7?`&|cSrk_z&t|;MW3|(7p?4J3tq9{tQv`4s2}$k;5+T=M zO0Y``IA|E-V!t~bQe^5jJWE{_O%BsSQ7RE-E^f|BIlrLHE^htEzq+ts@Ag45u{XWO zH~s!(G|zX{b}1lEq&4PYsr=0_Y?$6`)OB7&v~Df*>($m~3`>G6ro#HzUr1aicb5RK zoiS7IhU~xidm^kUOcqtk!d7kTt}H`4K~jn@)qYuf*BK2{XY~A9Dx6u9O%;-a!7MLL z-b+%VizvsT`|puF;OYmJL3dTkeKx3Bp@Po^2h-p92ze}$ur3vPb-lTQ5kwR8zjnO^ zskQM;K6SQ4Le)7i6~B1xUv*3)J~rL05dnE7{FV!R4eW=8^XT2evdgN{if zKv_h4)5vf0|Cqmv3fVZCqTyWOyMFVd)Z@hqq4mbgax|KrC6FoOiE~qdDa%C`R%qy^ z>BL(6Qwth}*E7h(lO}laUUu|64h+qK z8wdu&BX}Olh54u<)MhyJU2H!c->aK+hOGVl)jtJjEuSmA#_BdfRu7)r4&1~Pt(tAf zpiC+Qwm+q8W!kMDhQt0y6nH3%R|${;L4iR_(T_ZHLUT;U#9*lQ6&lw(5jw*@rf^+4 zCe~N5WXL6AP^_b*&lCrCT4;44`P6SQz0NW7hZO!4=%Lo%K+csz)zd@XLGS1=GE3xH z$Vf>Gy1Qw?5=I!>yPqAr*$)i3UoO$0?nYAsrY8yv0GKv1UxU+YY+v2Y{9D#%9=Xbl z^9LWT_h>d*v$cFiruaYJatCPB8L6&GUyR|~EJRUa)}6IeKrn!4dw-=nOEFCUxrG{@$TgA;#k}FWJ-K{`tUeF_f$Yg*KilyqATcK= zXZF8Gn|>ksIX3K>OY6Y5(A}fYJB$gN~`8tDc~@ZnBF1VdF5&Qb!TJgU7R(S5(k2S-K~v{44mc zj61hG|xt@<45VyP{%Gg~PiGb*E^H;=wEzVTRDSDau(QQ>?r=X-9%_9nj zQj7jADcft^*awBC#hwaY4Yabj7-lI385lfq?v68N>UFk{bzzk}F?~s`?fBO_zB5?U zy}!-GF%g7u#c_TX688<&$lK+M>vBkcMjsEmh*Z$+xwNh>>6;vz-8SC=_#q|QZZrpA zd)Y%sl~ntAuYx^g*1X~avirw*{2;CM-1!*`6ZK5Qvjg>mi(|BU+}F(A9_oMH<-LSNfulB1@H5$*`;t2HU?qjsRF zNCu!uh3#fNNCn?t^8xfyQc~7tpX-B}Ug_0D{r=#@84|~9v`P12DP8paw5DT4>PdUu zz5A5WH&xc8&q%rGP;&B7*)6uSbe6#PrpN;?PJ^BSi}6!U#bC@ibq3TXq#W3_XD%Ag z`KbX`bUzg~ZVKJApe!nn#Al6|)SnRJ@^}LnjoN5u18`#$A$5!aAyVG&&wq5n_8q>z zHec;c$?gM>u5$|umiN~uwkX#)NArMkm~E#DC1Cou=Q(U0EK9(uq#sh8a)lf|rJGpn z{?4eCaOdfD&wX7K-_}igg&v)W4U9VVMEqTNH^7%gT#jarc|=TwXcO zmA<+xoxi8@DvX22Vt*M$ohC1;5)C2udi2jJH#(GRTaGsTG?2V*eE4g9!(e+$k7@<~zG<&Cck}KAr^O#> zY$b*@z$*i1@+M9A8nnflPaPL}cLPjE>dY0$1uqywMyo$92h}s}qH_!$VMy^mleXwV z5F}e3-chRSB?meHPtob|=_K!A|I^ohq;oB|<1h#m3xuvys@tgs40OVIaE&C7iu(#v ze>SceFH<3jc1W(z|>Z%TDg#X09^UCW}9XaO?=#-31dWk@_)h06^PXh5%R!WNl% zcXjqlqvV?GT0{Bm;LtWZ*{64Qx;VEf*&^K)Q1_W~iVn zf`?D4cbnVq+^hZ~{MYK8!-XC=POz}B>bwsPt*oqYMn^}n1o`=!dev~p_g{R^eT}%p zfDBYTfGP2iyXCd_3=z{{%QEE)a)1B3rQ^h_*qH?N%W0!~c|u;%J5{k{h#%9J1O36C z?{pP-qa700SJ}(uoR7hs$v$_qspaMoze<<#h(y(!^JZubu|iptwj@y#=#7<^Wo6L;M!&UJpb66)4)<29wKzQ+xO?s}4ep=su0psStn`S2^i#lJ||gU2?FIJc`)7g@1)O(5E3UqxTHeYQITh(W+?QwHa2+t`N=wpmc@jz zEnH#BI*q@ls*uHL=#?__Y|fbZM2GFlI+gJ?P*QHR#4n+AgIDT?viBcg6aRId0Zzw% zFoyJ&d-^CIrlN7xw@B=urcakPzL8xQJfy!lf<0to{v$YfmZ-N-bC+muUi!IMhmMVreOX&mo;(-CWS=kmzcbL*BH5>gTpb5P-) z_R2Y!4y7SOvpXh$>)a!gRk(iqH~#}U=FKJRS^VSGrmLx)klh-p;5)-NzCUqK6VUGh z`Yvui%jF~6_S>eogTMI*tQBw>KRGkT{UbI&mcg_Ckn=KeKvo?5h#KtzGp`MHEI#gt zuulKUIxPSg3BeG5eVK>mXdm$T{fFANjd$Th7|^EJX>W~3a7l*s3b}6#5Cb5WM9A9g zcC5ur_>xuZNz)&Ovt#$Emt6MxwG{4ue-eu=cr^qfqkoVH^Gt?JJwp8BC6f>sxSO%> zrYv(SdBPR;d(6J zVC%1rls}(3#j80S4;Jf(zjRPfM<%rFM*0KZ;=~n(VI~PAu1VTC}HLD^%U8 zx$!4v>8ZCp4VD`=#?T4sEknffD8~x1K&)9Hp#~<^hLDHG-EXdcsR9i}(BGy}N2&gx z8KPVbfq~)vnLb0DU|jC>7XuIAq3>6ph5F5E=Dmv_Fp&DV;H74{BD&qIc8s0h)6%YI zQ}+F~_794UpTA8_#sw|(?{d^yo%6V0icMM`Te-$VLpp#j9%a z3e0E8WpM}WJE<;PXNke&*zhO=2qYg5E#o)MbSFG0Q_EX;slas;L+R^`ds(&qS*g() z$&?@8(2nRcl88W^wuyXHV*`*HW(<;~@?>q2i1 zPT5aTjKhHp$Uv-s)AK*yN+IRW4;}e|p_iYYp5^Ht{jw+jt3*G9D2(R1i`Bf{G5r37 z^*{QVY)I|Y#VCzNfuZ|zx-YDxc?0998J~A_v~Maauyi$F%EGNHtTCeB`bH~E1r?W{ zw>}q4yto3Ew`r;N+*XOVhcVqSt6SG95Nnf4}hk)ENA|aeaeg=&=7ewwa z*pBg-#TzUuE~T)}(B6p;+Z}N)Zr1-9P+EqZ*(RLCu>RpYXvDn1roNNwVkN-bb_RLV z&H-#(2TqA2;^N|hfkaS@O#aWb#WHhZQ^-+*y}mh&e=!ftBL2o+Ct+n^9z{E=&{34T zVZ|zFM!jvNc{We}Sf+YnJ)gd~R5u?aCgZl(T`Hr?xm7E#!yPHDtJ8&S$$uaPfiQ75 zQHhsG&Q`yyys4NAzm^4K_SSY`uShjAIkqpyq&=m-eJDPwEdH)54Pjo0tQa!(U>9$J42+s+7uy1;tT zJL|Slr-Bml-iTv`p=$JV%q4b5=+nXYwy?T9t$C|i+ z8zuVacQ(Z?CTX&x1agQ*U3lUU-Xh`r6a5jbHco$$AZ18szAjo7Z%2^xWzy5C8e`{v zDjXsV(uyuxlDZR=ze)_6?(8;%%57WFw!xbmWs%H4#P^}cF3GhrdlpHs^AJ3&PI^T0 z1!4x+9{8Z8)P*Ukz>>h9#$+f7WPC;ax3wkA4c;idlgg{JlLXM`>lQkv&IW}=P{_&C zoDHHrYnUj%Nex9g0L65LAq=QSlPs^f=ok=BN8e5lc)Wi7%NJgxs2a)nqaKE%YI(Vt z(D&-nR^XQBk#FeWBq%JSzQW4GL-AV0zxL zYH)l=Io&a5Wpu>q%+lSApLcC@*-3wByPl3MXkv@zS0Dg|F#BH~DF0q4qg({!Gdw!f zHv-Z|c7*7n$|t0C+lG)YKVNL1XOWtj_WO)?&ItARW3uQ)0Ic>#k3vA7gBAtDz|Pst z0c`-4)ysKGF|X&Zym-=NSMmhiEb=PL19#U!9}1f)rIvul?eoDM!QtAfA5gLkMlc=$)bb#VG^ zVANoA^es?ci8M26B@>tsNDS0kIh8sSIM_mnFXv%05Vmpb`R1#3GQ)+S^yO%9C0}IA zaRH7_iN-w^t=X;c(aOHsSAKsCV~<4^;p50N0v8NfEX90?gCKTtG>o*uv7s0|Uie2d zQ=1d2k5jb`1A?& zEsghL3K(^^XpTJd3XN26AsG982KK9i!jYu?YS0-h)_`=_Zzj)ZkE5yszavm9X=oz2--JF50+nm%_OJ zJ>D`F%VTQ6jmp%=Ao(d+Byh0sI{L$!LPh%aXKgcvbX7L%2ZL0%v!{8?iqt<}D!q}( ze|bS!>=0r8day5r8~}M$Aei7^n{kLKi)b;vNANis{If4$K>_gq-TLr;Eak|m3R7## zlg4>(B84C5J`pWi(lsP?y2^qq@?I#1VFvpNu>?6!dKDN@nLAszB&t^1m%Nr6FU7DQ z8t<59Nu=A@;}o@F%8E0}DDe&OBJbqOLp zH9pj@et%aWkmf3mpUXnFqaFz%7{sS1)W{>l^4-09>vsG*;8*&6OHg1kK2ms(u5GtD zmcRuE6kzj%pOerN|48F!l7WCrBm5)_{X;n{I`x9?nK+Psye@;T*0%O)7FU53(U=}v zM4i3x95mv7`aMVSS$!eWMH~Rj40Z*SSp!r+2(}KA_101eWI#i)mJFanQz0)~#_+iv z>JAqp$rUKC37qBhcN0!^sPsb`Scn6f`}(JAPnv0FWFT@+L6*z&Q8Mw?bCHEL;i@;} zlPjC55mf#Ev~3q0rdcAMN)%N|lrOmSv>Ocm(59&6yyEUFMB_=q6Crp?!w%6`=ZDwP z&CWq85-mcmt{sKUu+MnR!*n6{HPLHiZDTqR0{p2wlzdRfzOtf^#6&bZ9l54ahQAmTr}F?O$-xCDtIxE0pQWj3lB5D3UR)d28G@^OuU8qCn>9D2K8{LNE{_-%l*4ca&Z`1gnu&eeT-kwqzy)yNqfb*F&I9QNZE~$OOaw2V7^ScC$dZ2NMcDa zw>_KOg~+hG2=Ad;)pN>GGEquvV5j5LxBV*`W+#*R{Z$L|hWDSWA3U+-tgL)hD(ADc zy^R8Zkv91+V(9eJ6LTU2z(y#LArA++N_6yIF!=Ib>kFDt$4ojQyFz8fHX`^?)jdMa z->|i%MIiTzE)uPdgb15w?4C&yg`K{DOY1El$@xm3D@9v?G2y*+Pg%R}`Q~ zhDFbVnQS)eOC~1?vS3jl(V@VAzZ3H0&6k1}r@(Vfyz!xk-+ zM*KHpyiXmU5o*k`LDtHpQKIt@@@!=D|Mh(wTN@bZSAV}`oyTxze(Un>3_6=IB)glt^)JdJWfcq?1^eD z#F&~uJ}Al_>%)3~0MTa5fR>9(O`g^sYeaDz#7#k4Alg7=1StF%B!|jC5@9!W@k)b! z$RapQ&B2l>yama8eBFITc@>l~oI7qEkhb2f#1ZoMFBzQWkm(Zu(PlF>xFeFkT*57S zC$Dhm@d(+mG}zMObk#>=gzBKNp<-Cm>!4hpQvR!@?Rp(=-K}w~s_(_gEF~HxTD#Lj z;R{b9LJ3LDqgKu7<|J_PU(ulJY#Q$QD@VHUkr&XW zUDLlmJRH_Qj!!gR(av^~E?*i=bu&PF*&tR}M2WqO97iU;bdSx*p2R2Pjm}3O0^4rN zjJP+ODau^S(399Rf`Kgz66O`-Aw!-bY%?)ki$-uAX!rpP;FXi`*OI zdC6Fc{qu#2c8So@jLRiEa&(sfG`1uR!SBukTp}G!;OqkTB2X*;1`-89AkNg}1!#PG$P~la*{2QW$ z8AEL&YlTwia07@jin$G|`>ans9K~7OKO5&7m{3@WdnVOM#2{j&3)$7nye&%&XNUv9 zt+Prq(Tx^fv_Xck0C%?I}P1@SH?t0^bVM=i2{Hb@gbXp&4Yu3lvjX` z;H%!DT|1S1=<5QN})YlfAL&O=letMq1Q@Eiv}ZXA$RfXWZx1@({b+C97Zil z9twycA25mm)L2Dd*Rud}Q*LT>TwykcbZyq$cOZH0@7DMKE-HZMRVa-13%z9|V5O&+ zuDN^Cd0FP{8@aD>s`+l25W2;8kuxfxoEcD$GGtK8L5-3xn$mre&4;2B8TvvesH^0< zfV-MTwDo6NPI)zK+N-Gi8R1VI{6E|%TCV|L-B|?#zTlo7K+yyhuB+Yr9w- zfUGN5t1G6_=PUz;{TmOTVMnF<^+^505RngqUS{7f1H>jt=gO0UvI^wFiI`suhR4#% zAy*#Bjk$##S{?Da$fzD$2_5$r!W3cLWEIUgPXlQ{|GUhRNqK7t^?y&B@bE2o1->*$ zu39GOUZ&$%*Dbqh(#WG%kxP0?z7;^){}*?U`V77IPk8!5YU%IUn?Okbv37jC6$-Qk z2JFc|%DJF%Kd|)Ewp8I`!RLDvIdOCR3v!vXn&QY6WEs;o27PB6)NtRO)o6C%)pgGV zZmjPqb`0W{o%w}~KIZ0kI@iIT(tD~O!D0cH(@zFy6n=(!u8BW+iTkpJ8-ZiM^gX|j z7aTA;&#tUC_ggZ=d$e(Op~tOO`UYh&4~ND>?PJ587gO0*bAMENJ<>`y9rQcO4rvv zN71cSc$INsJa0MquA*9xoM2{i=Jha<$Gwk9Q?cOl-0BdnE0d>alTx8im2Z=0|Cb;g;7?VmAeMb(VX<|Zl3Lv`O`#K#5lZ>!LBGsQMzActgfWr#k0X5nPn zxpFN^`X+oSFbiA?|KYinK0L)W0bwE~wD%o9NAPSCMV7_3|E zFZAv(U&F2o-toWJzbJCvRhFAgMv<-}2n9Vr`ZL2ir)s{rgTA$u99I$QR4Nkzn6sF} zAKyCvL}o|?QqS{d2rr>}I%I?vG!*c%pn<5dcQdEnQq(2+ge} zT67&`n`eY@8!5#J|{?f~{z^R*3xFdpvew?On)bb?vy)XvH$$I_<6pUyW$$g2W! zq^8y=|6^rX6^z*igli!_UA`v2RHK@<@VSpg{1mhuPJ#PisecM-E5Rx?V2=qcWef8SygB)#G}C&8AaOi+W*v;qcDMNkBalN`t|S_^~f67h6(RxB(dzdg~_eD0AE zEstf%#W1`d{erTeQC^~bkkCstMsr zhWqBD{3X4qUeDa8@UPaR9$ca=UUGir>vdAstp6Nh;@;pZNao z?uV0Y35$!|)oP6mr3uY)&SteYTrH_6qB4Cpf9Ry&RGKqU_eP@c8SZHnMR?_qW57I? zRZdDr0k=(#?dm6%UBAz68UT25aSFAsY}*&Soxj%96k(W8J@qtQQ0Lh*$^sBRM;*RvZUqWFe{F#kOs7BCN z!8mrdGR{$GWU=Oq=YH45Y5m59%t-0Ap|2BhEGL@-QYR9iKBnqK3Yzo@y8ywRf7R?f zot4!x3y8gF*crTSO;+jc&g@jJ@etZK%ZfNw26!mtn}8jbz>=eL?=xZ-IfCGGyDb_w z6>gq9qUGRf&BxV+p~yWU8xzEpfQ##vYf7I+CIG3JVXY)GHM^pG#}~`vJkV73)BD*E z+$(Btp_;59Qbv9pnRv%f7xX0!cGS$p7g$5OGabI?YNH0~?+m9%WwdMvnY&D=98jA) zxB~WHqcnCd&l0}3;QY{DA%N?E0NFzv*ZZJbTn%qC%rK)z~Gu<)ZMGfK^X^YvzfB-#D3@!FsD5V2?r zSGsJ5P^2HJcHpZ+TIRAufmgulUe`iApNRz9-_ z=hLHB%B>36xRk3&i8U5^a^oS%Ylp^LjH4(QrfLNf_(+X|gR2aJy`(=ZMaX|5yik_d zW4f@@pwy_HD^e?$b#5aQNTQsRchIbyv#_;d&6+D=Gj!IodY)F0n6KyhbQ)3<=OQ!X zTC2#W3tqve@5|~3g-Pf`U41-| z!?bG>fyoSM5bG3l-c;#V*8F9-ZMU(NCyRs$3{p%|4hynxY2J~2LiItq`OFCvd`6XL zBUD6;St(%-{vH37kthMNY#1`P+tyH&+xshfrY&`gc30?HS1V*#+G1{WCg|j{6gM&P zvA*4&Pf*Z#V0(L_EMabWhUM*B1q_8A`G|%m$(@8mpUO8$}Fu>a)P^5s_*mLel8vFz%2>*v`A zqm_o<$!KsRX@Pyi$j5r&Co59(c;F!Jb`91135Bfh{(LX**+zl?c$$Cclck7Ity0Q6 zKTuL-BpR|#=zqMqvrNdANMzc1Gm=M?55f6LjeulA3s);K=gnpN(f&18o4p+C3tdpZ z3s${|U9#}{^E+ng7mW=8BLSl9*c+Qgg!eIrL63^Jw`T`~N+Cs2)Mkz=6T0q=u>ZuP zQve=~YA)9@_^&C|Njcbx$lgpyBvUQN3_qIS0^8k^23YHAuYtdj91Uqk4ALmj{)*4K z*LSud!%_*?tX7l~18UR(jO65x0!Xu^<6mq-?EYtnm$ zqj=m&!k3INo^8=c_C<{z$e3fArS+k5RoQ%87y)*s&TJpsE=PZ6vwcU48!GcSYVXWL z7D=z0`&@L6Fc&TZ!dJ9Wn+U=(o6o+5hA5P8OO`~Jx2s}R8!x>mAWpN&)7(cBAwMzT_eObw;zL#me`b_HY(3f*PG5eubjG`K01-|3WrHU6#POmw!%Tv1Y(Gslw2%Ti zH&YQ`dPX(`N1wtk-j8rxNi@-l6-G1tRR_3Nc6UZ!QUD{wFa~yO4ipU7F?#r*Nl@Z z52_0$rSX!G6y>(7;ed(v#k^MBXd3d;R&N5B5Zqx8r&s-S%8v+>unvs)Ujmw%6r27D z{cWq8Ze)`(jk9rU6~X;|dy&`OrvXk*i*_u@qGewrc&4S5`IEdxrt|Aw1x79GFgLp0 z{gtpG(N#)6z1ny@_R#6I?>LMjKwyy~(&S2H1U`)52pdFVp;$Z$5ihn80LKOXETm8O zO!Lux7 zisT_Oj2hAW4hjg)qJ*tawvjg%nl(;X;%{a))Oy>K+{H#;^>K0@C}@h<+^;s<+&`_Y zFA0vfN!$zKymkZcRavr^RP>lsCY_^GF>9OXncSJwK%A^!#Mg5bN6dPmE#tZ-F54?+ zkiD!}&(~mvZ8Va6e(CO!xtCj~Q&`Xb{WJNi1~hnQCqm5;a1)YXQXNAFAeeUYh^o=H zpw&a)(`Z%+pFGh(4ipbSXrc@Abp%M>n_|shU&8PqX3E##8t@C6>hJcu!-`B|q)6lg zY`3#x_}=EkOk8|Cxk;Nk`89;EIip4BjI+Dd(?@RipHb^3E-=-eM(^^WEhFJPLTJfZ zu4D{Qbi|fD+xR2U$NX+`1a(i^$&Qs>u~GmkU_ug+Gm2N2j!sF9Jw}zbc{j0U>9IDF zd#6UhiwY4zgalsT%jpkz=aeO6;ruXZ@j(Pjl#-}^dGWv{QTQ-Sa-f=B zzfY0T>P)+8bVVCnbxX*h3qA^?;Ahg;7{#_#!`Wk^9I)PrXM#sDsGZq&)OFHr<^PpF$A^**&L*86#ngghp4rwrNt~Na!h77_(wsp*w2#@+r;bAu-iu z?z9gIZO$zlSDvSc1EoVgudWIX>>Dvutbj1zEUf`fA#eS@FS?45JV^uv%8LenYVt_7 zPo|Zn`)+K=B#Q5CUd&FqWP;B^5B3YKCLRu)&?9GnJ3+A5oumuAL-ov4kEER{j!W!i zS;a+-It=C1BC??wM{NdBrxe`V*o=i2nLj0hq_VH0=bGGbUjAuRH-3yX!S)%{R*;D7 z2|m?xDqln4hQG3=$H2zi-F?-E!9-YVaPCOPdih&hypAkLpLKM48r!8eh%&#gTs7$@ccLM_g&Q4 zWqe!+Qz+-tYD+2!q*dp=93i5n50W??otV$!$Qza#|BT0H%=lo<7TMNuHF6lvn&3yI z7wCcdYOa=>7|QZA^p+iig>rN{R}p~TqTO1o-3QgHuS$~V3UunO+{uWV-fo@u2cfUN zRbL2x7s7ST3SM_n!T`7a`L$TJPRkn|2AmKAl7SUen|}5;7@R09uU)&V)Zk;HlO2kV2on8kZVHvBq=*-k`$} z9cuDBFBpldTnyv?6AFo84=T+-3oGPEEDNyw$QeRLn|({~a=Y;~Q1dbJN2-biQAR@O z=-la?mhYI|cwoT#VxeWd?NM%i#JiEEkIG8kn7QJoN-LKa&KX_qg2nmod2hV<5k%ZE z2Gs+R%=|(flSZ_45-JFm=c|JCtF6t*7jL8hORDblxaw4K&vU39@<#YMQ-XJ7xa!DE z-JAG}xn856KTufZRO$+OQ7<&bTW>|m#u>L0%OZxzj#rl?N8T>uwc~z6S5;_}j8l|_ zDSrSDmoo8XHP0=Lp8epbVkOIqM!vuO&xOjL>T+_~hz&_gA3Ty^RI(CQbW0Pd7z9fy z!I-nrrLug7#r9rs05tAH?R{YMsRNkxynHuWy}t86AhnQzb&jG>uYQD74F+7V8i@AF z#ef!3YECbeG+%p+r3<$mf7!mv3{`bnuE+g^`spZ*qoB>dr&2S`BuXJTL~abz+)xd$ z99Q0OupSpwAMHQi_#@oC>#JF`X6dXOwqI(TFk}#)(P)pCQK*}%sETst_^Av9b61#^ zofHfJcsf_<_bi96)mFBCDlzfZ@w2sj`tgBcztJM7MxRJB50>RoLWG(M-UoUShl>gz zX2Y~NO?!m5t&y8YAp_1IT*K$+rOWmBne$(uV)Hp`W+=f^zSeKeh-a_u1a@-YqGrGH z&(e65FlH-gyP5ttqki-jd@;&JD4$+Huz5mZ=i*~8=z*Lc6~FBfIi|sm5;nC}M{*md zF+<4B0+gSGkabO9gGqm_jn-3e;>)iNYL{gjD`e93o5xaNr@q&@d7fVrWi_&O<9dQl zgy!ZKGDRSB>eaOP?nJF9%!tj{_rvzqr3^-+WFK+}w8OgTYs7X%v#-AUwQ#yKkqmsp z#Ac>%wuAR60xFMu7A-Iv#llnkAP8l?aw9xULTO5E#VG+WE+% zI{7i~-)ONp|HzOMf<8Jm7ChvYVDh$>EHJW;=tyU{N)04>l9o&9qC=I*} zW|1g?>t=l?TaF&7FDDJ&f2Zp9k`ac_BZC5y>%BN6zyly90q<^GVlIG3H2wVADVC5u2F5#?>$p_`cp3jlxdp z{q%$Z6zl7=U&v>DFls`!{Z}q`mc`pqPQ(0sufM+KIor?7=<;eI!_#2l*2NYew+?&z zg!aA4o!L81_DWmXIv(FAOF!@ENkX!36;>X>OKV-rhlOH$zN}b#zEoaaZSUeKcEY%Q za;31g8Z^`DV@9&|q`=3;_1~AC+J9Cs-dXR!0K6sQq^M{m8&rz#7H`Oz8PTR07!a>I zU9lkq+scFoso95-jM&h8D0=cJ=a7`_P3dMK^HP)+Ie?j~-lyu3|MKNWZpVI3YKisT zvO~4SE79)9gng=mCx<%T8|m>q>pQqoj-PTx(IZAq3V5y1 zc#}YsbGA9&X~SvaN6_yAC-dO-NF@9UpQe*jv%%xNr@%l9`#SOUg*-hpIFC*`gaBd& z=VNX>1yHW7rFg>)8SQEhOf~w!i(H!6@*!9Pg<)(k4ajKOSIBM!8l1Wt6R=s0~gSpzY$o$o>36VRIwIEbc8= zFh=l?OFFyDjx9wMC0O%b zx3`};z*}NlxTrCgMfT%M(Rh-(3G8AVwW1=j6mhp}vSZty?PP5}7t4qz?1<})?q;ep zLjJ6CTr=S*L}L85-6_4eB6~t&xe*<6?KeL~sV;|b7|HfGD0L51o#zmbOMEZ=cfQY1 z&trd@~0Qa?bc=go#X1TZh#4D&+p^9wX(8zFAEgdJ%e&iK7X#E z#M0(0iqhNQs%3yCt2d;GPem#6M^jFdQr72w%o~h9dD@J5CNwd8k9+o|+qz`fB-<$N z*F%)0-46|%Lq3x5F*HlXJO;Ky-K>VQrsIsDle48ff$c5;bz&L^(kM$O429RfpNPT& zY{XZYBW3udby8mUvg2+_FpaJ4;+pe6;Y(K3)qP2|#72OaBdi?E%FC$^l6VG-7BW-u zN#s(64H&EX*hpNwk;*adIcW#S)bEBsd1WOq~3li@JP!OMOvzwX~ClLDzftL z;hyWs;i&6#>q-ZbiGMG_`~;4}MuC6~LZ^F*rO-(5;ReSI#eJCI3^RQ0_wdh-mco#! z)0w|=!cI+;udj$8q^z4koJBznq9C<@opaW-2GRLa^ z*$b6=w|SYAW6p&>%Fi30BpswjqlnOAwAKZ;CfNNqJ)M@@0@K>@d*V-)4yE40{*KOS zRB`tCEx(gJ*<0qXoX|J!CXa39e6Q6f`QvTFJ#Wed$G7Awth>VEeAwX4AlvveIn7|g z)5g;zitz|$C4KGgA$|ZnKCvN2MvmnmIM%h?Mm_kOQazKM3G?L92ydJ94*2WI%eq5I z3p_eoFHN$Ae={#k1nis-<=C!0amxZ?2VYo=~Wp=e@ogc&NyU7fbq>^zr+U zBukgF+iz2ajjvt&Mfu(3v}?83v};^>v9;+T@woF;Rk^6i5O!jMeu6p)ba>N(AXqv- zfA@kKEwp^aD~ z>~wnhOIr%{g3uW=vCJ4y`LcZM+`U|?L}ojNzJ4UV^L*I&NV71H51Nx0L)MTS=gG+y z`auEEr~WU8B^sz(JnjfiOP^dv!?9f12t3pWQSBl_86ORu9hrKs(;PsD_fv!Bw`C!C zr~o}N0o@=Uc$%q)CY-6RiUr;iW=Q^#>wFkn232MEqmaqLhtjo#B5x^dFA)erAUuynK`rlUD#TPr)|Hsi;#zpb=hFp8Y>B?(5n8?ChO8=XcKc*nHfoaSq?8ai*?>?`D06@0{}s z+6>U%|GeSgCQ1^I^$T3SH=lK8?oArwKoPF2i^z9K*q+>mUvd44)4h zrGr?*Q3WiYL>TQx0s~Msiy3A76M0dgkZdXE{)wz)5S=z*y@ zoQE8VCB_WzxCRRv@-1&-Kj)QFtX%FrfKt2z_0fivYiiDTFO_25nQe<2;DJwQYr&|b z^4OXXBwq$wk7Bxc&>N(G(m7T8(-h-N&$y=1XtWTy>P-w>6&+*M5>|O#KKqZU1jD?4 zxvLj@Buh-O^C6T90qY)kYNzy#nboP*xYIcPzD8kl-%)rlgJpWa9PkNAcD>pOC1n=p|#@mGyF)^YW zdyb5b^~G|mMyTerk?Q1YW<)K?w$ss+i*GUvJ@h3DU;)oAp22V5R&Na!JN4JsXAdBv zyM{jVuZDei;~^Lu28ek7*f7Hp6|kGss_?>jHW| zTctp0j_?DCi*$R-Y@BEBu`z1BZqOUc4nOzS$QCCwp5vZnJsex~99$f)@LkYi+c?*j zilq`q&xv4ywGWjXwveKORw&~3L6cT^KnS{~RoUQhp~gF|pO>Kv6n&}!Ij)D-sSTem zAD3c)n(LgY4_d%$%JhEZe4yXx(`xVEw(OIZ(LW?{gG;iVv9L7%D!D=8o(oy2_;E?` zt)M9eaM4;@Wwpln#>B-*e|nGQ8RF@Yj)^Vwt)$pS3x9Usg{f40u583e+uOm7ErKDr zE&N_S#kPV6Qe=amK<7uP!L%66T(-%|`C62&_YYBDba85He3%-;8<$8E&9MYFU!AHN zzI2pI;mt7{VzD1|MSU)ii00UVr?M`59t&fAzlxeD!a^t`Ehn(8!gWOL8rAa(&1}Fe!gyI4QKpkis8SdZ9 z@-zWK6Iqmsw!1a%_C=;t1+XL|6x1ZNjEr?R*(p}PyQIFO%J_pUY^M{n6DVR!Egk1N zXZH3wJwp(tbV$Q1B^x(?FA*q`d~?{bupAxSgxAw6X{l>1S3g+o@V_|CyU^4!GVeWA zFBGqEpe%~X2$uJhCH2K!Lamz?^tjl)9oN@v0C395H|GvaYpcw&REcv{vm{j33LM#Y zTGT4E8m`J@;%4?o7Pf_Q|G+)w62cO)?fyI7L8MT@?u>>}EER<>-n@;?OpWMZevMbY z+iI{k{$}L4QQb#uz-;lST`{Nxq=}hJ4@QNu1LJ@pvb9?QnG8fHS5C7*QPX*OUKj-b zg=X}_VT;Q@La19o698Y_m$A%vect(WJ>?j9zFb(5i<`#a{PN^_AOEwdfi`V47sbXl zhx%aP#63Y+DsJpe1Bqu=M7+}j<({mE%x-l~bWdl9Ka*vAMU;KKTkuNnEITAup zmFObm2kC>KZx!WwI-Yt+D*D$WM>-y+w8HC@KzCd!oxV;3)*5Gw2U z4-?$DFR{f0_&qcjSnmV_tRf3F+jv0J;tYK}aAv|H5^bcbTSFMKSir0?-WNU;5P`eU zwq>Lcxqc=|Fx1-Wo)DZA_Dl=UVGXWbZ_D0d1Q!lq{XMQd0uSp4S z7@fITJhTMO@-BXWX$!w6uZvQWrPy2>5XvA1n8f1bsJca^n(iZ(>3q4iwJP~M)HL$5f(Hdu0Ex$eNxYy zB~j3~f+SZ$Csr@DGuU-7b4wb^MkTJ%MHP4p%jxzT!^I(bg`8||W$I1z&?&72*=-dM zNbz(X4P_OtMGA%tn(bl=6Xg+IxW-_Qh%tpCort>kVTug=y$`2r@%cy0v=UdE|2?Jt zTOZMvnl2%6vY40%Ny`5gP*Z4*v-=g+M?faKKJ<%0i=^~V40Z3(S9Hd|+KsG5s7#J- zOs^y~ThU2!{X1275|NNo@#koOAR!RHwSSHgRDb{aG8dwou@D+Ej0WTLCohhBL1rN1 zWaZO6j0!nB3xN-O;|JgOFQ*NoMHQ@nBdG3KENf`KPZ-_e%9`THiQBO1bN)+{mS0!+ zPE|SCtTA&p7C@FVS?8KZ*%wk*KmOw~x!E8aPN+rv?rRBYJ8rZ@s*kdGk0|G$x`m#czN7o)!0%02Q%~w zW!;R!*f%j8WT9uessGG{-bP^86T!PUwCAe9q$y*&n)b?H77Hwz+E>oDsWkFgn^;dY zuoYi5JI}^?`Q9vv{Rq~ypc0BRf!oiUJk>>#g=y`#G9~J(MKhp)7n3m+w9YAM#Wy{t#rob+T9Ec7 z5CPP~aQ6A>MbDk6QGC$NB~nBiqIIrVf|$z&VVZ(*meC%hGw~G`$0^ z?bqmyFDC9JMq=ATgGx9EO>lcv$b*+NnsmJ;Y$*NfgEy_9(NsLLQ~Wkfu?fZF(W&9q zMx`upS8O?x7W4u9Fa*8+Y$9tp@B> zHRG~1ct#n~+s#bM(+h5iF&C`}4r}=xM9-&h*g&ef%hS_WPyagLwG5I7OBhEPh!(ea zSmLoq%g9K%;*0wlK_9~H*+r~cmbyOmHfIyL>~+yGgu1oK935M^bVbN{3vdbNbjw_##`D(8E7K(*nJy-YA2x?cQ3mc6|&B;hcGM|0m8VtTH_R>-OGeHHRe3N6cQcZAS zmHO8we|`8VP|>yd=xQ8bs}~Em6YLdXxGekpU$^$iF~HxCe);V$YbaMdd_3BQ`39*xtLQy(tMyY*taw z8A=3@qk{I;RG=pRs{8^y86`^j>4v~ipF(=r;}s9z(pFu1o3YfTMf=U@cg=64NTaLaaVmM=H+8#Fa5YfQ=H zkI%@nDudz(zowg`pqZ)S77*DJ;O%4e5Eun?ubDj3&`VwPsB4RBfCXy3nAyoS`rUuI zU;A9lc?BNdT^HTcgc3Cpv$^vHY8lSU(_u8tV6%gK*l*a9L@2qje|sG}*cS?&o}>S37VmHyv}OpyYwSOLLoLgg$KV1#kcucXS?%wG zQ{xmURjV3@Z|WMhN4x@O?wW08rL$a0kmGp#<3P?w_w}x`0l4Y<;EGfK^)h_Xo4|mK zh`o;*jSHE&LSl9Eij5^i6)#;pu3W9vetiGZL823Hs-wD49)(m{)eLu$3X*Yi6cIcby~k6lgV`Nd3I$9kg<3(A6=3Y=9$%DrEW7n1G)6TTK`6wmxfzSjzj>5~!Q#)d z?{`$BL=mOx{<6F1=aBQ7Wcac<%zRd`9x`&K`g?7S;Z3v!gA$SdGGz5@Gv+|j75dej zpH))5aIPx@jmv0Ym;lgP17}<&Y->8zMU+7x`bv0y_5%y1CO1N5-^(l=1BRRBf6G>P z6?qxz)R1$_eD1wyCEo3DP91?faLjFmc{+j>BKxH)Ofovo#v)5^tY;m8pdmXtW*VVphg?t>) zyGCTT!$ug*^Qi!1U4YqmlJL(cDqR>flXq(`D#!WWa>#OImkk?lq_nSiGd6jx8+Zar z@O-ZG6y?zfYm+#9G71)U2yY7vT7c)20^2?nBIi}=zF7P(vLMP zooipExH+DIzr(kCIV}6mNs3>ERZsy;qkSUn&Qqh)e~{re^MoJ_>er& zwp0o*R?kiH#L(1`Oe`%MX5wo+Jb`keOj~fwn!}?<$4;tw?r)wb@wBc;9FrDCCgvX# zJRQP5Tfd~M`!h-Q){pXR`sOx6CN1(fP>2ZQuU-)?y9~9jk|5uU)VGem(|6_j-Vj+M zyuLba%KdfrWhQCwJaA7DPw{p9mYf)Z>M8mA73c+QvVdn-*3ijM{^R&kW9`k3@^$UG z679vA;I(^SH8$OW3@W0ht+*pvYvG4lCy*?s8MM+CYpF>|i_x!9kqPCAf{FXbB|o|n ziyhBT@9=+?s{!VY{PAR@;o6zMpU`rtvQ;vXACDQS5uogfO9ghq)%xY;r#`U1QBnj) zgq`*Ga#)E2wckshdKj?+T z64kbJCQ4B#3R=W(tg4%JYFvJrxRtw8dPD-M3*f2VLDKfrD(QH0ORkWDRq|$hUM4YO z#vr~Yi*K&^1f!vWfH4LtG#BY{M?gpxox_>jQb8?>M;{exhmpIn-Yu=P! zzTEmSzxs1!Tl06T6!BrJca}I4oojq+<<&2Lc=~seLKKXP-*^)@NegrwHs4*E2F8i9bG@sNxm>t8zrWLsR?wTH5z^wj;(6@LzI;wX!-cC&zp!_gq-&yp0+ z_S==5CoMV5KkT$Ry0l=&QF-86=Sa}l;L4y@WEkwlwmG8U{r`Sgc?U;urpsy#xFH-mcF7z;Rw-c4lL|H`Kw*g#3A`J3pVv5!@nQ~z@lSK$ zGFJx;X<7V?M;2%`FJ40(bTQL)dKZYv-}Clw5YWX9$@uc*{rXbHn9-@W4C%)63OKmf z=SIx9a2Xzv&P49&AcMID+~I(mZJ22}1L3?$mV{J7$Ew!^i*Wvo|f}Kbp z(rz#QB_Rvb@nLhnK7**zAU2GhRs!-pM7s6cdG(LS3u$2e&yNC{u`c9>8$tcp??`J? z{>BLBjq@`Q(9&sq@A>p(p?^{%=09O)i7cyW4{BcD!ud^UH*I)#>xRzUb0lxp*m&8a zQ%6d==5Rk~4LBfq&gcf{ShpdyM7Xa6YEKo^jwFe=wBf!xr`H~%P1hbvP5PQ0U>2Ty zp0a_O<69DLe8={pP(!v@;-0!is~0;X+K~Pl7RbZTL%|X+%_cCaqr^Tt?e8bR_+eqD z(+G(Jm-S4fLp zKQ}fg=Sd$rn$t#G-dK4+PI8vgqkXnodTRc0R++arKf{tlXS%va;kmq0e*5%1pAAb9k=E965sUk)~a`nAu3dJ$@r5`vl8wL6whN9xQ_B%05d(4o7s*6@UhQ*=azI7(s_KOMUH{ku@Y;@;qsj=V(L z-{v&@={WEtu-}AOG(tU&dl-Fi{w>pkA`j45^CT6pa<_;8nu=#h??-v^Xo3C_(C@YP z8TJjEGv)!hx|NiH;&me0pBmm7%N(5l^t;-x`{VVvz2`hwZj-C^Sw!^+YiivJgDy#Y z%m&+5%kXTgk--_)*s>X{jJsNRAfnDwaV8<`i4^f4ew1pjeE(HGFu zMa+l+Ff%cGs#<@4Qe?Bw=8S&5E1rxof=OoeOz{0orI0+@t}~TqBT-#0@U>)w6^kKP zto+)3Meo{TfnuNR=nDyZHk5^fHd2L!T`vD!8Vw23@YPnd`UT{T3R!Ev1Cyc@2_3fz zTEO-QnS#{CotoyZOkCY7o=iAh5b3IISDbI+zs{-C%k~OL2hd1noxQW*^SxX}5*%)e zKkLUHO5($^?rHCN14e&{wBEi<0JivUJwAzmV2Vnnp(frPkR{co4H)8{3U3_Gx$8S& zFpCmhr=#&;s@2N&)<7)LY)7eq;3A#lIguu>Ws$;GtG5pbi0xO#$-@l zUk3Nsa_$W$xHRlZ&f`lx98aYOJh{cRe`MtgII?KJn)x)ZS(`Wd7Mnu7lMq4g$Nw8B ziRIF-4+#8%Or34glc?5x09Jlu|MwOqVr)K}US8w5N>Zq*k~NB|N}zT(r*fsac3=Cy_7I>6l-{Ur-pHUi>(O8^8+fYhzL=AW&+`u( ze0U7;l%z!UCFp&H-uV6d&w~wDixoXvaCn zzFVei_LaezfN>9kh7wfhkNS{U#mCn&QJ4*XJo{5=UvpN z6YO`%N|UorEOa6Q^8pDF%4RJgdV=$jSO|#*{fm zJDe2LUeW&3^p~c$TB%e>nU+Q6K9fOQ`Y71?Z58%b02ZpL@jt~k>T~BiqaXl@dzZum z<3S~WOMn^>0oh{wMq$KdL;;&W=afrm`v*jS#Y(qLQlXBI7R2%RIdjee;#Ar9gIyRU z{RyDoH%Ol7-QVFga2J1 zp_i%AA8GVb!jpOS-!eLAS`XxY3>Vkyh18W_EQ;9LpN@i5|Yy6&oPup=LtD6hC;9h^%30gp(&2;QY&bm1?CJr1teu zo)z8+1{SG6UI?_xqsT4vraXZ5gMAw#Ahm#2d=%?dTUM5x?Vo=bYP;vz1II~VvuRk; zYYa7lj9Ctu8H@{6R!p36qGpOyf#Qx_S?MLt@@(U!h*RUQf^pUr%(U zmy>%h_i6~fkPn0W3FMz#_s{v_aV+Uzn%RIbNN-)z8BS_@TP;NPU#l^UH$Z(h~v*6s`sPYR8;Awe4z$V6A=Sj=!_Pn?j>DeN=J0Z)1hvqJrl^A8gr6W67T2r(2%P&cnaMj8tYZ zL4+1g!W9UK+?P74q+`j9Wc#X}XfI8}GWq3yB{S~XJrzogsBwvSVHVJK*t}{ipi(y= z*M-*|k3z1;`rth{YjSd8As4l-ZjRU6ZoM$pMqIozdlYJ zcvt0RgnC?%PYiA#M`afMTrW`JQOH~_yQBJ{xoRbRsbs^_zAsUkL<5|7^TNxT>sR?KFyAEX7Os^f9FMq9* z+ulg~^zDLQt<{%!BH+ZquXYnhFXZD~@CWC^$EMA;sm?xkl4|)bGg*NzK~Vki`1|Pt z--H2C@UO3GKe}}uTT;)Pcr(w%=bV>BZ@!(SJw2j}cR35cO4OWoo)w+l;P-q&pOf;y zBjvP~#pu(_%bpR(SueNY@Z%93T zzjV&>4_(&oXLgFySl0Ymu?wo!mf&j8^;UuGCV}rgsH5IzNrpo_A)2ZU*4?r-F_78d zdiL*BV+)D!EZYHuD?S0}1LC?wspKY`@M;S7YDph8K|SAX{6e3 zY*YaUeftulaausSe9m^=LLF_I?do(4lsl_HD3009c>1UQ`g6vQIBSKfkf;I8D`rea zXRV+%_SG*Wm^t%IrcWc)IqOGz6Jq9$-wM4)6lO8T`&UWew~5tlCrikuS#$Z2d2!uT z8Rwb7OEi1sfmMIRV6u%&Wd3q~Xq?S#zCrW9ud07?#q_t9D8Y#YlUUC@fEXZT`?;qnEqkCF9YO^plF!K)Ld zDCFbSwK((BPNcwxp4*6`X`$!4pTCFqJ-NRKFt}5FH6-kQq~ix!z@*d^0Mk5%+U+)* z)82^`QdlsxKO8Q-c>J>^xbyhj>*~%%YmU}Gb4zt-E0QI<`-sG5t3ZxJ?j5VK&@FMh z+qG)tyGI~l2iCjMhd)H8ecG*&_86L`;Y-C4D~;U~lS^Jr;L?F}%@z{;@!-_Tz#ng! zJgM@teBDnN6IH+3t?;im=+@X+JB=1TCA0z_SdyvcpbL2sQ^ z42Zc>o~b>-+@zk4FRiX&bFg)qU4XgIfnp zRfC(ne^esmpM|YwKS!ALWZ*ysLb*3nx!Jjh6KkHjAK=}8kkuE_0ln^+AHtD$);{~| z)?V>D%8!!7xLG4#T6@es-c3PO@d38pL*$-G2|Ryy|4Kq(cD8EZcJY$#>LEN<8rQ$> z*7jFdhQYYETLk=Y+|>7ENwQd6{kz+@%0~L%WFFlI>&0kDTu1m*IJarXq^R7)^P7wt zFL)+}pyed)c#VMl{lojP_O~x@v8lhlZol4&e(|qI-g&HVXg$_+6^x8-U$r3Ty+5;t z?#*QQ7Vnt-JRd!qZ)(14W$HP+SDybyxg$Z0SI?&U7qhZXwiBfr<3U?#A%_u!JfYH1 z0%3I+(dWaT6Jkkv;lcho<#hboBJV{+E55;zi0===x9IJ&anY+uh;dyfkNKKpHmbnI zQw?e)UF2J3h=D#03$lYqV)v1P-kC``-S%$ZoRx(ZkQLdNP&G1nc+kx}8^)f0U(fsK ztVPvC>yPv3y)3&Cq7lM%IXf`8H;IcwuLKm;-CIrZH~(u;6+CHlZr%wos|Y`9ZUN9R8!^R#HROMUm~dg)||?Ez$`1TyMAO$ zA%84Eq9{4G5XhM$rqNsb7zpr(WCfStg=$DMg${4`bl}^!FZkD|v5Pmy>sJ*LyN1=g zn1uw*J-%&3G#su9Uuq-qHS6$}c*`|k!~oI_aqOdBe{axywf+gdaFb&W`*0P*cZc(W z(;pcK+gQQ*%gLZ~2DnuqoP4vDIXG-=WU_yTb9f4-|IuN$x0W==JDnY@yf(YUq!YUj zOTq6s+uSh3>K;ZH7{o{IT&1KzPj}wO{oGEqfy%N)XN)N;UG%p8IoI^F%(H21ubpr` zVu{YkHno1tJwIsT4a;%PXTnFciu4w9tc2VX_d_z#iMk#S$)+#zXR|r0y-#%4feDcg zweHjv(bIX`l4Whh`aT}v;6$|f#M`wtjrutW`d_tj59Va{{lB*Lbji51R}d8Oae;(* zivinnO2(0ni>gI2-}1ji#tcv@#SGw~s!<7}qx$0gJS`7L8B+_86~QtVM`7;4s`5fS zyML(c;s_1+H+~x31Ph=Ezm!$Ou__&-x5t7c_=Mp%*&JjbK$CfU@AHZIR!-mjC$Rn* zT^oJ&^=w8G*^T$y>kJaW3B6_>Q4$=>Ggh5FzW{rM(euDhwD> z5(cBs3FBO`%i!0|scv_!T}k6V&23;`66J<&-u6`uJ%q0jv?$J!+PzpLL;^3rZdhsZ ztaSd=UOqs5hOvGuygHZ=!&KEl853p{>|(_8JOn{vz<~>$AVPr@e%cn6!i!&HG}Fq6 zZB|mAqis=OF2UE^VlaLDA&;MjbjMp@<19&QGX~IuP2SVTeTQTYgcj=&r(=}DC9|A; zJMtz{f0NT9uAQ&V%q?07i{oU;s&74=BcyS@@fFT}$(VMVs*qUM92gduAccf>;029Zwr6yctvIzGct51h+U|I3I5ZC3c6Vu-er&$m5SNsbM_94$^3j+D| zcmb53HRMvAXK;1*(fGfT7;{H~c+);)6+sJaLQxQ?e$wBQxm3*{0YJhK;o83X+PbE9 zY%IWamNP>lPVEZHArd1WhuW;b!?CD}yx`r5hc-`}qFD+;Nv zJ-LyfL#{H+xDdXj6E-lSy9C^5k^PRZryJKwaT*aKoE+&Pdm4fC#ki6K2X=&YT$VAX zzSbkcNPb(M_R8HJ9fW?6B6cpWO=ZiXM)y2|3j|jdxLYeyB_6wvZ-_-w_n)8W5OF{> zI~Phvpm%s0uP@Kg-r12w6!PglIP3Ti zG0Q{qazn;~P{`$;o@d!e9B~v)Tsz1ML~`k7g%nZt&RbIw0p4cVE?2RQN5yD=1Q zLg*|diG*uTrMsp0=p^apj)Y{cbC#f^H&Up-nzTC(MjN{|PqmwFjTL{TJk|+>{o_4~ zR%uhOdxPEQ!RDY&*zfo+-46kZmQJwNa?ozv7!HqDOMecp#(W?npnD)JARqZxa$~Ky z=5#|(;D-Pgx85gvWQEo$S~hIW_zIOU;dRvPp#CS?(@+D?P)RY0%Amh~4rE3oi(V$- z$oym&Pto7x>)$sZAY=febm!AWLyiLDdcOVo2Va<*o?8!GYe$C$Y1$6SWeyE!uD0Wi zmZuFpv?pJ^RH?@J%?;}1O7D&RyubDRjz0h5o~G;jM?hz9qB_|gz7y5&`!%QeF4Ajf zS});;b%CEUW^o_rVH_!} z!Q{ff%q<-0G+?(6mD8otM>8vHu%)MJ+OO_eo~vgaB5*az{9e0FUbBrL!twl!-OUOJ zf#7yl4u{lpTl>XvgT<kv@=LBVt4W#;wlki5Rc~Tk@FqBM^_X14 z@ucgPatLj{!$QqvsRTe95t>kGQh;G>S5UO1$ACZQOSx$mwPd^ds?fZHb>H1EU&%F$$4=e#|x4y;A|N8E5=dMW%b%Z@p%+t*Q zA`DXIf;MX4HHumL`!2ZQXcYPPm7=#b3!HNy5(31dKn%cFm;Y9B7A8FUJiI29yLKUb3#N2BtPn6Alq^v zoAn%DlCsL) zUvIhpQ_MDsik*5NDURb&`CbA!6Hn7s|3ZAO{572lX?_b|T+&~@#sWlYrJ(mmen-L< z4BTjh9-$x$bh=1)d|VblNC27ScTK*)mmt`Q-Fa~^`{QiJ!_=jmitMU5f{niBqnSrr*9@AVT+j`t)T>i z)rQ$k@LFm$>egsJ(aCBlHDtJXYe-I`HIgI^qa&$rc)hgs!4pwa+8NA~q&;(oor8L# zU3CX1WWM+5T^Rk&RMU7@93dcUip)MPIR6=lBnfrH zV})w2;LJ&TbSBe}7a^T{Gh-czeu=k0B_IMRZ%i z!3ZqJI(gkAQ&CI@4WC|?2%58d;USBm8xjCQ#}twef`?}>F15axw? z^0J1a2;lfreh{GsYKEZFHA7Xt>%~^GL4sj{?dJpz3$^G?+0NxFw$6#dR}!d5!N?MM zejA7^;~rAehWAP z3|KG&5g`~gwp?b3Xq*bl97-rL{opxA9|KyH1XZRTm4tJ)-^LH_RcOzZf>XFNPN$@f zrBOw54Kfk@lI?+fFZq%A0qjB&Vu^nvEbLnoQ>P+JXiMKv;mBOr#oeWXg3V*k4Q7s$ zs)gUj36|!wQXG=9gmejeE|a^dPs4>R)WpCF)^AmQ*$)rTui8G#EGB$|AS2h}0jFFddBpY$FcOyBAG&IDQ|9A1Bg(kjTfWB+DN^ZH%3 zBigp}(%;{*c$&Nn-KF<**?X71Ch_;+fZo2lOnF#OMl$T@Ehv%G|im$IM!_3B%Q?hr!fHqV3?E0_K-y!4SKPsWK|C~uZRpRrX ziE;Xr%H@pm+%7YML(o`Bat#z7o<{G?zc!D7{R~0R*W5oOL5%~#~1XhEw zXfz_NkAeV~#f0+*19z*~nv=4UbTYw{VwB)q3&5O6PBV>@i}9sR*o#u_nTG(K{jvk2 znVFRtY3V-ci{;|twsP({=~HhFW;85Srh6yY)6dIYFIRzoF?r`xr|9dbp|rs*G`s7+ z=BgnDHEm+2Q5j7z1^+;Q#(alSmK^OCTEQM?7o^I2N!lv)o9gM>R;2MrwL|10<> zSMT1SslF*SQpx`_S>Q3m%UHw<7qu}ZDIAvu{LbO`KQC;I&llM^pYukx1=3M_cBgsz zMY4Op-AP)88Yj(bY+vXogP)fY~{Day@O7sZTY(Fyp2pFxZ_u*Z6^h(PUZyZM|Q&`#g_5k=*t$8*)qc z7D8uiO!P`wL{}pLb%^Jbz#?>P(diO_yY*;iS}x7!;B7v6H{YUYBL(R}^|C$@&ZXzl zyVdqvM*HveElxnk_gVWRw=^fwq`KDc2Q zeT4_cKRv39+IH-ca_U!&8ZKigXz4ZPAVBvQRri_4R!k$!6!gQOIet}#Sxdo%mEZ8N zd3O#@#0NJ9nGaXb#lAYCNI}<$L==^0k5|an(PRE1$TgRfKd#>>CK&pb^=Z4r zn@uv<%Syt(4~|E9zDwxmF=S(F($sSN*ibh2%yjjJEv!qJ_PeV1D0)KspQuo3;EcN# zH{fNqd0!%)ewUg5&&50}dA|_y#7clSNq$~2`#c4#)`gEocm@XZ8Q0+f&8Zi*wo?T; zHQ3)t*dW;$%Cru1_yOsMJ)25Aq&^Vs;?@nGv5Xh@jC!JSaOUXz{-`g3( z2O*mA%Qu?G5+#M*&m0JU^K?;F9Yg4R#9vZ0xPGGPY-@m3&bK>}SU(DpSXpF9(GY&Y zJ|lGCUW#IJ!tL4fM0(i{az3`jj~|HijY-;A?Dvn>Zd_vk$ch`z?%-SC0MiyLmnq-s z1!KP3WelM3cN6m&;Rtw+^A1Cvx+pr+NBzpxzyS;Tcr0) zOWFLHO2MDhrlOmp>?(xCMh(MR+DV{Xd{}YsDV%0D;}kZ;J=YnftML$J^ytRTNaQVT z56R6j(=(%ZyuZzcy23M&*~LzTyQH=-*T* z16t8SWP}N?Km}kr7byF4;%(TBR&Kxb_Unfy9RTrkkvLlr{LLa&_f!Nt`*q!uhhag0 zbv>AzqSUvh=vny?Fqj46~+a3 zQd???j8AHB3l>=)$cRsy{r+nHzBI5>lQ@UqI+t7m72DRg%?kw|XohU`Cb@pkK0LUc zun#1^Z93)m+{58~{0DJBv?WKW_o5cdB%Ix1y3>WK%xMH`oR1uaCYk2QLpWWq(z@JV z1}r>Avw#J+uBi6kHAOEgaPpkyP}Afpo^ThYH3X|YW632me)maWf3+O_+fNBx@8I1# zy%2&H^V)It`_&)obTEILNFS&^sO_n-iklh!*QKt7AgQNMhC*4uL@CU1-(P~fcDe=9Hd{E0HUv2XAVquhFPC`xte$two7OVi{X&>~ z-Z(nQcGCHdBJ8`tsQ8g6prmb2<7NnuV4gx%or@Z4c{9b@bclfx7w*uaGwOS>ZOBpl z`BD$jL9Lf&2lzx!x8j-aKMTxPPmT1KzX%6SoO5; z)9!z{L^;_fGgB+4h3e0!bi6T{of5{SpAC?MSfIfKm%7xne+Z(nORmdUx%NJe>msG29tK zVS4`bpRJCH8S{-f_q_I-xf$1QP3A0T%M4t6E#nOt03jMiLIuK}&)SZChZ}Q(_c0rd zhxYo*gxZc-Nr|o+V4fbuY;gkb)pp9To;O@9U*}!iqQ%7MRzhQy#4T1f+_9p1^daDv z0_(jXs3_o8Ntn=Qt_wu4#%*UF`NnjumRiB6pww0%(O*s}vu|-FZ75}oZZnQBhPA*@ z4L-m6VmE@Q!$N$d9()|noQGBTwUAH>r6l~9)_to>8#9qJtQe6iWE^?;==LGDEya6P z%B^aRD(lcw%#S{idEUp3`+Zu);9^pPKJtP6p58bTdF%iA^`)PkGjaOpZcP-U8?UH4 z4*phz?Dszd_jvS@RXM0Z-P?yfK~T^xBUm2|w8%3Q0+i>lPTq=Bz3ke%874U=#KO$~ z9L!Qz*je?FPGa^j{Tz8U2A`~Docg&5j7u$L8SG$y<8s*zsk0IW7qYZm*QyXvfTb$V5pO{AO+@)Hs zB)Sta)yaWuuqMTZ7Aj%(_>FgKBT^F}aFJFKi7CEW4t7FBL)N;eO}_jDkV%LOZY49y zmL=G8e@Rduki&)wurU(SukU5aZq?zZwbW(Nb6j>;m|6$jaz>a|9ahiW=si3A9{~SA z0KW(jKtb{F*AJsSRF1!1@K@V)7UUEl5DcKx1D#O2ur@k2?}&Dd+o40_4rtf79ojc; zkHXx-YIoTQhz1I->U0$V;CS#jmh4`FA9w$VpLYF(HHX&7fIu(-f||q-R0RWoI99&Z zYcd6+YS8>#eHj2XI++WXESvy~{6%Ts%=z8V$2Y6Kk&6K-3;+=czT5mAFu9oJ|B0{|#)B6)0bewwhcywM}g+` znxlP__A)SN)&cFCw#O+gPC@(K;Aep!?`}gP%ya$>3*Odg`abyQp>{)@+nx2;OHd;4sErSac zWQbHNJ4^`C>I0}&tN;Pyz8{A>``sDWia)*W>6kKV3Woh_7(z58D?p`^->!qZuQ-1T;ND4b6mTiHaaxzfDSD>pnbFU=+L|aIyCEmmW^6MAlYBntX57f3~VzH1KSJ) z0Bk$D4GVWH#Qg2^v1sQaR75JGU_j8Z15TTjap7{J001srvX=x%KR9jEv<(^+H^PD7 z0nJJ$5t*LoYZF8}|a({ewfP(=pCn5k)D>sRf2tg3E z30HfiG^Qe;RxJ=lM6FgGbHX?<_ru~nvmzj`1b8B7f0TwwT}j1@Cug-k3p0P2DJy1$ z1t4C6&(?f~NBcgCCPhtBvsepj$risTvkOv0lD8odc~F@Jpq^;Ov|ep{CA5u;&$<|I z-S-x5fBkm3o3{{+GcZ`clDu6#BcP5-sS>~L{1v}$|210GO#(c`gH{b&;glAq;IeZs z!|*=C;qzu^;9-t82Lsv+z<@Rb@Eo4QFMEH%>`k*VbJI-ORUp7Vc7SBh{qOj@c$EOn z?~{xHpt{z+F*<;nmN75Ss^(flrexj=pc)8wb5uX63|D4kJEyffO;*l2dY(!YAu)tk zetIS4^^1}yPk0gx>(@6Q(&%chTr8+-ldgt!EZMXq?si7>8-eFhqvOJU%tU@uil1p{(25J?AlN*p81|ldg9UE zk7DUfOYz-^@9@_ie?{y3)<6gbmyC8TSl#QmWCqx908qtj02eMAL8OStU_jR$&@dFRK#Fw0pnz!I12-JnfPRnk!xuk)QLXN$u8q3l z(cX_@$xTZzcf?%W-sN^Q@HL2n0g;0NF4X`4P)c1H38etWTh77IXh%Nya4?Ppj%4I{ z>e9N4tn^hDAVM_|5SGGtVAcbWsFd{jcOKXoL$@>E)2QWIFRz|q9rX(9VZ+`H7&~cf z-0eMi)swjL%qtC<1~Hujm9BxLkVM&mA`??kWCR3iM?q3ZP%f0?h6y*|k&hoiM2u9s zNxMhm9{5-Pf8n>=f5Ru2eu7~q4?|8Q2MEHD5n_9-_(-k{ut}%5rq4J7z*zt;HAnW9 z@5{(`8q{upIt6v2EP#HZC%{j;e!_&GCnUZ84Ldj3Plh@MKz+^k<;Se&`tz>G3!lA! zu^-xl073}fxb+S6ZreK=Xh@*B7f6nd708pVdX4(my9HQogIdv7Qb_Q|!Z$Ev+z{+L zy02Q^V;TtKAJWB;N}v7%;eNI4i)VMgRax<)Qtr`z)c6 z?C)p_+d~y>myb-2{pI^J_9%2{)&YN~SOSem@_D4n`BX<%JTorOi81%8e*G#4N^pJZ?`sf{st_FN zwr1T^!WfKWFAbH(PBcWo^#iU42*LR2kWOo0I85qab*?+XZs;zA&W1P8q_FN>n(dz|X55jX^{e-GvbusZ0NfS8g^R6hJGL!j z+iKOQmC@fTBBom3ap^d&{OC$-*zY_7e%`Wq*uHPOM#B?A45?_$61Elq006G(cMUvV z4JXNp`MNf`6Z7+m%0RXALBxJKNAh5ka^)bl1Rx_J>k8}=D4Y;hq-m;m8u z;Gp4N;qC$M0^q{7gfcCJ@YKKRESrvQ%GkD=)@vH0{Iz?Q$N+$N3HDa*#o&p9v1r4h zxa$l@!uZFV|A-c%QOo`cO7%Y*5O6ebl)27k^_t;=o)^gL@DRN8Q`R4K_l55h`a0?G7T>Wb!Q`^x|a@WT*GK=R}m0#ZOQck^8I`e!fvwEm|W zbwBoL-3K2J{}@YdS%Moo-H2S8YiJ^+R(Iq;fCGT)WbQK~U1JJ`P{h8M5*T*8ki-Wc zvG>cy!y6HiG819muy#X3u^ufGK#W?-#3L)eL*YZX{N2m(*o?3> zt0{Y}I-f_LHHh+Ocm_n^>JC?cf}Ui&Uk z3D61(S{Y>nR4|}{AFJmT(N`6K=xYuLIf5Kim?vOwa4&|uGz8;jj)N$PHEP0dU8gmk zzvy}VarYk>^QSQ=l8QhBRL&p>Q7wQ_yMIL8c};bQ?mSyb&AV1Q!0Od5gF*t20pP-g zi?xKr5H=s#oRMwSuU$Wys;URVCKdob+47Zq65jan4Rn5_GoG0G1eUB{f+M9z5DW*g z^pB+&`sh%+`}MnWolrIUUQNaGD#}x-(x+#t?(T6nUOE32Bh5-D zK7v>0zKTaCKVo}~gHIidCk8zsvj72EQ5l#3Cr(;DTS0W}fM1tgkT1Iiq4bE?VK7^29a1St90nQB6D9Ly!VAtsMI8h{2 zqVnXV|DM$fnAqRcwtc1J9Seo??`aah=aRk56oB9N|88pyyCroB>lm#Qkzu7M3J<>M zcgHG@;g$KX;N@>#mZ|lSVpWTB>tEG%Kynl%sZ!_)3!o`e3S8X!Vm#UF$@mkF$BS$G zUyJcyjMo%0@e#Z+{|$IN9z1o`QcymVID&mI)=GUK(wllfX4n*$nDc zdN-&bK{>vkcK(EO$DWHVGG-5p331-GfG}cQ-)B9i{dIa7%&O0sz?e z2C(|y{25jL68$}wEEWR%vhNoR?=(E^n<_3WmOEoAb@C0xvUIdJB{XJY)BO1!c~Gz1 zQdk2GO71;!0pviAw)ZN_5_u){^Xg;#dE*_ItiJw&>+#|jFUtF%RQ-bhy!!pC@cDgs z;&ST@foDfNi;ep?V$se;vTH*fW(7s!UmtCbP?S9dje-*0c{vt1h8y0w0ayKU6<)aR z1r+BO*SOo&BY04pTa5l~`lBpRhDP~~u&-htwjSGx9i=;PBz%Mo1Y8bPN@$*Qd46}= z*G2uVCX{He#&rM?pPovwf*+;4`X3+3k6-rxl95NDD6hymE=8~G35l(>pBIgUR}1L~ z1#)p6^_Ao)^mvZKAgFNw3jP1L)BhGz{m)KLZhA5%=;3J0g}MJgD%Az01V2w#?jVp@&UOuAXKQ8*fVr_$hG-gY zrE}3+n5zz~LLd@I|3fSY*4@m^_4*b6J@M<5oTA{=#yV=feNw1^fC5Dk<|u9eZ!`;_ zZf;#%)9IRo_xb$?-^W?)&Wie()oOo!f^l=l;rVZ#w`M%@i!tTyDX8bI7mW!}S`}-` zDUnH99~Yno2(o$+6bRTI+>J|Lz7!Aq-vcPCEUU4%Z=<3{c=6H~vEa4^=+(HF7I%R# zv|v-ic~0llN0VHRrgytFp=Lz&X8;_cyF{&dZvFF-sznisgs@`IinKopx&GYfGaN|?Ou1tUd|{ugoC47Z_M|LS{e-UvN5G#vZtl1!6QBT$G2e`V-{Z&K1MX)2{>-*#;-xEJ!aY;&fk1?) z|DMQkK*U25^HuBP0u&HHi4sh#W>VEwH)@Uhrrw9J7>)uBAHkzvJ_@hk#qIrXXa4@$-q&LFuGM&J@mmHZPW(gz zH%TcdQ``jgQjPT>gn$ZE9v+HMR(yh4t7hS`%OArn7u*7`r+Q4Q$I6f4*A2hox6Qxd zw@trc)s|IQzjHkzBqB3CKAjtc5<@{K^o1iGA@?@Q$r3(Q@*Oz{Ay%HrxHlayj6IYI5 z#Ggi>L9GV3=G|)$j0Ckz15n`M&mTsvKNr`Zdp+~F|Gw(qShsf_7HnBys8DD~>q|6Z zof!WoM8^gQv24Kc;Bh?k$wT;P;YaxAh<~Dg_x@RRFYY)gEn0z9at`UMu5aI-Av3{GX8%n zIluGym~`tT83cp_8WR97Fly@k@O%6ian6XC-+2TNKD_fo^!-;KY%Sdi5J87=r~%-l z#sWX&Jrk4jev!HCxxQ zwyR%^K7p}wpotY=2H0`{;8btAbJir~B1E5Q5*N_ZG#>-CSSH@{5bu?%|LSP|E7y$x zvo_97D*!Op#Mfhhgst5Kr951Y0$+ivAmIHQ-p94?T?+}4W?_p|!rhbaMvgBBm!E!l z%61+@xXUG2p^F2-vk zUc)_;?}@qsJb*+c-2UP1$noaj;vN^r{H}e|_IUs1_i^QfE48==SzVia)u|M)VFgjD z^%Vr7#RaHfVBwa9SoqRHw5Zhrmz;44dUfuFwoTfiQQbx;$SXjOFGo}Aq9o!-=@A?) zJ&KZ}B{+EWAoiB*#s0(lv18v3>^QIkJNECu(XyjaY(k6ydBkseZ))76z1PQdnCX8{ zGz$XWXaz|P40vETx0V_-)%nh?n1Ezr0cf1%IRlV|^R2=PR7HiRMB@o~#QzCG1Q3Ff zKna%ZT86V*o}HF$M8pW&n$N&vu>R0`w5-+A_4QuU>l*AR*@0*0JS#uX3J3^`VchWk z4fy2tPjG&h^J9KDu=_wfe9^;r_S_LGxbtXpPV|k zvtlP+|L^N~eb(!8+M_vL(Mq8(VlRkK=ciYdI$%6rffzeEnyq{xTGH8|_yvpqJ<)5R z{V!zZ9?M!9p$16x?*_;~XBs6+?UzfcI-tbs1Mq>wY61Y5wP9A;9)t2gd2Gf@hQ`W0 zE7Nvdqc0haOFCa7=l82k`8+_FgmKL~*WibBKd^sy>1bTo@j^LoJ)p~7w^F)EUQ>Ol zq@j3Fj;?}Wezb^?R$(zukZTI$337yeuCCUA-N@BdCseCAD(lj=l`m+u3P^!&+iGE_ zB3*q4wbp}fIqi4qdh<-ZAaq5bv_?=>naeLZyiSr0d#u+NaoB>I7C=~Iy8*JInYnPu ztoa|c$mVRCleW!-LLq~dNJ!?)vPIh$rIkIIco3^cP->?tLc7URB^8pj;})us4Qb&8{^uzbno!#-w{DA&=%oE7*mi_3RVw8Q{dqRKN!j zNVJWz0tSRU!N3S;Wta7p7xn!ZSnrkP)l$tdN?m8&TUqr&t`P0*kV_!s2vJ3^l!t~_ zQT9HW+0cevO@(Bu@Wor+txAKiSsyI64+qP008kyULW11^sRg4DZ~a`j*f0TK{_$m6 zR$mdQU|V7&&DI$KA~b^OtEZ>+^tEr=9xsl3FV~EHwsc+0gCcBFoe{lYpiDj1cfg5!$9E+`8vyArR0@Cib>26ilg7FR=t_d*ZMUS znA`w)469ym+56@F)0Dkx-7AV;A3vZEBy^?vU#6x^n#KFZ0YEAjHk#{94SCP{{O9O< zNs>UR#8@u=pfnB)jk^w53`fGo`w((HiHsZ*GGM_ecyqb*K&mD7pAv;83Upe}4JT*mY=U% zpZM)d=v01yfYgnZp7h<-;3pwaY#GDt3rBZol9RX+FY zhELu;d{hZgRE9?xTAqI@b6jd8%C6d+)3gmlduXW74PxhQ%Frtu08|mK^7;Jsv3-xL$LqY{+Qp5y=pAZY0EHB! zpdmm~+S(fCbeFHW_P+o*ciu}teUNkV{RGeg`UD`C0C_e;7XXM{-N?}ofcoY00Y8yn z)!cn8e_!4ob-xVvN~-q^b;pxZMRB^Z-et;GUNxyAaK;$`svxOUhmhi~Q`4W-cTSFn z3l~Qeu>gGf`=_q2+Sd9enK`x>et046EI@-=4e-R!Cp3RP6_saCX>Yu>bSo}<^)ehT zJ8bx!-|NQ*cYT1m{<=T__HAv`;QC>?28d5rU?&Im(f>*u0sPR0`g?77qrQ4AMbD1D zCpGXHOQi@=67#s%>vc_^)p!8l_Cb0CkE=x)5>fhGxFibzX8tkL^=IK&`7wK?Ptt!} zzwQ4GpZxMk+E3&4=UtBu4LU@XxT?IB*1c;Ft;O&+hU0kUal`ML*K3Y@AzSilWWS_D-+N_idBxrp81d!^RD>!Fza7wR03NvLfoMRW`g^zP10=&YTLFYb z6*+&-T)8$>r0gsj39cHP*&;$Zlzb-8jUWhdt@*5AHK=jFxNsI=@~X+MuC~0goUKfd zp_%|nb-BG|dogDAn6z*1vU4s&>pHDvH-K8;hf=MDF!2-oxbsI`H}N`zA|b*A@Z0z9cn=M78_2&^iv)!g>(8zF0DL4qr^cH*-DW#rn#%!a{Q#6# zugB|_Zp^p=ohbm20W%!7Eu6StpG($Q|4RAPvTzwb|NV1!0RSWCKO;Rc^quDffO;tI znsyhCRvb<1X0Pdg4RVnyvjA#50FAN{YT(?=wKH+=hxZ!Tx<<7d;q6=BmX*Hp`;5f{ zoG4a%A{ISO!}eYD{~Nk(>hz7@<2nN%WmI>%2molD&!{BHFx)McBiEN3e{W3myIT>L zJo2AQN($2heDupluC21XvK&PDGlPIk9~bcu>@3@fyQbWg*5{;lVQmcVIT$o7D{mT6 ziu_Prq`d+HCa;`~M?QVT@cZ+-o{zr{{Hq}rz;QePm#POEG>z+axSbq-j;jm+rBpfYJ?b_Qu(GZ}EF+-Q@7z!)41oq;msE(V0yv#hXj;=HfT;;1cr4OhBn1*qG^KadQ$-eR^@KZg9DDtGZu+fh*e(m z{rRo}08tdfDRM0dOUBv(MC=HfkZ|PoaIE|Q!`m1Bp9f$Nhvt&DU$N z06<_WX(a&=Xl$UA{)Qmb_<#`?4xQSe0mfZUX`JOU!U}Oo_e4nm5Q=HPO~n%zJb`)z z^-=}^=8ec;m}btB)SBS{RG=VU;J5w1;&|n86z3JEWs^C+9Gus+AHM$OYtS$S2?I1D zfr!yQ_V6f=vT_a{`s^XpEv$>7rw;`HG^x`B9h!8&DSzvTfjtM}hTb>g!Y&uWD|k`A zpgsn79E`yo2Lk}M9NvQeZkUU&)_sMacl->ANKs|22Llv1z3J(AtncIK)2a`1-)raA zM(y0%IHkcU7}9YF0ASDYJ(&L6bbPSleQZ0r&DeIAWHA^>H6Nea^lNeQp2o56nIOQJ zE*`D+PK_0v^(BGzt$-;-L2iL7x=fNJ6#xVr9<^&Cr16$8obGTqT&X|URHZPt(7KTm zgQ~YIUFlNLeljJ4`8a{g0}DW<6u|pS-cR{iI97JdpcFD$3fOQ=$}0o{>H)SM--c^G zyv7iP@3su+c>$;hB@O`c5S8azEqCjIRvuUMiMaiv+p%!nLTw#`P92254SE2xmd(b9 z*G8bzqn$A3t1;MGvemGyHg((JjHC;_{eLZ$zm+sCZi@TPy$>tyTZs>ce}q%&bdt*!hvjuk5{1^z#O3*`S`M1zveX(I z$7>R(|GX%#$d!9o)rsM7xWZ!7sBQotM)w8+figD%K#{-5y4|Eg?Wpa5waDHy6$Ij` ze|#jGdZbdwA1wa>5h;=y0}!aRr9Vlgkbr*MiUt0|wjc1&XAh-qa_QZzHxPjwyr%>M zA_C2CPpHzyR;{|{CkS~$xN_o^SiU7%km>PZkK^)FF9!`!?Af;m4EPZBixzhIAf+AMg1Q z?+$$zjdL0UL1?iKF>wjmoU$k-_&%AI!f-IJ!)AS8oJ$~@5^AyiTDi4c1pt+mm8F@c zd4)77{1_=KD?0)(s+J`wb@J;Z$4PMEk`1C11=>@(2h&%j)+MkqR2f@$zA7nVU0NXV z61=zMJxo|IAuXHg*s3Gy7uAm{ekF?Ekj|&nD1cW949p>@B$c@0tt+s0_gckuLGXX~ z{T~K(8zd{*AcYi^u;BLvxaFN&(C*=O`1`cKW6hp5G5gTEUTZu$;8D!HX(n3MZt31> zBm~2I49AMUt-yU}-v=Qq$mxz@-7!j4Jipb1IW@^+Xi(U|mCdUK`?*ET91R}w1+Ux?=6>0a1e>OvK~IFc&I_E z1bF_t=ToA|%PY!bgJC6;Rg=NvQk4=x)EEEASC3%Uuj%O+ct*Q3GzLIbkQx|}qA7hE zC{gO_9||49(AS4z*Wq27<^9P6pWuqKuaJMQ)CoWcICAs|Cd{3Hv!6H{=RJKM{)paB|X1Wb&F(|M~}3^B=Nsp&Inu`a6n&TQqg)?<2} z>gLyV6#yJPdh{>@&ZRXiP)LK~XOc5JckbM)_&HqJ@kT|B?03p8IKx~YAc^zJ3k-2d z$@*8HJ^|Q#bTekGnvwMCj#nIyT{o#hCct!j#7iJ~B-}pfcC6X8#`Vpe*5NdHlD10Q z)140@C`^D~b_eXK*n`0@4Mv&lp#&iW@7?&Et`atYy0sdb`1)vy+l!}OY5a_Iet|q z?%cU^pHqFB?F>N7&M#fMbPE84LLpZ+*1T5pXimS**B_Jmq)Y^q+86hTY0nsExukqm zeDGmsz`T5T$-A?y-*>PuZyb6zxcnC@(r5OI^a2z~-&{aLu>7-6FB`!t_`55Z^ zn@bk!+!Mq{u=VIx%v?DWWq~pXL_kHL0^@HQk4G+lgjw=f1vurwas)%cv}HN4B;TKp z3D-=(+gH7fd?{aM1I(q2r5ZR7Nk~t;iiFr$E(x~r1L|@u>a=hb0IXQCVk_*cKx8EY z;D`;_v}w~Z$Q1!y*-)M@4>`UZ%REhOBzexL#b0I&C|>aAgkb@cSb&X(He$-MDG9Hp zGFTa9yGRvV{#M7Q6bFJ2*j=$3SH5{=OsBq7q(jRN(QcqRC1~i^0pt1BVgeKp05U&{zV!<(@8doZxzS1_5UQRK@bIIscLa`Vx>pC}1c&!<@vbngxK)_wFND zv3mvX`OiJB%>!+lx0Tz2D{cU7nEkylF#&3JfRAA3@tr8lFT~ydxf_&HG^*VQTlQ_i zT^HSjckg&tUcY)g0@30Ky0z+7W%{*U<93+$z&zY?#x0`xah@C9XSEA!yQ4UxRRBf%EvCo0lkOM*!>M+=7JwFnVU-TT_|9O-X9yjenS(?o zK30W7&Jfff7C=Wy?=9bp*S>!(Df-aT`pyQHL(uu&l_>lfzsMfXCy(=6#!SRj;cs`7e{B z<;QglKsfWo+YFNH%f*XVzli_4;r~!fij8c5ltpYnyty%zN`k4HtWHc>)3)mr)^X+d zRb42GVxd#YM*-V?JZRBTJPyb66)2Fge zcbs(xUcdBpbZF24&t3K$&TV@x1VO;7b6>^yug0TQgI4(8`u}13!R;7y>L7eR>T?w5 z78|+_F5R{?D{i67PrDooA6kgc^*TpeB&W+Ikj?X4oD#rHr7qe0-U5I$snx_49j0ag zR903VkHdeYP7| z_s{;GumxeO;7N8Iqu%!pzdY`ld=HjxN?nPzXw)Jav9C|PwMeKsr{y{L_rQNgEopBq z^89(YwXfVKV9c~Jn7Vi>M)nzrF;m81?~%Re)u9(=KR8>?|5nyDY3Zb_xsBR1Y=e0Z z&co0yLycJiRZ%k_6~BBYvH_gz54E1-o7Zjb%4t${;nAZ<4`fpDr-K1tS^b9kdkL$ZkDp|;&MO}otDYwSU#J(}=9-|%z_<*nw#)!8@V9Wk3Da{2<>ov6w1T;OT0u}Jgz-Qngo|yGKJN#Lkf6Dow zBE_9=-if)t%*EqZK8~xNy9$R&520JjZkYSvT(m5135dXqpHC+O^$kiz`|3u(f#pm5H4KYWC1*~a{Sx$zu|EC;nW!bl0C<#9jC4| zFZ@7Bs01S?j5O9WNKhKrZEXF#n&gsGE({Oyzk;0dJYRe2wYKXj&M(G{hi9PJUyO>%3Jm}Ea11(a z5WbG$f04TcA%q^#t{&yPySSo(?eMLn@NEF2| zWpwLHR_YhmkG6PHBmAk>7(M#GR{bgZo=OrZRofH0JE+B7NGY!p#D}F{2ZR6+D2NC6 zX6@H_cj3GC6rvggNEl`eK~^54!o!0I06Y}L2M|B-{g(N7aMA z$}L8plj3*jJGsfpc>S)|0g^)cU3t&*6biAaL?XQnNG9tTh}Spd~Kh8Gz9*=YQ4)Bh~*{|(zWu&GQ` zlVcT(Ou&0TzK4nPCMG-&6c-f7#_))-&;Gfs&V|q8bF|K3y@z3VuPXov*t~Bu{yptq zxas_xv1sigjCgSb0^tA(atbhg)C^qO^HQwZ{0n+L{3m?1_X)v0MhZ}$4dbBG67oDX{p^%l7grtZAkKG>dsK=sE4#>Uxmn7(jo#5D2IjfR6w<1P{-67;}D|lh8a+ zm{+Jb_?5UHUEg=*+3()8M?&izciT7=&WS(6T`*%wIhpBVQSbP$UGu z*N^|Z_e0#+|0WzQKZX&{jljKc+>4`SN3#Y5cmxlgzUmpgI^s2W!d}o2g%qNo5kL|t zsH8tvDO^+P90MYe-%@wCZ&*&r9x;5boA=FRa?5(HT)8Hy4pela)9~|Z!vHY*HtpQG zb29)`R#v*Q;r0#N$NKc8*nkeTEHKm81ACn1G^f)MGhhds?BG+wI*j z@vDi5h>@%T0yp-(5tDA8ggh}%t{0#N2S#XYHN0fzAK1*NPV3tx`kj?+EHPLB#5pd? z_>Jka4oy0^axGLHxNFz0&9LvUS#1~q*suU10CDl+#jDid2R8~SbZOkhP|Sx}*vG7h z!2kqRAa2A#uqp*|spg`l$|*__USR9dtr+mk0BqX3$*}0kjVtApIswLB0HhioudYTw zsZ@$9U%wJ1GGQ2hA|rx5*ijk7+KH!c-F4|*Xjs%xODXh@FN>r^A||YV~~pD5dD$yt^y9OAP>Av}n;P7zJa^CswlHI5j zD`lnWQIselvC6-iupSx^P>y#;=?+}+>J^UqBX|UlBOh_S{CWw`G5I<9xNGoTK*XpV z)t&%ft@;YTZvWK)%Ig=`N55|U@b6pxjd?H5gGfaTyni5GnfgjrxCYK@cNXS6GzU#` znnW`Mls*Ei*omy~2Vh=SWat7XOayFnh$Oq38W%TqFE4NtBPXaQoUIKqFBXhker|3Ncac_jT?l= zCq0hEYZrs$$e$CRJX9cH>kg<6$E%bJUcP%d?)~82xNKQrej&37nEBDGomV@l-Me-0 zt?Q(L)LTljI>OLyY~ON>qC_cL~(02Wr8Dl3^r6^CbH_ zKKRgpC;_O4YAtmm-Uwct^CE73<7OZiT3KDyT>t@~#MH>T8Xxb}6;tu_7f(By;PuC< zv3t78pveNFdbR3d$k{_c!@61`%D!HH+U1Vck?YUJKd$=+=D#@~t2V4c-#hxE$2C3h z!pARQ``+zU0s`7LZj0Fu&qmX{rjP;>q@V;ErjR0%p=L_VwUUy&#-^^UZmu)ld&B(z z#^(<9rANyiu37&8py)z#|4MTTVAeMSvLaBZ?!dGI+_Y)aI>5a^z%yH&8B4Llo&jLp z7>*~HI1GWKWvF{Vj>iFvUN%0JCPzTJ9zT(5Z1J)Ge%Q+q}WH+OIj9-{C|; zE&jN0$tVcOi-G{+BN_`(ZM#OBkJl%In|nUG2g^1sWB#P9qRi3pmWRrd-mUXbKObJ| zjRF8gi8QX2xKB98mxGt?e+iSGnuNl_LQsKX*@k5pJ#jQTjqHS;H}=GscgJAK>Lp26 zM@&RcZhSI6|J&!tr};6Bgc2g5lcnmZOW&nZFgH&2LG9w&=-RBSE9W~H3<3aV&z`+3 z4g-+Z;`8YU0tBr6{~`c!&6+g_B}s~?ZGqj8E={|{ZjmCkhVNeg4$T@jGZaMnW7i*ecFMEpdtYBP zyQCSee*9{@_vL$7zkPk$KtRuvdt%}(6Qjj~tUy4zgZk1@D%dJW+)T9VnF5op=-R>^ z<*&8@mLy4BwQALV1^_TCe;~_)04)d;HUI!1mX(zq0^BPI)T?bT?cy2y?qK^FnE@dT zL>a>jq?7jI!X=JXtnZ|!F#-BlU$mhRNDVn&B`W|v;85rgu6*^%n8rb&a7atdvy+nY zl9YDqPo4fG&tMT~SpkK)g(7q zE9H%!)#@w=RDcLk-U>nVRh>|D7B~R`6%=GEMEBg_Pp7)ykyz!OsP8=?Q5V0ZJ*>9$1STC)|inM|~=%{{bkiER}(edhCR4lI%XZ z8$Fx%Oi5W&k%B}>6a=^+P3kql-0^d9#n>ybaP>kXm@!pTDXA>M%q27N#m`>=qWtW) zY|s)NT6VxGC!K;;ja#8rlU8U{w-Jg9icyePfP%aN)Gn%xvWhZ&?#<_p3d~zE5BtmZ%b+7ST7QCgh&*Ep4opTnh3xdZWY=M(;MHb7de^Q_Gieze=FoMM z7W2S^bK1D;|KGWD=SG%pw9uhxd6L}%02HxP4z;rW0f=+w&Rx>EbLU=e#Q_xN6rxLu zF8FoluQ7W@L5&nTu~6{3^Xnv9*h=9Nl9)2)aRXcuQiduBAcWmbu(}lja&WxFL$v3Z zQi{3j=HkJR9>hyGyd+ywm1QzhpjVuXbFi;;UrM{vrdb==B35hYi$Fw*z$>Ial@{g| z;`4ugj_aPg4&N;Q#>nKv)U-F+j606*!1lx2F?Z!$Yu6?#^-gsw2@3OI{ik}Gr7A{=4jZ!Lx z!(lls&xJIiK5hHhXH(i03o?DDPXkHR_mr;K0Y3PMdHi)$IWzFDrjUTSx+kRxu37zN@>~#!ji0E}y zsv{bLKJy8Ld;ugs`k9a`MB_o!*Bk=m0LW2X3g+Qc+(|y7#al4h6A7sm=1IgipX~Zr z&3wc-+%zn70F1}nw?ki7bd)4XY5^c|{`~n{}g%B}tMe3`sXZ>MlAJ6jlIAfF04X1tvEDC5bTuiJdTR{c}l? z4LDJbRZv`AQ1baH@Zcv8qIJX8C@n9QgCJG2#$y6R%Imhn+fv$%I<@M=I5!WK9zyMc z+U`xt9xvXx{~h@Ketfj}qi8iqH9b-{vl59!gY-nxY^w$kOT-vtY-Wsa`Ypdq}D-D1mHVi=80|3*(007p(fBOF; z0L0CkH?IMJii!$XHr%XsGjwUzg&9$A8D$T|6n==Ou-!`eTM`!ux z3m^pqq>w-;5Fiu?AcgXKQXmhZK+ygt`Na6YIuvFhCZ&`hv9!`;QvcG?1Hefl`(3N^HkQPaY3&8wp$pB27Hf=HBUOfN+=+~j2v$DW| z<#PJ!VexLnWB@_BiUje3KwM53CO}sspj0fy2S0ugrMvwKrR|B03D|mgt2?utu9(=y zJsZ<xdg~Vv>;Tz$vsdI1p-2W0HM%gr~o0)SXfG9 z1+3;47h?lbvi@0}0PQ*tQitDDpkJqcu3b}A*G-)|brFLBU@84HmbP*~3xJp|fmIAZ z1c11H{rZw{I2;6!Ln(Ddft}XsH0?p5l!8daFmYJ90kmuYNv8bOebGPwai(BhvFd3R z{gw-tY6b-0mG5~1#p)Mzri~I0ATKUc=f^6J;Yh_1)XA@t)Mm>o%cJv(GEJ}FmA>43 zfe3i>&No3o@X^m7$#at$apofE=s9&?GPJwMFmXS`r~DlBtXYorv4=o`ERwn zg}StA6R)`iERxpsv0rY{|7!k!I2;bHU%$S@!~n1|0Hk!!?&)#?uuiL9`Kv=baNxjp z04OgncV*)(YPZ0dZO&xYcb2Hcu8Xd#A#QiGCE_Yb{`k{aOV zB}_l|){^8|fYS2P7;ACGmKA9|T!9F9x^f*=`d`s`EalHC1)MhjeXD(Y`9-`4Reh6@bX5rCgAYCsH#0!%AgB&+ zG@{)c)Vrl5`8a?h$B)F!aw|5kKzX1%?I7T-yWYakQ-^{El-9lBXzN}=h{g;Mk9_?4 zVE_m|u-~g-${Sr5Gr8L;DqnIqw>gdcrw+EuS{GoQ$|zYZXTbzq(Cq@(u3;b$008{> z{e@3k~QeOjp#&#W8S>eS(9Eb1SzE`XRhl{M#E z1cieF1-S*THUFWMLeX*Jgp{fjU5EI z^GTv)tz@B7#CjjUMA-;Z`!~VJe~ZEp&Q2<42e@#tWdih8tJ!)rDY?xho0Hzu#vL1D z7zGgE+h4y;OFEzx2$=lfWSrjO^cZ)578~GJ>Rd8bx|6`aM7Nzt?msJ~4~QG>4;aD9 z#oaGIQIQbZXKGZ5p&O zhE>%WWn}|{rEgWsDanz@I<x2|CduNlRt`Y-WHL3gW`03RwXQIUYEU1EmL&TJ4IpE23#} zYW#un{{4mTW6Oap89T)Kwd&)m$G<|;!lqj5UbRDE!ro(=!UAs=IPCI(^=z)-22*An(z-k1PRwdv~l~^Dk3?RI0*|H@A z2M)ZnqM`!1xw)?Fz!|O1K&~ejm11SIJ0O&1Jra$n3!v5ku!KdrN(b7_9j88kS&2I> zC7g`%=YfP=xHy}Y*6mw|hD8k%`swcdyRrY!ez^#bS|@~1EmuAu25|R(?#4F{exr3M zOt-XZ*b1MG{tN@29Dve5DF`KU!z3TIPvJ|4@~3g;qhvY)TJ4);!8e1E(xmVi6YONhqGFr<=Qn;>HlTRmMvje|5k;7(nkBIn*pGv%S0W3fXKv&6Mv+XN^VvK zY*xD&26P!w zm7VNaXZ()$_w(0pF0SjojG6n~=bY#Ecs`!bV^A9II&|aRan4Kj^U|*z_CH?b?4w8i zd`pGprsZjdUS#n|i;IsieKzBug{1%bm;Xp|n?>6zU)T=zd;U7#ZHRhm2eCJWC~;;k z8m*R|u5p~(y%dcJUEsm6b+_Q||J6yBeSG!0ItJh@vWpb0^`}=d)%m&^S@U0;>z+=T zyblh)Qj43?6@((pS!x{M=*+J$rL8VF=j=qa|e+$51$=Jo`%aG+z`p3hJz zUH92Web%j{Z%IBxK18PCIYV`P$8RX^PRe-Bfv090Hm!rBO(Q1LD7jWeAgjrw#;Y}ieb#A~|+_Ht=pzClodD1`48 zebIr$TXQT7-4tPC4!_E(`J*cR^GuXvk(Fdwt-1v#qvyh5MRv=W#M!j(o?op$_j_B^ z2Pm8|{JOEpkaz*}$4~* ztnrOD7HjQ<)>@iew024Iq;-*37I$#F+`T_HB-vB*v&!{!#2Ju7IrI9a--#W08#PfD zz1j0(hoB2#oyn=sr=LCmfPo+spO8@V>5_Am8bk3?^~GA)H`r-;W(HKw&AZBCTz}qU zS!D!3-Dv(72*BEu;on!7r_vYKc=BfmFvfHvd6lV3;(yHm%pWak=IGx8%rJ?$Q%gDT`hb?asQD?Md|;iS7JkB@?2cy z!h@eaQZ~ttxKQkjcwSm_@nc#1`r#V!_`;N1Bo_L70GjfMJL&82iQ6h;&2-J_slq@z zq#5hriKCC%v%Y`FUs|BQMVL^8c)o1rciQzTh;N=U{;3_6uEO=--<6PE=lU3ZrTD?$ zn*rp#y*1%%bz4L?Q>JI}D|#wrCZ1ce<|^Xd(~edLPpsgo7kVF0P=sh#NObPxV_PFqsDPjOK(e+Vgz-jjP;hJ8Wv;&ghtC1oR&@H_s7p13Zl=zP3!R-T=;Ft_)k(ha@4cSSV}G%PGeepI;*31Js&mCO(Wg3wnlga!`= zg+v`Sv!IWl_Wd_*Cia{3wv1@6&sEheS$i@2*Bx_MJ*S&;Qs`h@ZssqrU)84k+&gS< z9eHP+9*}WL?qXsWyfmd*DO&o|^YMInx*v81aWCMm)e(7z=s^Crb6@$Z7dUSe^iX)* z3n_e{(U#vahnk1_Cl2)D#XXuZ$w9|XvJeB-9>()5;}VBjOpiiP_8djVwr-E6-VLF8 zKy0OkrN|IWw6I~4Q>)dJ6bp`)n@R${3Owsg-?_7N@1!TEHWlz0*SQ%b(k3u~77j9P zh&DO*?kl5rg#u>f;!Wat@8J~M^%&sWJeLrRyl|oR@Gwtr6iQDhr;?*IXrHfkvR^Q0 zZ7H(asV=;^jpd7fRCcLQbVjj%Cxm(*FJJ9RrNq>!lW?G?v2R7?-t3g|N$a#@H~EAq zV7Y6@p($1?xjAU%PX3ljISb;a>!N+qkmO~I#`D-FsLATngM9>~tuvn85#bpryP5X- zyFE;-iuiH`g3-XNKRf=100*PqKnFS2w7c^MH@`1EubCh0wQOBlGG4~|C3xqu#66T6 z{7(}EzX_TNNMaY~a(H%H#VQ->6iS{P@dY0CRacCj*4%g!v^VvRMIS@|hgb2vHxmc1 z_*X5lE!iQ6`Z0ghvlb>J2UwcEi2x(uZ|$J4|CUC~tIvND>ut=Y zc{DmaT4_k+8()jO2(6-SPKYnE&N z%#U_H(Nl+I#?Mp@*&hCSFdVu{oyT^7He!SrXv;3b7^O(B1XW+f$H%WcN~LPwnYI5z zxUM4o$Dxb0Y~fsCYCHlC`on1Nhe2#2QDpm~>B8)s8*~febug1McFhKR&5pj+DQnXAwjYQndDB&a(R4gCDr#-CgF zzGnm%16GXt)^u8gp633SAM0%euVZZYt-8mfYW7klhES7)wb~s!L&FN^wpW5Tq>6B+ z)R+XN*M$<)cq;hzc?m|8{QaNr-650!^OxGQ*J@eRe_KX7Sgy8KPE-|~BEexV9U&!J zjgxpJ_H`7#6i4P;3*2Samei4Z++v+}nB-Odp!s6BaYl2&PN6^!T>z5h+!$J&8q&_kUaOh% zOVAJbvq?@5bg%laaMrvZSLgXx-nYcv{L5)+#c5L>gabKNfV z39%>|l|_ zF;&)o3FC3Fbm~maajsjA?GLC$M#>CD^(PTYT<@nXT@OudZM zGo*uRuj3I}kg(`}fS2~rH<_Z*W|_)94t~1aYWqA9=k~I%R9O(me|$NxYF!eP$+-;w zc|kcV&kaTQg31D$1WZTkre4)c*5$F6WhEpD3o)F_e`ampHZt#7R_7OX+LdN=q_^}t zV`-q)uxt0(-3PF4wAf1ICl5rCz(vRQ7HBiH5#{OWX+8Qj^>93@oDh9?@;!W*64VqN z+ee?IbO|)n+kP<4E?Hd?)$`^i*6h&mJcG~0USV-L!Fqly{zUr62${6e zD(5+`(z}HBckH&yZ@7%Zgnwjx zkRQ@0aTD%-i`++EZD3^*GY%pL^Vsl674q>KQf}(+tC|n`P7D^W&272)?o?30VIV{K z^y<4Q*V6ibVF^MA)lH(dvzI&P1EbPCD)U`x*|a*~XazThbKCme(bNntlp=}W)@_W< zxVApfS-P@oPFO3M+6V4Qt}6JvOJ8pl4YlFJcmdUyTt2>@J~iY8?^{N-8qoM zAR?w*k}%Lc%Up4{rN?g+;u1-2)EqJ{gal618LuCdD}{I#HMYp_muHtKGAex|;P#OxcJ_)tUOU$D>vxtpSy59$lQ)Zps_yfjXRoYNoMxzdcQ0>!+{3 zjwi$r*zfns-nSdkZDupe!yW47Ow8Ua%>JxX_li<#vsorqRIt&Xwb_^mSi5j{QHn4~)v-#>U3+xTB3W$sHB?@cyGZ;WK$Hg20=0aEus-r$P!l^q0?rdx>jM;i=14lQngyA^60+K- z=))oC#EQl>8q?gdIkxNMIv^JCLZpV<9?6YxBn;`?ol-@aY79GUnl39$hr=>Y+RQN4 zo&V?5KLo=X+>PpL|3>c-`s!ng{k#n$D9lxhBz*WRbyu?LY0-gkQh6$O{_TGu%9v9x zE|?VMQfMZlo5rr1$=KY#FAfqK%tBW_ucf*-SmX}fF3Y79R&MAi!XQ;Hd;&9%yn$4s zGa=}ok+wMKN)KY(0nl|)8@;_WEUD(HnKouD8wwwX!%W`2SLOj=uS*6&19v06ILt6b zuv3_ER=AW?b;Tm~qiTBe)|a%kB~cE|Qy~~A-tb_|tLL`!;<@4ZW9R4{0uv*ilYx~5 z`Bc$;BG6;J*2mREWA4+HD}V0vOXfM>mQl|6cjtBU(mC3x70|~`L2vPV;hs_XL811( z5l!dh^%4G1n7Dp*nY57Lzr5unqXC8G!D6c~kAAlzzyn$2<18G=W(rW5B%@;jQ)aGZ zs6*SUbnys#5f1v(JdCxqUZ7d~=lQIF;f20G+zu0!MbG6Xns0r4u&G7G>Y+~xmn8QO zO+TA??6T859hgwC8B-l&T8_Z>9mz=*A;-4n1N38!rk3t9QHRl<00D9reOHEMx({eq z4vw9c?Nn9m0ykRdc#-XF9nYvS3$Qce4SgeAqk|oRg^Qbbd)pI;P8+pm8qZbjV?+9J>-*Y6VD7yBi32$`g zNLoRUrL7AN8XigV^uB9ZYhQX?QQ|lPb;_>ISWry8#Ib^rIfrijqS?JgZkL8+(hH0f zAO5PO%oA`E-(@u{7I7BtWQ0i{vyu=4)Se@*!A`r5alP}-w{7s*+D4o3@eI&+6n@AK zME9GUo7Usye=mIbUE44;olPa&5g?xIrp*?V1CJgY9ORy0&AM@eEvGdZ(A_!de>hkYUSr;Q#pK|MI>dnfBpY}UzSO_uf7Zg!OcSBakB3xVu<0{a+ z1@b0VStLMKHFQOL=$1 zE5Bqg(4>v}Yx&*<@{w-Qt}!o6^;6^b&FVY4MgDBbmtZNE@4d<`36i*wlv7b**tIVV zDs$xd>zlQY3%Lf-u|aZBQQK7(_!Si{Qf^uxI;$KuQ2}1!MjyV_{`=)Blb@G|pIm$1 z_WO~~d`iDts6p6`JN<{*S;B1N8HF1#)9B0J!kQM0azE@?1kG>XS`tkS+U-yix*`-3 znYwGF`1eis+Ki%xjwmy!qe3?xjkS9YF=lu4kN2c8c^r%GX5UZ$P-1t+fTJqy_~f1v zZx;VRcy04T^6!MBSw>8p6sC?^-Cv#yVog&EI#>fz@=Hp~(6Ry!Wdg$aNzL#|pNaY9 z%DxQPVgb88`vrGhy{*^XyFMxY(6H&YSMw5xosE*>(RU?}tz;TFb3Z97Tu3UctmKFj zxwAFbotmphps3m-j*HG5pOqB}cdp(c_&_8WL#7@BqosASHWcz)IN0wxik0?#wnL_b zS%#OWGrG4UTpXXwK zC^`g#THhre2R+lxO)kdyB==FiF3G1l2|_Q}8A$f{yDK5UG9QsS>2>$sB z^;w1ipO#;qFZKVqudJo<<0e~Y7dZbMgfh0Zf%}^_j5&mxQv_o{x8)*lSTgGyA#O_( zntnUfe>O(S!AE;*F#^h-N;dUy<0t=8oPQMiR1bS6`28sI{jZe$5zNtO0P|hIBVT+l zQ01=!&9aZ<>iL4A!t%|vpC1@9h>QD`HvS0*XwN_G(}3NKD;+v5d+{60+>9JqQ!(;@ z?0f-|O;<7%z)x_pR=m3(3c<5)#AKX_$l{?7|49$Gt)pmqyG(RkbRLkS#V8vJ0IE}?lfr^>rOhSz>6 zxIVx9H}LGkttz&48g223;KS9o0smH%zx_O2rb{j~y^kB9hmy^q^Xc&J7q=tF(k?lF ze|8d7BJe=%SH{zu&hA**-FW^%urigv%hT@S)#2YRV#LZMpjOBB`EGZ(j)@%82G`Ke zTRlJiMJ(0IASl&v9^D)(c^yL)+nak>i8jwMinO=!n>bk?usd;6BowHiO5~fo&CPC^Y|s$s!8!cE z)#2~w(j+SMaL` zGHJ*45E`N6f&F|BTLH;5H+~yq6+t zNCltg3Ouv?sp6>kQ=9hI$3-)2<(o#StigsS0d-GyQ`esa-v3fGJ3DLHaExHNB0He# zOv*TjF`x{z9F!_D;=|N{9u2jxK)^#VEpPPHl*0`rsKV5NC$*h!txn>vt`E_@pwhC& zgr$P>aHQQ)&ebN=%5OZvlV&vxHaiv`q&MklEuR0mi=b0m)-|NQpZ4Ub0{4hKTLj(S zM}3N*mCx6w0q00({eJq^AVTmW68Gqj#-IeTPg1!39#d*t|?9-Ba` z_?`-$XH5(yQ%+PeRo0^LV!WCA6V7qnr8!2VIY=I#xqsm|-0%)!3`r{>;?ZH6^LHjF zrJ_l1Zp7QZKG%MyE%Ge3{Iz09IL}Z{_=yDSSRyEp@`B#o;M`kpFYW>#W4Pz%DQwbF zRm4G3!LozlLkNHSA;d{rW)A5Pz5{Y>uoa+jdvYS*UlL=5Z0j~Ow;%Lfa+|~_n&3&-PpdrW;GuCv%XKsu7EbpRGcZoez5MSU&S?$mn{x zAX-N8`i9Ku`la{vLM-j2smi>VktLeurD|CzM#d1$b5FHXb{7X}e!B@I4K7P*#mz1K z=e^K74H90s+GyLdilgprT(pOGobfr_RYScWdoz(TY?SW1Nj4wclEqNhS6QY^p4su% zK%3AX$!rMo?jn8v>o;$Vwi{`L$KnVC!rJbk0f=4yu^$hPRm(bTL@i9P<7qz#!4B3) z3&K$AagkYJPcrwwbk+QA=(FRytB(ij@(O%<<)ygYEjsuZhg-yEt z8R|VUd?!vZG3$ywzPo1kQy|Mq4(V0}^VQi`4Vtj9SaB+x3~_C&SSE0&;>Nue|Kl~F zxV)VNBq|{Vm;UzvM0Bgzlbrgt=FWUjIM`2=ur1edyZR_W8ea&Gp`&^yQafMk7P=(T zwsJ1d8Ii}tkMZd;w>XlQQ_SovRsc9-<=CYfVbJfx2fm%pV2Um(4)*f*0!JKe40TZ= z{uY19C9}mRC7tDAyc#ER|68)0(eBzLZus3MOV%^aqkIEK2=S!c94hpK3i&fVyHgYb z+M@X{ryFVmm0)`AV*1Z26SFH`tC#MLR$ln>l2y`QQTMWXSP$Xn@XiPo;|I1P?<{dX zHQnR|+)(kccPrv%SzOI*BWO%f;0V-$iKefqcNZ zF=g0)zqUO%1n&8jdEZrX2zB>n`F#CNYyNEd=AULxrX==L(76NtYECqp@lo8y7oOV5 z5Ce?*NCctvyPeIbcgra534ipGd}rP!LFv)VWiX5_-@ZD#JB?6T7Nsz#ipa+R-Qo^4 zQE6j@`pvewv6wKgxo;z~033eevP-&!haf*n>%3gqJjOSIkTKbt^YiPf*u7v`@v7?W zbXoWng;y-Lhv+B03r+=@8Cy}+LeFMm-a5?euo>`P7uTi#=q8BJ6~rgG1&E*Z%G2F< z*!UPM=gL)~U|hJk_kZdRo-@-(g|EJ+-UkAMAbe2R-q} zCJ}m(e}>vrngxahxymS-Unw_TvRPku;T*0%vH#vr%ATs`E& z(=Q9hM!CA=?)j}J&zblKFTX)y7nH9(TI$HPAKQL3T@ z>%FMo`!Z`DgJ&??{OkVw+!;;$Z2nv+zfweU8{Cj^=L1 z$0xRHhKOZjV?8V5^`G!6n6Roaq^A@G$Tn0TM9E6gf2VgWo$bi+x9QXPa-h73yyv_z znzQ>B6INWFY4yR)z-BC{W85>RkMX72)EdaMr|s^~6G}go9sHg>w8}XgP$J@@sUVPO ztVM{VYgh1N>u8`rfHD+HN=i0A9(&Z5c`FRBmVP)D0X zbnr@(&I7Fa)fEIXpGm1KWmriSctLmF?y)WVST>_=BJ5bMc;9c|aUEzIzxMa~WJ%B^ zf91~3PF6;0b@2pS|HYir;JxYR#f)79lV4_nMS;i3=gpz4i>neZdKW6;^sz1xNThO0$umLU{Z^YoN|8DppiIXv*p>W!(b4}tB*An~!zK`xL z;p{AS>B?plp*HnUDa~RVubHf?^H{vjZIgdRJBHkemxH)3#q=RWE6ndFU9zNU{{_AoA0Nzov(AU?8V%pyPc;YgfnBceCHB`1m(#@Vk z3t~vyL{U}`op)aPq?}p_f7v3Z>S35_iyk`?(vqNXFG*=+^Ol6}7b8(_pU3VR-oOg*PyGM;W~T`s-Z(We+?_l%M0u?MI{X zAw6l9hxuZ`sB@PvCP({}Kx@@?OY0|p6L^X7007lEBPJ|uT1-mnY0rGu9-?Bm-S(D^ zJm=)mTI${d{NG#p`q>PyN6=M)LiC5vu|_TF7wFRw3?*OtYBDrnVJUVjok+y37U3KF z{3*MnUo%6J$C2M_Y0viXzx?2n>U6{fCI}1*k;8GgyCzcu@+Zy!*Y^^CEJ;LnZL&Cr zZO%ieYY+*JT=;@ep@K=Uw)fS~!PMYMdI#40!PwLZix@#8xVzrCfM_=FGpY{4|l#3{o$wGhqDxAsGSwU;vp|=CMRus zxSXtP&sXYusHuj-zlVKK=F=ZboPMvZ4na~B2e}FIKbsZl5kZr`5vrJO<`)KkbVD!& zSX73+-rT1dOo-%m!G!c}^5t*OY@`Y&#o4EfH=6HlTn3z?YNiIJAeG(x3Y{VeoVIua zSTsA^pq&8%>u7IrC=9;c80_0g?Cc{K@IiihQ;W^kXGx3Mt}oN=z&{D^u8eqj|7m|s z25Dp<8TmG4`7SwqyQ{3M99%jSd2|%$S8wvXsuMB0=dx(F=lvsB$@bA$!}e=l9u%`AMz9RF zVMtwU9_nqrtLy&wyO_rZ)QFE^VN8D2PhYr19+Q|X%|F;b&A?j`#Lt;L;9Tyu9A~?f zANFcaKWGktJKUQr=g7pb`R2I7-$S$xx zbJe;6rlJ2VE@oHtxn@w>^*z^;Fr>~A7k6jGaZ{hPMtzpQiGRutg%U=?B6PB@Xqlwc zQsbtE@|d^(O1U}-2)qOwq6>v&qQpasrbt(~*df&J^mF0ALH|aaAD??lTH8H~Mx(Pe z!^}M^kHjcnmWavweYaN76_d4;J8AOjI6)noumdhe|kUAp}y`asWkzs>02 zMfM&q7cRRt+T(ty&ZEYB?o7bflK5{ZPUIaR=)TjZjW?76eR@_e^<3FPL@|w;UkI{j z3@e2^dOnMjwj>6bUy+}BXZA1QnxAQ7_V85vT{ro#HrtNnJbrRlo?pRTnK;GjW zT(e%g!r4pDh+@7pb&l4 z=k-k_=oauo;|!~&K^ky9AA@?U@jRo24a-d|K9`BkWND@ z3z34~#41~LsOGazz30Nzaa=8#s&SN*^*G%#$xLg0eZ9?y^5W+a$Y?F}WwTHdlz9ZL zyuYRN<+5yN$N$uf-#lz{r0rE2O(-fR8(F4@syj0^0n2vMd$eLno*E7Vp4rW~ zrx+A#AeeXOQp+kAnW!g+30#B3^i4A|`PA&nSL3}d#goohm}APOT_ABOKslOq;{wh~7JCr&MEKElypAFq z?}&$0z5Sfu>|-GdTdD=Me?LlZpcz+`Webaf>Idu$3_?7V7(rG3o#yYLyGze&5iQ|5 zvqh}={^5=wxgh*xrn(@E04oagg;r1nm8U+Ow0|sR;WbXI5DC{Inp8;y9_OKdy=@GN zw!Nc6-PYFD^m|ASXO4O89q|UM9l=COdB25Arb#s3?=4*F6N(dsQBIzk(a-;~q5AT* z7OP(QD2yR8p4g|F@e1}I&D1w$=PV_nlBAv&$Oi#UETVN)gzXgiXuUby4p?|<&5-2; z9I17NWq||7YS4+cuQb~h#S z&&uwjVq7Y|;d`-awtGy2QvLYiy^+kjgBcR_rNYoBz|^1raYHyAq!;sL2H9oBkF^ZmmRyV{`&cW9388Mbx;zdOooeC@HBR(7-A2G?T8+9X zRd>}WWjFKQGcC0kB-8@R*M%lD5970Qx@n)WCl!7^Ty<~%u?(A&55#b$uZU{BdY!(7 zKwY}PAs!S-`Wi-9;GXp9G}nrwty_fo0^%v;>G_xEGZuybEc%A-^tyjNSk{oqwNfrG zCyTqhCuhza7as}-j~=Ctg<*1|-s16h8^64kXb;z^h3vA#gCB7am1)a>k@LRaM>X%Q zLgV~ci9dWld|)R2+11m?Fm;6{VSqo6&Xqf~N$Ura{b${EcNmg6h&As^O(Z9aVzzF-C_JY?dna3&19JNoh8e%f5N&nn%oYGm6=o>DgQJ3AR(kad6TBaYBwnmi?`q@@fs;=dlruSC5^({To79Z%` zgJZz%C+^RsCI||+8CwXh zjnsRvy?R^szwCNfe&mAw8^r_gtG1<=T|ZLAy)HhiwjXVHIBZhE@I}Yh;rKOK$=aXi zd5rLN6i0hePLDd$?7(!{v#h}yC%wcmpgulRd(SxcRLX$+GcG2}%)8BrN}wx_!d$

2$^6wqBO=M!NWXIBGy9FsS5u@P2qi<` z6PD^U=p$;3l+d@ecol)Ay84A9t!Z1n=1cfv8t{mxhYVZU@y^fMp6EVny0mG^q#pqGZi!O;Tw2r2`) zsB6DlqYr}tFnfb10_|wH>C1(V+;rYQWNHi^FxdxP%b7qh#1EdLOhUl%uXM8OrR~f{ z8q#F7`($GExUbb(Q&ZCwpe5(#n&!7QMp6Nn`~GXd1H_;*#VH`kKvG?++iE^(tbs~N zDy^PDC^nDP_Y{=HD7TdUIyeOSLjA;X|LR3ohR47C=UfA4yoJ9QXl57WldB_Bzg;;t zW{swSgQIObp3bl!;qPRKN1iR9fbCdT+?{K-wEC!C zt#$_Ih_Fm4L34jd>BKTIL69N_qfgnzr%T_P=UP7x!HrQ<^;_Rn^;Rc|IPU*g*Y^W0 zhVH!pPd*|ENHEhL!YJp|%GarMN3W^U0nIx$=j7oKz6{nNn!DV;HORF=6H4P7wAc=hO1r<+~>W=HE!g?cLGS(?bQK%$&M_FP8YY322 zwIWjv*N#iX7Fe5?Sl$)|Tq5^W>|JAQ=_yz;J6jyg47rG%gdcc8)V&t!YA$`xv!S6?)k|cGCW-_~LBZt8 z@?|56IyGyV#I)<|GWuN+co1C(!ZuPTyHXG5Fs6jyC$DbI%i=?MY5ib(eDe2Vag#y2 z>El4Pa;XvY3dL7;4}t$;wc5$(HQm%w^CIg7*oG#n2)u`qREbr!+x!W0)A5)>o;|18 zZFuAh;b(tePTJtSBRFk$))Q>TDF|huh`Dh7!7COl3`V4)1+r@okjgdSGW=rZlh4zs z_up|@w15f80}Ig2=A|#3!||M1P(=~s{suslGK_RMNVnbiD0a+xZTcez(Z>6j?%|FX z8Nn(1PEeX|t&J+&Nnt&c@o7&3FL$a;Uyq^T{u?Eb( z4IISxoB{so1m)kTd+AuUyWQLG5<`->LJUz~Aje&IG1Ao(V9)yg*`RnJyHgbi(KImkiR1TL4))mLT%Zkn2gqj_&u# z-NBTyaKjkq)sJ};KQM6DlYzq#5WgaRmP-}^OLQek1fYc2r!IelEh!?^*KI%`DR{86 zJk)RkNxb-bwa^VtoV0tW%H}z3$o|wYLSM`=b2p*qzLr);IoQK)X;+?Xs%XU-^QkqJ z9b99U!fgdy!uA@Gom$*=b_wk#fekwcGz`H)U`X=;WOq(@u{rEZqdg)}C3Bi;YQw*N zLb9~3;@a9o{iq@Uwq9lMvLe;H&H=j}czv!(v>O!CS1y2OV@#w_$cHgfmX-JVK(1@> zhNDKNS-TXPm_E?MC*?{QsC=%uONdnu7J$H+*ZFw?F(uyQ%Lkogx{^Uld5 z;>ZOoHJ?+`Q;6iXl%G2&3<5M@0Y()IfQ-Cr`~6baO zX;}!;FoL1CIK+Zn^FEs~weX@20pf*mbwS=uGG_+cWEyKtWXz8K zH^J1XObO${pG`sxcOTMF7saC`6){ARCg+XvgJ_Gbs-! za{Kp=|1|j7@B;_gh9RT}EIJA!Y&kSRg85om#{DOj00CA3CF|ur%Y&<_Aitgnz9}(< zqj+M*X@Ae+e$ccMiln<}HL&cQ@R!QZQkVt;Q5iU0fQHGRM|)hDM!-A-;^J9PCgCYK zIH?Z=LbWI2J@Vmp>dB^-kroqc2U{+~Z};ucayW|iS1$rd4r+%XlDx&e6Ftp1>r_B- z-q=fJwwEu!kQ+gj<8M$oBz^*q`%*T$WS(QAk}p4Qbub{GD(gE~i6;W?!z1jXSIhqv zW`Kj1mXYcq_a#!q=`yR<*RD|c2195tfgDVnU-{VM1~|*})F+J`Y(SJ=ea15SP>LyR(XXWIcW&G(fI3&b?nuHOp1POHB~V#B>(Wil(f2(d5j zpD|3xJ|H^6;aNnI`CDHLAklQ_<6gMX*qNEqFvQoVIJ zD*i+@r^jAcB=z@91o0Uia7Be_7tm&nc-mz@nCdeUy@;P+pj!*=S1+byyLSOBt&c*( zAnE&l4J7@8gL!)93&B5{4j$X@w;ftXIZRva?^p~Re4d#HPsjwpW#!oL<;+%tPZaI7h`=y)yS|x?E@V@+pbmJiM-JGB zN$gKKQMJ3K(JzXgCBS#h1J|DZi)n-WNX))}Ite--)S)haE_N)mG6s{nE8S`_@x4j! z>CAit0Rc&$XO)C_Y>>WKlDODSjmFVI+A{qkDKqE+1koU^;D1I2w|is$p2+7BG}*BMN?t15@9$(xo!lIjoxl7h--XA{6^gA}1H)mru z=i|C}JumL>SpPWr2m|5PrEPvtTDPA8?B?&QVzavvfN2NnaXqtMlJtPVIk`TW^8a^n zGKv5DOZdt9oxBC?IWzQs7bgS#-(RGy!G=9~>*Svy(*IqY-0%PYg`#1b#|Q|Ka7i)n S=+hPiURs*E8YNe;q5mKL{w44L diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml deleted file mode 100644 index 9b8160989..000000000 --- a/snap/snapcraft.yaml +++ /dev/null @@ -1,78 +0,0 @@ -name: olive-editor -base: core18 # the base snap is the execution environment for this snap -adopt-info: olive -summary: Professional open-source NLE video editor -description: | - Olive is a non-linear video editor for Windows, macOS, and Linux. - -grade: stable -confinement: strict - -apps: - olive-editor: - environment: - "LD_LIBRARY_PATH": "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pulseaudio" - "DISABLE_WAYLAND": "1" - command: desktop-launch $SNAP/bin/olive-editor - plugs: - - opengl - - desktop - - desktop-legacy - - x11 - - network - - pulseaudio - - home - - removable-media - - unity7 - -parts: - olive: - plugin: qmake - source: . - build-packages: - - qt5-default - - qtmultimedia5-dev - - libqt5svg5-dev - - libavformat-dev - - libavfilter-dev - - frei0r-plugins-dev - stage-packages: - - ffmpeg - - libqt5multimedia5 - - libqt5multimedia5-plugins - - libpulse0 - - libslang2 - - libglu1-mesa - - frei0r-plugins - override-build: | - qmake PREFIX=$SNAPCRAFT_PART_INSTALL - make - make install - snapcraftctl set-version $(git rev-parse --short HEAD) - desktop-qt5: - build-packages: - - build-essential - - qtbase5-dev - - dpkg-dev - make-parameters: - - FLAVOR=qt5 - plugin: make - source: https://github.com/ubuntu/snapcraft-desktop-helpers.git - source-subdir: qt - stage-packages: - - libxkbcommon0 - - ttf-ubuntu-font-family - - dmz-cursor-theme - - light-themes - - adwaita-icon-theme - - gnome-themes-standard - - shared-mime-info - - libqt5gui5 - - libgdk-pixbuf2.0-0 - - libqt5svg5 - - try: - - appmenu-qt5 - - locales-all - - xdg-user-dirs - - fcitx-frontend-qt5 - diff --git a/thirdparty/vestige/include/vestige.h b/thirdparty/vestige/include/vestige.h deleted file mode 100755 index 41e78f7a0..000000000 --- a/thirdparty/vestige/include/vestige.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * vestige.h - simple header to allow VeSTige compilation and eventually work - * - * Copyright (c) 2006 Javier Serrano Polo - * - * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net - * - * 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 2 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 (see COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * This VeSTige header is included in this package in the good-faith - * belief that it has been cleanly and legally reverse engineered - * without reference to the official VST SDK and without its - * developer(s) having agreed to the VST SDK license agreement. - */ - -#include -#ifndef _VESTIGE_H -#define _VESTIGE_H - -#define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ - ( ( (int) b ) << 16 ) | \ - ( ( (int) c ) << 8 ) | \ - ( ( (int) d ) << 0 ) ) - -#define audioMasterAutomate 0 -#define audioMasterVersion 1 -#define audioMasterCurrentId 2 -#define audioMasterIdle 3 -#define audioMasterPinConnected 4 -// unsupported? 5 -#define audioMasterWantMidi 6 -#define audioMasterGetTime 7 -#define audioMasterProcessEvents 8 -#define audioMasterSetTime 9 -#define audioMasterTempoAt 10 -#define audioMasterGetNumAutomatableParameters 11 -#define audioMasterGetParameterQuantization 12 -#define audioMasterIOChanged 13 -#define audioMasterNeedIdle 14 -#define audioMasterSizeWindow 15 -#define audioMasterGetSampleRate 16 -#define audioMasterGetBlockSize 17 -#define audioMasterGetInputLatency 18 -#define audioMasterGetOutputLatency 19 -#define audioMasterGetPreviousPlug 20 -#define audioMasterGetNextPlug 21 -#define audioMasterWillReplaceOrAccumulate 22 -#define audioMasterGetCurrentProcessLevel 23 -#define audioMasterGetAutomationState 24 -#define audioMasterOfflineStart 25 -#define audioMasterOfflineRead 26 -#define audioMasterOfflineWrite 27 -#define audioMasterOfflineGetCurrentPass 28 -#define audioMasterOfflineGetCurrentMetaPass 29 -#define audioMasterSetOutputSampleRate 30 -// unsupported? 31 -#define audioMasterGetSpeakerArrangement 31 // deprecated in 2.4? -#define audioMasterGetVendorString 32 -#define audioMasterGetProductString 33 -#define audioMasterGetVendorVersion 34 -#define audioMasterVendorSpecific 35 -#define audioMasterSetIcon 36 -#define audioMasterCanDo 37 -#define audioMasterGetLanguage 38 -#define audioMasterOpenWindow 39 -#define audioMasterCloseWindow 40 -#define audioMasterGetDirectory 41 -#define audioMasterUpdateDisplay 42 -#define audioMasterBeginEdit 43 //BeginGesture -#define audioMasterEndEdit 44 //EndGesture -#define audioMasterOpenFileSelector 45 -#define audioMasterCloseFileSelector 46 // currently unused -#define audioMasterEditFile 47 // currently unused -#define audioMasterGetChunkFile 48 // currently unused -#define audioMasterGetInputSpeakerArrangement 49 // currently unused - -#define effFlagsHasEditor 1 -#define effFlagsCanReplacing (1 << 4) // very likely -#define effFlagsIsSynth (1 << 8) // currently unused - -#define effOpen 0 -#define effClose 1 // currently unused -#define effSetProgram 2 // currently unused -#define effGetProgram 3 // currently unused -#define effGetProgramName 5 // currently unused -#define effGetParamName 8 // currently unused -#define effSetSampleRate 10 -#define effSetBlockSize 11 -#define effMainsChanged 12 -#define effEditGetRect 13 -#define effEditOpen 14 -#define effEditClose 15 -#define effEditIdle 19 -#define effEditTop 20 -#define effProcessEvents 25 -// the next one from http://asseca.com/vst-24-specs/index.html -#define effGetPlugCategory 35 -#define effGetEffectName 45 -#define effGetVendorString 47 -#define effGetProductString 48 -#define effGetVendorVersion 49 -#define effCanDo 51 // currently unused -/* from http://asseca.com/vst-24-specs/efIdle.html */ -#define effIdle 53 -/* from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ -#define effGetParameterProperties 56 -#define effGetVstVersion 58 // currently unused -/* http://asseca.com/vst-24-specs/efShellGetNextPlugin.html */ -#define effShellGetNextPlugin 70 -/* The next two were gleaned from http://www.kvraudio.com/forum/printview.php?t=143587&start=0 */ -#define effStartProcess 71 -#define effStopProcess 72 - -#define effBeginSetProgram 67 -#define effEndSetProgram 68 - -#ifdef WORDS_BIGENDIAN -// "VstP" -#define kEffectMagic 0x50747356 -#else -// "PtsV" -#define kEffectMagic 0x56737450 -#endif - -#define kVstLangEnglish 1 -#define kVstMidiType 1 - -struct RemoteVstPlugin; - -#define kVstTransportChanged 1 -#define kVstTransportPlaying (1 << 1) -#define kVstTransportCycleActive (1 << 2) -#define kVstTransportRecording (1 << 3) - -#define kVstAutomationWriting (1 << 6) -#define kVstAutomationReading (1 << 7) - -#define kVstNanosValid (1 << 8) -#define kVstPpqPosValid (1 << 9) -#define kVstTempoValid (1 << 10) -#define kVstBarsValid (1 << 11) -#define kVstCyclePosValid (1 << 12) -#define kVstTimeSigValid (1 << 13) -#define kVstSmpteValid (1 << 14) -#define kVstClockValid (1 << 15) - -struct _VstMidiEvent -{ - // 00 - int type; - // 04 - int byteSize; - // 08 - int deltaSamples; - // 0c? - int flags; - // 10? - int noteLength; - // 14? - int noteOffset; - // 18 - char midiData[4]; - // 1c? - char detune; - // 1d? - char noteOffVelocity; - // 1e? - char reserved1; - // 1f? - char reserved2; -}; - -typedef struct _VstMidiEvent VstMidiEvent; - - -struct _VstEvent -{ - char dump[sizeof (VstMidiEvent)]; - -}; - -typedef struct _VstEvent VstEvent; - -struct _VstEvents -{ - // 00 - int numEvents; - // 04 - void *reserved; - // 08 - VstEvent * events[]; -}; - -/* constants from http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=3740&sid=183f74631fee71a493316735e2b9f28b */ - -enum Vestige2StringConstants -{ - VestigeMaxNameLen = 64, - VestigeMaxLabelLen = 128, - VestigeMaxShortLabelLen = 8, - VestigeMaxCategLabelLen = 24, - VestigeMaxFileNameLen = 100 -}; - - -/* constants from http://asseca.com/vst-24-specs/efGetPlugCategory.html */ - -enum VstPlugCategory -{ - kPlugCategUnknown = 0, - kPlugCategEffect, - kPlugCategSynth, - kPlugCategAnalysis, - kPlugCategMastering, - kPlugCategSpacializer, - kPlugCategRoomFx, - kPlugSurroundFx, - kPlugCategRestoration, - kPlugCategOfflineProcess, - kPlugCategShell, - kPlugCategGenerator, - kPlugCategMaxCount -}; - -typedef struct _VstEvents VstEvents; - -/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ -struct _VstParameterProperties -{ - float stepFloat; /* float step */ - float smallStepFloat; /* small float step */ - float largeStepFloat; /* large float step */ - char label[64]; /* parameter label */ - int32_t flags; /* @see VstParameterFlags */ - int32_t minInteger; /* integer minimum */ - int32_t maxInteger; /* integer maximum */ - int32_t stepInteger; /* integer step */ - int32_t largeStepInteger; /* large integer step */ - char shortLabel[VestigeMaxShortLabelLen]; /* short label, recommended: 6 + delimiter */ - int16_t displayIndex; /* index where this parameter should be displayed (starting with 0) */ - int16_t category; /* 0: no category, else group index + 1 */ - int16_t numParametersInCategory; /* number of parameters in category */ - int16_t reserved; /* zero */ - char categoryLabel[VestigeMaxCategLabelLen]; /* category label, e.g. "Osc 1" */ - char future[16]; /* reserved for future use */ -}; - -typedef struct _VstParameterProperties VstParameterProperties; - -/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ -enum VstParameterFlags -{ - kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */ - kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */ - kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */ - kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */ - kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */ - kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */ - kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */ -}; - -struct _AEffect -{ - // Never use virtual functions!!! - // 00-03 - int magic; - // dispatcher 04-07 - intptr_t (* dispatcher) (struct _AEffect *, int, int, intptr_t, void *, float); - // process, quite sure 08-0b - void (* process) (struct _AEffect *, float **, float **, int); - // setParameter 0c-0f - void (* setParameter) (struct _AEffect *, int, float); - // getParameter 10-13 - float (* getParameter) (struct _AEffect *, int); - // programs 14-17 - int numPrograms; - // Params 18-1b - int numParams; - // Input 1c-1f - int numInputs; - // Output 20-23 - int numOutputs; - // flags 24-27 - int flags; - // Fill somewhere 28-2b - void *ptr1; - void *ptr2; - // Zeroes 2c-2f 30-33 34-37 38-3b - char empty3[4 + 4 + 4]; - // 1.0f 3c-3f - float unkown_float; - // An object? pointer 40-43 - void *ptr3; - // Zeroes 44-47 - void *user; - // Id 48-4b - int32_t uniqueID; - // Version 4c-4f - int32_t version; - // processReplacing 50-53 - void (* processReplacing) (struct _AEffect *, float **, float **, int); -}; - -typedef struct _AEffect AEffect; - -typedef struct _VstTimeInfo -{ - /* info from online documentation of VST provided by Steinberg */ - - double samplePos; - double sampleRate; - double nanoSeconds; - double ppqPos; - double tempo; - double barStartPos; - double cycleStartPos; - double cycleEndPos; - int32_t timeSigNumerator; - int32_t timeSigDenominator; - int32_t smpteOffset; - int32_t smpteFrameRate; - int32_t samplesToNextClock; - int32_t flags; - -} VstTimeInfo; - -typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); - -#endif diff --git a/timeline/clip.cpp b/timeline/clip.cpp deleted file mode 100644 index d044e107a..000000000 --- a/timeline/clip.cpp +++ /dev/null @@ -1,720 +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 "clip.h" - -#include - -#include "nodes/oldeffectnode.h" -#include "effects/transition.h" -#include "project/footage.h" -#include "global/config.h" -#include "rendering/cacher.h" -#include "rendering/renderfunctions.h" -#include "panels/project.h" -#include "timeline/sequence.h" -#include "panels/timeline.h" -#include "project/media.h" -#include "undo/undo.h" -#include "global/clipboard.h" -#include "global/debug.h" -#include "global/timing.h" - -Clip::Clip(Track *s) : - track_(s), - cacher(this), - enabled_(true), - clip_in_(0), - timeline_in_(0), - timeline_out_(0), - media_(nullptr), - reverse_(false), - autoscale_(olive::config.autoscale_by_default), - opening_transition(nullptr), - closing_transition(nullptr), - undeletable(false), - replaced(false), - open_(false), - texture(0) -{ -} - -ClipPtr Clip::copy(Track* s) { - ClipPtr copy = std::make_shared(s); - - copy->set_enabled(enabled()); - copy->set_name(name()); - copy->set_clip_in(clip_in()); - copy->set_timeline_in(timeline_in()); - copy->set_timeline_out(timeline_out()); - copy->set_color(color()); - copy->set_media(media(), media_stream_index()); - copy->set_autoscaled(autoscaled()); - copy->set_speed(speed()); - copy->set_reversed(reversed()); - - for (int i=0;ieffects.append(effects.at(i)->copy(copy.get())); - } - - copy->set_cached_frame_rate((this->track_ == nullptr) ? cached_frame_rate() : this->track_->sequence()->frame_rate()); - - copy->refresh(); - - return copy; -} - -bool Clip::IsActiveAt(long timecode) -{ - return enabled() - && timeline_in(true) <= timecode - && timeline_out(true) > timecode - && timecode - timeline_in(true) + clip_in(true) < media_length() - && !track()->IsEffectivelyMuted(); -} - -bool Clip::IsSelected(bool containing) -{ - if (this->track_ == nullptr) { - return false; - } - - return this->track_->IsClipSelected(this, containing); -} - -bool Clip::IsTransitionSelected(TransitionType type) -{ - switch (type) { - case kTransitionOpening: - return track_->IsTransitionSelected(opening_transition.get()); - case kTransitionClosing: - return track_->IsTransitionSelected(closing_transition.get()); - default: - return false; - } -} - -Selection Clip::ToSelection() -{ - return Selection(timeline_in(), timeline_out(), track()); -} - -olive::TrackType Clip::type() -{ - return track()->type(); -} - -const QColor &Clip::color() -{ - return color_; -} - -void Clip::set_color(int r, int g, int b) -{ - color_.setRed(r); - color_.setGreen(g); - color_.setBlue(b); -} - -void Clip::set_color(const QColor &c) -{ - color_ = c; -} - -Media *Clip::media() -{ - return media_; -} - -FootageStream *Clip::media_stream() -{ - if (media() != nullptr - && media()->get_type() == MEDIA_TYPE_FOOTAGE) { - return media()->to_footage()->get_stream_from_file_index(type() == olive::kTypeVideo, media_stream_index()); - } - - return nullptr; -} - -int Clip::media_stream_index() -{ - return media_stream_; -} - -void Clip::set_media(Media *m, int s) -{ - media_ = m; - media_stream_ = s; -} - -void Clip::Move(ComboAction *ca, long iin, long iout, long iclip_in, Track *itrack, bool verify_transitions, bool relative) -{ - track()->sequence()->MoveClip(this, ca, iin, iout, iclip_in, itrack, verify_transitions, relative); -} - -bool Clip::enabled() -{ - return enabled_; -} - -void Clip::set_enabled(bool e) -{ - enabled_ = e; -} - -void Clip::reset_audio() { - if (UsesCacher()) { - cacher.ResetAudio(); - } - if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) { - - QVector nested_sequence_clips = media()->to_sequence()->GetAllClips(); - - for (int i=0;ireset_audio(); - } - - } -} - -void Clip::refresh() { - // validates media if it was replaced - if (replaced && media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* m = media()->to_footage(); - - if (type() == olive::kTypeVideo && m->video_tracks.size() > 0) { - set_media(media(), m->video_tracks.at(0).file_index); - } else if (type() == olive::kTypeAudio && m->audio_tracks.size() > 0) { - set_media(media(), m->audio_tracks.at(0).file_index); - } - } - replaced = false; - - // reinitializes all effects... just in case - for (int i=0;irefresh(); - } -} - -QVector &Clip::get_markers() { - if (media() != nullptr) { - return media()->get_markers(); - } - return markers; -} - -int Clip::IndexOfEffect(OldEffectNode *e) -{ - for (int i=0;iget_type())); - switch (media()->get_type()) { - case MEDIA_TYPE_FOOTAGE: - stream.writeAttribute("media", QString::number(media()->to_footage()->save_id)); - stream.writeAttribute("stream", QString::number(media_stream_index())); - break; - case MEDIA_TYPE_SEQUENCE: - stream.writeAttribute("sequence", QString::number(media()->to_sequence()->save_id)); - break; - } - } - - // save markers - // only necessary for null media clips, since media has its own markers - if (media() == nullptr) { - for (int k=0;kload_id)); - stream.writeEndElement(); // link - } - stream.writeEndElement(); // linked - - // save opening and closing transitions - for (int t=kTransitionOpening;t<=kTransitionClosing;t++) { - TransitionPtr transition = (t == kTransitionOpening) ? opening_transition : closing_transition; - - if (transition != nullptr) { - stream.writeStartElement((t == kTransitionOpening) ? "opening" : "closing"); - - // check if this is a shared transition - if (this == transition->secondary_clip) { - // if so, just save a reference to the other clip - stream.writeAttribute("shared", - QString::number(transition->parent_clip->load_id)); - } else { - // otherwise save the whole transition - transition->save(stream); - } - - stream.writeEndElement(); // opening/closing - } - } - - for (int k=0;ksave(stream); - stream.writeEndElement(); // effect - } - - stream.writeEndElement(); // clip -} - -long Clip::clip_in(bool with_transition) { - if (with_transition && opening_transition != nullptr && opening_transition->secondary_clip != nullptr) { - // we must be the secondary clip, so return (clip in - length) - return clip_in_ - opening_transition->get_true_length(); - } - return clip_in_; -} - -void Clip::set_clip_in(long c) -{ - clip_in_ = c; -} - -long Clip::timeline_in(bool with_transition) { - if (with_transition && opening_transition != nullptr && opening_transition->secondary_clip != nullptr) { - // we must be the secondary clip, so return (timeline in - length) - return timeline_in_ - opening_transition->get_true_length(); - } - return timeline_in_; -} - -void Clip::set_timeline_in(long t) -{ - timeline_in_ = t; -} - -long Clip::timeline_out(bool with_transitions) { - if (with_transitions && closing_transition != nullptr && closing_transition->secondary_clip != nullptr) { - // we must be the primary clip, so return (timeline out + length) - return timeline_out_ + closing_transition->get_true_length(); - } else { - return timeline_out_; - } -} - -void Clip::set_timeline_out(long t) -{ - timeline_out_ = t; -} - -bool Clip::reversed() -{ - return reverse_; -} - -void Clip::set_reversed(bool r) -{ - reverse_ = r; -} - -bool Clip::autoscaled() -{ - return autoscale_; -} - -void Clip::set_autoscaled(bool b) -{ - autoscale_ = b; -} - -double Clip::cached_frame_rate() -{ - return cached_fr_; -} - -void Clip::set_cached_frame_rate(double d) -{ - cached_fr_ = d; -} - -const QString &Clip::name() -{ - return name_; -} - -void Clip::set_name(const QString &s) -{ - name_ = s; -} - -const ClipSpeed& Clip::speed() -{ - return speed_; -} - -void Clip::set_speed(const ClipSpeed& d) -{ - speed_ = d; -} - -AVRational Clip::time_base() -{ - return cacher.media_time_base(); -} - -Track *Clip::track() -{ - return track_; -} - -void Clip::set_track(Track *t) -{ - track_ = t; -} - -// timeline functions -long Clip::length() { - return timeline_out_ - timeline_in_; -} - -double Clip::media_frame_rate() { - Q_ASSERT(type() == olive::kTypeVideo); - if (media_ != nullptr) { - double rate = media_->get_frame_rate(media_stream_index()); - if (!qIsNaN(rate)) return rate; - } - if (track() != nullptr) return track()->sequence()->frame_rate(); - return qSNaN(); -} - -long Clip::media_length() { - if (this->track() != nullptr) { - double fr = this->track()->sequence()->frame_rate(); - - fr /= speed_.value; - - if (media_ == nullptr) { - return LONG_MAX; - } else { - switch (media_->get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - Footage* m = media_->to_footage(); - const FootageStream* ms = m->get_stream_from_file_index(type() == olive::kTypeVideo, media_stream_index()); - if (ms != nullptr && ms->infinite_length) { - return LONG_MAX; - } else { - return m->get_length_in_frames(fr); - } - } - case MEDIA_TYPE_SEQUENCE: - { - Sequence* s = media_->to_sequence().get(); - return rescale_frame_number(s->GetEndFrame(), s->frame_rate(), fr); - } - } - } - } - return 0; -} - -int Clip::media_width() { - if (media_ == nullptr && track() != nullptr) return track()->sequence()->width(); - switch (media_->get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - const FootageStream* ms = media_stream(); - if (ms != nullptr) return ms->video_width; - if (track() != nullptr) return track()->sequence()->width(); - break; - } - case MEDIA_TYPE_SEQUENCE: - { - Sequence* s = media_->to_sequence().get(); - return s->width(); - } - } - return 0; -} - -int Clip::media_height() { - if (media_ == nullptr && track() != nullptr) return track()->sequence()->height(); - switch (media_->get_type()) { - case MEDIA_TYPE_FOOTAGE: - { - const FootageStream* ms = media_stream(); - if (ms != nullptr) return ms->video_height; - if (track() != nullptr) return track()->sequence()->height(); - } - break; - case MEDIA_TYPE_SEQUENCE: - { - Sequence* s = media_->to_sequence().get(); - return s->height(); - } - } - return 0; -} - -void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) { - if (change_timeline_points) { - track()->sequence()->MoveClip(this, - ca, - qRound(double(timeline_in_) * multiplier), - qRound(double(timeline_out_) * multiplier), - qRound(double(clip_in_) * multiplier), - track_); - } - - // move keyframes - for (int i=0;iParameterCount();j++) { - NodeIO* r = e->Parameter(j); - for (int l=0;lFieldCount();l++) { - EffectField* f = r->Field(l); - for (int k=0;kkeyframes.size();k++) { - ca->append(new SetDouble(&f->keyframes[k].time, f->keyframes[k].time, qRound(f->keyframes[k].time * multiplier))); - } - } - } - } -} - -void Clip::Open() { - if (!open_ && state_change_lock.tryLock()) { - open_ = true; - - for (int i=0;iopen(); - } - - // reset variable used to optimize uploading frame data - texture_timestamp = -1; - - if (UsesCacher()) { - // cacher will unlock open_lock - cacher.Open(); - } else { - // this media doesn't use a cacher, so we unlock here - state_change_lock.unlock(); - } - } -} - -void Clip::Close(bool wait) { - // thread safety, prevents Close() running from two separate threads simultaneously - if (open_ && state_change_lock.tryLock()) { - open_ = false; - - if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) { - media()->to_sequence()->Close(); - } - - // destroy opengl texture in main thread - if (texture > 0) { - QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &texture); - texture = 0; - } - - // close all effects - for (int i=0;iis_open()) { - effects.at(i)->close(); - } - } - - // delete framebuffers - fbo.clear(); - - // delete OCIO shader - ocio_shader = nullptr; - - if (UsesCacher()) { - cacher.Close(wait); - } else { - state_change_lock.unlock(); - } - } -} - -bool Clip::IsOpen() -{ - return open_; -} - -void Clip::Cache(long playhead, bool scrubbing, QVector& nests, int playback_speed) { - cacher.Cache(playhead, scrubbing, nests, playback_speed); - cacher_frame = playhead; -} - -bool Clip::Retrieve() -{ - bool ret = false; - - if (UsesCacher()) { - - // Retrieve the frame from the cacher that we requested in Cache(). - AVFrame* frame = cacher.Retrieve(); - - // Wait for exclusive control of the queue to avoid any threading collisions - cacher.queue()->lock(); - - // Check if we retrieved a frame (nullptr) and if the queue still contains this frame. - // - // `nullptr` is returned if the cacher failed to get any sort of frame and is uncommon, but we do need - // to handle it. - // - // We check the queue because in some situations (e.g. intensive scrubbing), in the time it took to gain - // exclusive control of the queue, the cacher may have deleted the frame. - // Therefore we check to ensure the queue still contains the frame now that we have exclusive control, - // to avoid any attempt to utilize now-freed memory. - - if (frame != nullptr && cacher.queue()->contains(frame)) { - - //if (frame->pts != texture_timestamp) { - - bool allocate_data = false; - - QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); - - // check if the opengl texture exists yet, create it if not - if (texture == 0) { - - // create texture object - f->glGenTextures(1, &texture); - - f->glBindTexture(GL_TEXTURE_2D, texture); - - // set texture filtering to bilinear - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // set texture wrapping to clamp - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // queue an allocation ahead - allocate_data = true; - - } else { - - f->glBindTexture(GL_TEXTURE_2D, texture); - - } - - int video_width = cacher.media_width(); - int video_height = cacher.media_height(); - - const olive::PixelFormatInfo& pix_fmt_info = olive::pixel_formats.at(cacher.media_pixel_format()); - - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, frame->linesize[0]/pix_fmt_info.bytes_per_pixel); - - if (allocate_data) { - - // the raw frame size may differ from the one we're using (e.g. a lower resolution proxy), so we make sure - // the texture is using the correct dimensions, but then treat it as if it's the original resolution in the - // composition - f->glTexImage2D( - GL_TEXTURE_2D, - 0, - pix_fmt_info.internal_format, - video_width, - video_height, - 0, - pix_fmt_info.pixel_format, - pix_fmt_info.pixel_type, - frame->data[0] - ); - - } else { - - f->glTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - video_width, - video_height, - pix_fmt_info.pixel_format, - pix_fmt_info.pixel_type, - frame->data[0] - ); - - } - - f->glBindTexture(GL_TEXTURE_2D, 0); - - f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - texture_timestamp = frame->pts; - - ret = true; - } else { - qCritical() << "Failed to retrieve frame for clip" << name(); - } - - cacher.queue()->unlock(); - } - - return ret; -} - -bool Clip::UsesCacher() -{ - return type() == olive::kTypeAudio || (media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE); -} - -ClipSpeed::ClipSpeed() : - value(1.0), - maintain_audio_pitch(false) -{ -} diff --git a/timeline/clip.h b/timeline/clip.h deleted file mode 100644 index e4057d376..000000000 --- a/timeline/clip.h +++ /dev/null @@ -1,191 +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 CLIP_H -#define CLIP_H - -#include -#include -#include -#include -#include -#include - -#include "rendering/cacher.h" - -#include "nodes/oldeffectnode.h" -#include "effects/transition.h" -#include "undo/comboaction.h" -#include "project/media.h" -#include "project/footage.h" -#include "rendering/framebufferobject.h" -#include "marker.h" -#include "nodes/nodegraph.h" -#include "selection.h" - -class Track; - -struct ClipSpeed { - ClipSpeed(); - double value; - bool maintain_audio_pitch; -}; - -class Clip { -public: - Clip(Track *s); - ~Clip(); - ClipPtr copy(Track *s); - - void Save(QXmlStreamWriter& stream); - - bool IsActiveAt(long timecode); - bool IsSelected(bool containing = true); - bool IsTransitionSelected(TransitionType type); - - Selection ToSelection(); - - olive::TrackType type(); - - const QColor& color(); - void set_color(int r, int g, int b); - void set_color(const QColor& c); - - Media* media(); - FootageStream* media_stream(); - int media_stream_index(); - int media_width(); - int media_height(); - double media_frame_rate(); - long media_length(); - void set_media(Media* m, int s); - - void Move(ComboAction* ca, - long iin, - long iout, - long iclip_in, - Track *itrack, - bool verify_transitions = true, - bool relative = false); - - bool enabled(); - void set_enabled(bool e); - - long clip_in(bool with_transition = false); - void set_clip_in(long c); - - long timeline_in(bool with_transition = false); - void set_timeline_in(long t); - - long timeline_out(bool with_transition = false); - void set_timeline_out(long t); - - Track* track(); - void set_track(Track* t); - - bool reversed(); - void set_reversed(bool r); - - bool autoscaled(); - void set_autoscaled(bool b); - - double cached_frame_rate(); - void set_cached_frame_rate(double d); - - const QString& name(); - void set_name(const QString& s); - - const ClipSpeed& speed(); - void set_speed(const ClipSpeed& s); - - AVRational time_base(); - - void reset_audio(); - void refresh(); - - long length(); - - void refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points); - Track* parent_; - - // markers - QVector& get_markers(); - - // other variables (should be deep copied/duplicated in copy()) - int IndexOfEffect(OldEffectNode* e); - QList effects; - QVector linked; - TransitionPtr opening_transition; - TransitionPtr closing_transition; - - // playback functions - void Open(); - void Cache(long playhead, bool scrubbing, QVector &nests, int playback_speed); - bool Retrieve(); - void Close(bool wait); - bool IsOpen(); - - bool UsesCacher(); - - // temporary variables - int load_id; - bool undeletable; - bool replaced; - - // caching functions - QMutex state_change_lock; - QMutex cache_lock; - - // video playback variables - QVector fbo; - GLuint texture; - int64_t texture_timestamp; - -#ifndef NO_OCIO - QOpenGLShaderProgramPtr ocio_shader; - GLuint ocio_lut_texture; -#endif - -private: - // timeline variables (should be copied in copy()) - Track* track_; - bool enabled_; - long clip_in_; - long timeline_in_; - long timeline_out_; - QString name_; - Media* media_; - int media_stream_; - ClipSpeed speed_; - double cached_fr_; - bool reverse_; - bool autoscale_; - - Cacher cacher; - long cacher_frame; - - NodeGraph pipeline_; - - QVector markers; - QColor color_; - bool open_; -}; - -#endif // CLIP_H diff --git a/timeline/ghost.cpp b/timeline/ghost.cpp deleted file mode 100644 index ec48003c5..000000000 --- a/timeline/ghost.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "ghost.h" - -Ghost::Ghost() : - transition(nullptr), - track_movement(0), - clip(nullptr) -{ -} - -Selection Ghost::ToSelection() const -{ - return Selection(in, out, track->Sibling(track_movement)); -} diff --git a/timeline/ghost.h b/timeline/ghost.h deleted file mode 100644 index 14ee4b131..000000000 --- a/timeline/ghost.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef GHOST_H -#define GHOST_H - -#include "effects/transition.h" -#include "track.h" -#include "project/media.h" - -namespace olive { -namespace timeline { - -enum TrimType { - TRIM_NONE, - TRIM_IN, - TRIM_OUT -}; - -} -} - -struct Ghost { - Ghost(); - - Clip* clip; - - long in; - long out; - long clip_in; - - long old_in; - long old_out; - long old_clip_in; - - Track* track; - int track_movement; - - // importing variables - Media* media; - int media_stream; - - // other variables - long ghost_length; - long media_length; - olive::timeline::TrimType trim_type; - - // transition trimming - TransitionPtr transition; - - Selection ToSelection() const; -}; - -#endif // GHOST_H diff --git a/timeline/marker.cpp b/timeline/marker.cpp deleted file mode 100644 index 24ebbd539..000000000 --- a/timeline/marker.cpp +++ /dev/null @@ -1,165 +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 "marker.h" - -#include "global/config.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "ui/mainwindow.h" -#include "timeline/sequence.h" -#include "timeline/clip.h" -#include "panels/panels.h" -#include "panels/viewer.h" - -#include -#include - -void Marker::Draw(QPainter &p, int x, int y, int bottom, bool selected) { - const QPoint points[5] = { - QPoint(x, bottom), - QPoint(x + MARKER_SIZE, bottom - MARKER_SIZE), - QPoint(x + MARKER_SIZE, y), - QPoint(x - MARKER_SIZE, y), - QPoint(x - MARKER_SIZE, bottom - MARKER_SIZE) - }; - p.setPen(Qt::black); - if (selected) { - p.setBrush(QColor(208, 255, 208)); - } else { - p.setBrush(QColor(128, 224, 128)); - } - p.drawPolygon(points, 5); -} - -void Marker::SetOnClips(const QVector &clips) -{ - // Don't bother if there are no clips - if (clips.isEmpty()) { - return; - } - - // add_marker is used to determine whether we're adding a marker, depending on whether the user input a marker name - // however if (config.set_name_with_marker) is true, we don't need a marker name so we just add - bool add_marker = !olive::config.set_name_with_marker; - - QString marker_name; - - // if Config::set_name_with_marker is true (set above), ask for a marker name - if (!add_marker) { - QInputDialog d(olive::MainWindow); - d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); - d.setLabelText(QCoreApplication::translate("Marker", "Set clip marker name:")); - d.setInputMode(QInputDialog::TextInput); - add_marker = (d.exec() == QDialog::Accepted); - marker_name = d.textValue(); - } - - // if we've decided to add a marker - if (add_marker) { - - ComboAction* ca = new ComboAction(); - - // add a marker action for each clip - foreach (Clip* c, clips) { - ca->append(new AddMarkerAction(&c->get_markers(), - c->track()->sequence()->playhead - c->timeline_in() + c->clip_in(), - marker_name)); - } - - - // push action - olive::undo_stack.push(ca); - - // redraw UI for new markers - update_ui(false); - panel_footage_viewer->update_viewer(); - - } -} - -void Marker::SetOnSequence(Sequence *seq) { - - // Don't bother if there is no sequence - if (seq == nullptr) { - return; - } - - // add_marker is used to determine whether we're adding a marker, depending on whether the user input a marker name - // however if (config.set_name_with_marker) is true, we don't need a marker name so we just add - bool add_marker = !olive::config.set_name_with_marker; - - QString marker_name; - - // if Config::set_name_with_marker is true (set above), ask for a marker name - if (!add_marker) { - QInputDialog d(olive::MainWindow); - d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); - d.setLabelText(QCoreApplication::translate("Marker", "Set sequence marker name:")); - d.setInputMode(QInputDialog::TextInput); - add_marker = (d.exec() == QDialog::Accepted); - marker_name = d.textValue(); - } - - // if we've decided to add a marker - if (add_marker) { - - ComboAction* ca = new ComboAction(); - - // FIXME kind of hacky, we get the correct marker structure from the viewer panel object that the sequence is - // attached to, as the viewers will give us the footage marker set if its footage rather than the sequence marker - // set - - if (seq == panel_footage_viewer->seq.get()) { - - // get correct marker reference from footage viewer - ca->append(new AddMarkerAction(panel_footage_viewer->marker_ref, seq->playhead, marker_name)); - - } else if (seq == panel_sequence_viewer->seq.get()) { - - // get correct marker reference from sequence viewer - ca->append(new AddMarkerAction(panel_sequence_viewer->marker_ref, seq->playhead, marker_name)); - - } else { - - // fallback to using markers from sequence provided - ca->append(new AddMarkerAction(&seq->markers, seq->playhead, marker_name)); - - } - - - // push action - olive::undo_stack.push(ca); - - // redraw UI for new markers - update_ui(false); - panel_footage_viewer->update_viewer(); - - } - -} - -void Marker::Save(QXmlStreamWriter &stream) const -{ - stream.writeStartElement("marker"); - stream.writeAttribute("frame", QString::number(frame)); - stream.writeAttribute("name", name); - stream.writeEndElement(); -} diff --git a/timeline/marker.h b/timeline/marker.h deleted file mode 100644 index f56f86b8c..000000000 --- a/timeline/marker.h +++ /dev/null @@ -1,46 +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 MARKER_H -#define MARKER_H - -#define MARKER_SIZE 4 - -#include -#include -#include -#include - -class Clip; -class Sequence; - -struct Marker { - long frame; - QString name; - - void Save(QXmlStreamWriter& stream) const; - static void Draw(QPainter& p, int x, int y, int bottom, bool selected); - - - static void SetOnClips(const QVector& clips); - static void SetOnSequence(Sequence* seq); -}; - -#endif // MARKER_H diff --git a/timeline/mediaimportdata.cpp b/timeline/mediaimportdata.cpp deleted file mode 100644 index a323c7b1c..000000000 --- a/timeline/mediaimportdata.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#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 deleted file mode 100644 index 70597c40e..000000000 --- a/timeline/mediaimportdata.h +++ /dev/null @@ -1,29 +0,0 @@ -#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/timeline/selection.cpp b/timeline/selection.cpp deleted file mode 100644 index f7c71649a..000000000 --- a/timeline/selection.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "selection.h" - -#include "effects/transition.h" -#include "timeline/clip.h" - -Selection::Selection() -{ -} - -Selection::Selection(long in, long out, Track *track) : - in_(in), - out_(out), - track_(track) -{ -} - -long Selection::in() const -{ - return in_; -} - -long Selection::out() const -{ - return out_; -} - -Track *Selection::track() const -{ - return track_; -} - -void Selection::set_in(long in) -{ - in_ = in; -} - -void Selection::set_out(long out) -{ - out_ = out; -} - -bool Selection::ContainsTransition(Clip* c, int type) const -{ - if (type == kTransitionOpening) { - return c->opening_transition != nullptr - && out_ == c->timeline_in() + c->opening_transition->get_true_length() - && ((c->opening_transition->secondary_clip == nullptr && in_ == c->timeline_in()) - || (c->opening_transition->secondary_clip != nullptr && in_ == c->timeline_in() - c->opening_transition->get_true_length())); - } else { - return c->closing_transition != nullptr - && in_ == c->timeline_out() - c->closing_transition->get_true_length() - && ((c->closing_transition->secondary_clip == nullptr && out_ == c->timeline_out()) - || (c->closing_transition->secondary_clip != nullptr && out_ == c->timeline_out() + c->closing_transition->get_true_length())); - } -} - -void Selection::Tidy(QVector& selections) -{ - for (int i=0;i ss.out()) { - // do nothing - } else if (s.in() >= ss.in() && s.out() <= ss.out()) { - remove = true; - } else if (s.in() <= ss.out() && s.out() > ss.out()) { - ss.set_out(s.out()); - remove = true; - } else if (s.out() >= ss.in() && s.in() < ss.in()) { - ss.set_in(s.in()); - remove = true; - } - if (remove) { - selections.removeAt(i); - i--; - break; - } - } - } - } - } -} diff --git a/timeline/selection.h b/timeline/selection.h deleted file mode 100644 index 519ea5939..000000000 --- a/timeline/selection.h +++ /dev/null @@ -1,53 +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 SELECTION_H -#define SELECTION_H - -#include - -class Clip; -class Track; - -class Selection { -public: - Selection(); - Selection(long in, long out, Track* track); - - long in() const; - long out() const; - Track* track() const; - - void set_in(long in); - void set_out(long out); - - bool ContainsTransition(Clip* c, int type) const; - - static void Tidy(QVector &selections); - -private: - long in_; - long out_; - Track* track_; - - bool trim_in_; -}; - -#endif // SELECTION_H diff --git a/timeline/sequence.cpp b/timeline/sequence.cpp deleted file mode 100644 index 0d419cc04..000000000 --- a/timeline/sequence.cpp +++ /dev/null @@ -1,1404 +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 "sequence.h" - -#include - -#include "timelinefunctions.h" -#include "panels/panels.h" -#include "global/clipboard.h" -#include "global/config.h" -#include "global/debug.h" - -Sequence::Sequence() : - playhead(0), - using_workarea(false), - workarea_in(0), - workarea_out(0), - wrapper_sequence(false), - texture_io(nullptr) -{ - AddTrack(olive::kTypeVideo); - AddTrack(olive::kTypeAudio); -} - -SequencePtr Sequence::copy() { - SequencePtr s = std::make_shared(); - s->name_ = tr("%1 (copy)").arg(name_); - s->set_width(width()); - s->set_height(height()); - s->frame_rate_ = frame_rate_; - s->audio_frequency_ = audio_frequency_; - s->audio_layout_ = audio_layout_; - - /* FIXME - // deep copy all of the sequence's clips - for (int i=0;itrack_lists_[i] = track_lists_.at(i)->copy(s.get()); - } - */ - - // copy all of the sequence's markers - s->markers = markers; - - return s; -} - -void Sequence::Save(QXmlStreamWriter &stream) -{ - // Provide unique IDs for each Clip - QVector all_clips = GetAllClips(); - for (int i=0;iload_id = i; - } - - stream.writeStartElement("sequence"); - stream.writeAttribute("id", QString::number(save_id)); - stream.writeAttribute("name", name_); - stream.writeAttribute("width", QString::number(width())); - stream.writeAttribute("height", QString::number(height())); - stream.writeAttribute("framerate", QString::number(frame_rate_, 'f', 10)); - stream.writeAttribute("afreq", QString::number(audio_frequency_)); - stream.writeAttribute("alayout", QString::number(audio_layout_)); - if (this == Timeline::GetTopSequence().get()) { - stream.writeAttribute("open", "1"); - } - stream.writeAttribute("workarea", QString::number(using_workarea)); - stream.writeAttribute("workareaIn", QString::number(workarea_in)); - stream.writeAttribute("workareaOut", QString::number(workarea_out)); - - QVector transition_save_cache; - QVector transition_clip_save_cache; - - /* FIXME - for (int j=0;jSave(stream); - } - */ - - for (int j=0;j(all_tracks.at(i)); - - if (t != nullptr) { - end_frame = qMax(t->GetEndFrame(), end_frame); - } - } - - return end_frame; -} - -QVector Sequence::GetAllClips() -{ - QVector all_clips; - - const QObjectList& tracks = children(); - - for (int j=0;j(tracks.at(j)); - - if (t != nullptr) { - all_clips.append(t->GetAllClips()); - } - - } - - return all_clips; -} - -QVector Sequence::GetTrackList(olive::TrackType type) -{ - QVector tracks; - - const QObjectList& all_tracks = children(); - - for (int i=0;i(all_tracks.at(i)); - if (t->type() == type) { - tracks.append(t); - } - } - - return tracks; -} - -GLuint Sequence::texture() -{ - if (texture_io == nullptr) return 0; - - texture_io->ParentNode()->Process(0); - return texture_io->GetValue().value(); -} - -void Sequence::Close() -{ - QVector all_clips = GetAllClips(); - - for (int i=0;iClose(true); - } -} - -void Sequence::RefreshClipsUsingMedia(Media *m) { - - QVector all_clips = GetAllClips(); - - for (int i=0;imedia() == m) { - c->Close(true); - c->refresh(); - } - } - -} - -QVector Sequence::SelectedClips(bool containing) -{ - QVector selected_clips; - - const QObjectList& all_tracks = children(); - - for (int j=0;j(all_tracks.at(j)); - - selected_clips.append(t->GetSelectedClips(containing)); - } - - return selected_clips; -} - -void Sequence::AddClipsFromGhosts(ComboAction* ca, const QVector& ghosts) -{ - // add clips - long earliest_point = LONG_MAX; - QVector added_clips; - for (int i=0;i(g.track->Sibling(g.track_movement)); - c->set_media(g.media, g.media_stream); - c->set_timeline_in(g.in); - c->set_timeline_out(g.out); - c->set_clip_in(g.clip_in); - if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - Footage* m = c->media()->to_footage(); - if (m->video_tracks.size() == 0) { - // audio only (greenish) - c->set_color(128, 192, 128); - } else if (m->audio_tracks.size() == 0) { - // video only (orangeish) - c->set_color(192, 160, 128); - } else { - // video and audio (blueish) - c->set_color(128, 128, 192); - } - c->set_name(m->name); - } else if (c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - // sequence (red?ish?) - c->set_color(192, 128, 128); - - c->set_name(c->media()->to_sequence()->name()); - } - c->refresh(); - added_clips.append(c); - - } - ca->append(new AddClipCommand(added_clips)); - - // link clips from the same media - for (int i=0;imedia() == cc->media()) { - c->linked.append(cc.get()); - } - } - - if (olive::config.add_default_effects_to_clips) { - if (c->type() == olive::kTypeVideo) { - // add default video effects - c->effects.append(olive::node_library[kTransformEffect]->Create(c.get())); - } else if (c->type() == olive::kTypeAudio) { - // add default audio effects - c->effects.append(olive::node_library[kVolumeEffect]->Create(c.get())); - c->effects.append(olive::node_library[kPanEffect]->Create(c.get())); - } - } - } - - if (olive::config.enable_seek_to_import) { - panel_sequence_viewer->seek(earliest_point); - } - - olive::timeline::snapped = false; -} - -void Sequence::MoveClip(Clip *c, ComboAction *ca, long iin, long iout, long iclip_in, Track *itrack, bool verify_transitions, bool relative) -{ - ClipPtr clip_ptr = c->track()->GetClipObjectFromRawPtr(c); - - ca->append(new MoveClipAction(clip_ptr, iin, iout, iclip_in, itrack, relative)); - - if (verify_transitions) { - - // if this is a shared transition, and the corresponding clip will be moved away somehow - if (c->opening_transition != nullptr - && c->opening_transition->secondary_clip != nullptr - && c->opening_transition->secondary_clip->timeline_out() != iin) { - // separate transition - ca->append(new SetPointer(reinterpret_cast(&c->opening_transition->secondary_clip), nullptr)); - ca->append(new AddTransitionCommand(nullptr, - c->opening_transition->secondary_clip, - c->opening_transition, - kInvalidNode, - 0)); - } - - if (c->closing_transition != nullptr - && c->closing_transition->secondary_clip != nullptr - && c->closing_transition->parent_clip->timeline_in() != iout) { - // separate transition - ca->append(new SetPointer(reinterpret_cast(&c->closing_transition->secondary_clip), nullptr)); - ca->append(new AddTransitionCommand(nullptr, - c, - c->closing_transition, - kInvalidNode, - 0)); - } - } -} - -void Sequence::EditToPoint(bool in, bool ripple) -{ - QVector all_clips = GetAllClips(); - - if (all_clips.size() > 0) { - long sequence_end = 0; - - bool playhead_falls_on_in = false; - bool playhead_falls_on_out = false; - long next_cut = LONG_MAX; - long prev_cut = 0; - - // find closest in point to playhead - for (int i=0;itimeline_out(), sequence_end); - - if (c->timeline_in() == playhead) - playhead_falls_on_in = true; - - if (c->timeline_out() == playhead) - playhead_falls_on_out = true; - - if (c->timeline_in() > playhead) - next_cut = qMin(c->timeline_in(), next_cut); - - if (c->timeline_out() > playhead) - next_cut = qMin(c->timeline_out(), next_cut); - - if (c->timeline_in() < playhead) - prev_cut = qMax(c->timeline_in(), prev_cut); - - if (c->timeline_out() < playhead) - prev_cut = qMax(c->timeline_out(), prev_cut); - - } - - next_cut = qMin(sequence_end, next_cut); - - QVector areas; - ComboAction* ca = new ComboAction(); - bool push_undo = true; - long seek = playhead; - - const QObjectList& all_tracks = children(); - - if ((in && (playhead_falls_on_out || (playhead_falls_on_in && playhead == 0))) - || (!in && (playhead_falls_on_in || (playhead_falls_on_out && playhead == sequence_end)))) { // one frame mode - if (ripple) { - // set up deletion areas based on track count - long in_point = playhead; - if (!in) { - in_point--; - seek--; - } - - if (in_point >= 0) { - - for (int j=0;j(all_tracks.at(j)); - areas.append(Selection(in_point, in_point+1, t)); - } - - // trim and move clips around the in point - DeleteAreas(ca, areas, true); - - if (ripple) { - Ripple(ca, in_point, -1); - } - } else { - push_undo = false; - } - } else { - push_undo = false; - } - } else { - // set up deletion areas based on track count - - long area_in, area_out; - - if (in) { - seek = prev_cut; - area_in = prev_cut; - area_out = playhead; - } else { - area_in = playhead; - area_out = next_cut; - } - - if (area_in == area_out) { - - push_undo = false; - - } else { - - for (int j=0;j(all_tracks.at(j)); - areas.append(Selection(area_in, area_out, t)); - } - - // trim and move clips around the in point - DeleteAreas(ca, areas, true); - if (ripple) { - Ripple(ca, area_in, area_in - area_out); - } - } - } - - if (push_undo) { - olive::undo_stack.push(ca); - - update_ui(true); - - if (seek != playhead && ripple) { - panel_sequence_viewer->seek(seek); - } - } else { - delete ca; - } - } else { - panel_sequence_viewer->seek(0); - } -} - -bool Sequence::SnapPoint(long *l, double zoom, bool use_playhead, bool use_markers, bool use_workarea) -{ - olive::timeline::snapped = false; - if (olive::timeline::snapping) { - if (use_playhead && !panel_sequence_viewer->playing) { - // snap to playhead - if (olive::timeline::SnapToPoint(playhead, l, zoom)) return true; - } - - // snap to marker - if (use_markers) { - for (int i=0;i all_clips = GetAllClips(); - for (int i=0;itimeline_in(), l, zoom)) { - return true; - } else if (olive::timeline::SnapToPoint(c->timeline_out(), l, zoom)) { - return true; - } else if (c->opening_transition != nullptr - && olive::timeline::SnapToPoint(c->timeline_in() + c->opening_transition->get_true_length(), l, zoom)) { - return true; - } else if (c->closing_transition != nullptr - && olive::timeline::SnapToPoint(c->timeline_out() - c->closing_transition->get_true_length(), l, zoom)) { - return true; - } else { - // try to snap to clip markers - for (int j=0;jget_markers().size();j++) { - if (olive::timeline::SnapToPoint(c->get_markers().at(j).frame + c->timeline_in() - c->clip_in(), l, zoom)) { - return true; - } - } - } - - } - } - - return false; -} - -void Sequence::DeleteInToOut(bool ripple) -{ - if (using_workarea) { - - QVector areas_to_delete; - - const QObjectList& all_tracks = children(); - - for (int j=0;j(all_tracks.at(j)); - areas_to_delete.append(Selection(workarea_in, workarea_out, t)); - } - - ComboAction* ca = new ComboAction(); - DeleteAreas(ca, areas_to_delete, true); - if (ripple) Ripple(ca, - workarea_in, - workarea_in - workarea_out); - ca->append(new SetTimelineInOutCommand(this, false, 0, 0)); - olive::undo_stack.push(ca); - update_ui(true); - } -} - -void Sequence::DeleteClipsUsingMedia(const QVector& media) -{ - QVector all_clips = GetAllClips(); - - ComboAction* ca = new ComboAction(); - bool deleted = false; - - for (int j=0;jmedia() == media.at(j)) { - ca->append(new DeleteClipAction(c)); - deleted = true; - } - } - } - - if (deleted) { - olive::undo_stack.push(ca); - update_ui(true); - } else { - delete ca; - } -} - -void Sequence::Ripple(ComboAction *ca, long point, long length, const QVector &ignore) -{ - ca->append(new RippleAction(this, point, length, ignore)); -} - -void Sequence::ChangeTrackHeightsRelatively(int diff) -{ - const QObjectList& all_tracks = children(); - - for (int j=0;j(all_tracks.at(j)); - - t->set_height(t->height() + diff); - } -} - -void Sequence::ToggleLinksOnSelected() -{ - QVector selected_clips = SelectedClips(); - - bool link = true; - QVector link_clips; - - for (int i=0;ilinked.size() > 0) { - link = false; // prioritize unlinking - - for (int j=0;jlinked.size();j++) { // add links to the command - if (!link_clips.contains(c->linked.at(j))) { - link_clips.append(c->linked.at(j)); - } - } - } - } - - if (!link_clips.isEmpty()) { - olive::undo_stack.push(new LinkCommand(link_clips, link)); - } -} - -void Sequence::Split() -{ - ComboAction* ca = new ComboAction(); - bool split_occurred = false; - - // See if there are any selected clips at the current playhead to split - QVector selected_clips = SelectedClips(true); - if (selected_clips.size() > 0) { - // see if whole clips are selected - QVector pre_clips; - QVector post_clips; - - for (int i=0;iappend(new AddClipCommand(post_clips)); - - } - } - - // If we weren't able to split any selected clips above, see if there are arbitrary selections to split - if (!split_occurred) { - - const QObjectList& all_tracks = children(); - QObject* obj; - - foreach (obj, all_tracks) { - - Track* track = static_cast(obj); - - QVector track_selections = track->Selections(); - QVector split_positions; - - for (int j=0;jClipCount();i++) { - Clip* c = track->GetClip(i).get(); - - if (SplitClipAtPositions(ca, c, split_positions, false)) { - split_occurred = true; - } - } - } - } - - // if nothing was selected or no selections fell within playhead, simply split at playhead - if (!split_occurred) { - split_occurred = SplitAllClipsAtPoint(ca, playhead); - } - - if (split_occurred) { - olive::undo_stack.push(ca); - update_ui(true); - } else { - delete ca; - } -} - -void Sequence::DeleteAreas(ComboAction* ca, QVector areas, bool deselect_areas, bool ripple) -{ - if (areas.isEmpty()) { - return; - } - - Selection::Tidy(areas); - - panel_graph_editor->set_row(nullptr); - panel_effect_controls->Clear(true); - - QVector pre_clips; - QVector post_clips; - - QVector all_clips = GetAllClips(); - - for (int i=0;itrack() == s.track() && !c->undeletable) { - if (s.ContainsTransition(c, kTransitionOpening)) { - // delete opening transition - ca->append(new DeleteTransitionCommand(c->opening_transition)); - } else if (s.ContainsTransition(c, kTransitionClosing)) { - // delete closing transition - ca->append(new DeleteTransitionCommand(c->closing_transition)); - } else if (c->timeline_in() >= s.in() && c->timeline_out() <= s.out()) { - // clips falls entirely within deletion area - ca->append(new DeleteClipAction(c)); - } else if (c->timeline_in() < s.in() && c->timeline_out() > s.out()) { - // middle of clip is within deletion area - - // duplicate clip - ClipPtr post = SplitClip(ca, true, c, s.in(), s.out()); - - pre_clips.append(c); - post_clips.append(post); - } else if (c->timeline_in() < s.in() && c->timeline_out() > s.in()) { - // only out point is in deletion area - MoveClip(c, ca, c->timeline_in(), s.in(), c->clip_in(), c->track()); - - if (c->closing_transition != nullptr) { - if (s.in() < c->timeline_out() - c->closing_transition->get_true_length()) { - ca->append(new DeleteTransitionCommand(c->closing_transition)); - } else { - ca->append(new ModifyTransitionCommand(c->closing_transition, - c->closing_transition->get_true_length() - (c->timeline_out() - s.in()))); - } - } - } else if (c->timeline_in() < s.out() && c->timeline_out() > s.out()) { - // only in point is in deletion area - MoveClip(c, ca, s.out(), c->timeline_out(), c->clip_in() + (s.out() - c->timeline_in()), c->track()); - - if (c->opening_transition != nullptr) { - if (s.out() > c->timeline_in() + c->opening_transition->get_true_length()) { - ca->append(new DeleteTransitionCommand(c->opening_transition)); - } else { - ca->append(new ModifyTransitionCommand(c->opening_transition, - c->opening_transition->get_true_length() - (s.out() - c->timeline_in()))); - } - } - } - } - } - } - - // Get ripple point and ripple length - long minimum_in = LONG_MAX; - long minimum_length = LONG_MAX; - for (int i=0;i area_copy = areas; - for (int i=0;iDeselectArea(s.in(), s.out()); - } - } - - if (ripple) { - RippleDeleteArea(ca, minimum_in, minimum_length); - } - - olive::timeline::RelinkClips(pre_clips, post_clips); - ca->append(new AddClipCommand(post_clips)); -} - -bool Sequence::SplitAllClipsAtPoint(ComboAction *ca, long point) -{ - bool split = false; - - QVector all_clips = GetAllClips(); - - for (int j=0;jIsActiveAt(point)) { - SplitClipAtPositions(ca, c, {point}, true); - split = true; - } - } - - return split; -} - -bool Sequence::SplitClipAtPositions(ComboAction *ca, Clip* clip, QVector positions, bool also_split_links) -{ - // Add the clip and each of its links to the pre_splits array - - bool split_occurred = false; - - QVector pre_splits; - pre_splits.append(clip); - - if (also_split_links) { - for (int i=0;ilinked.size();i++) { - pre_splits.append(clip->linked.at(i)); - } - } - - std::sort(positions.begin(), positions.end()); - - // Remove any duplicate positions - for (int i=1;i > post_splits(positions.size()); - - for (int i=positions.size()-1;i>=0;i--) { - - post_splits[i].resize(pre_splits.size()); - - for (int j=0;jset_timeline_out(qMin(post_splits[i][j]->timeline_out(), - positions.at(i+1))); - } - } - } - } - - for (int i=0;iappend(new AddClipCommand(post_splits[i])); - } - - return split_occurred; -} - -void Sequence::RippleDeleteEmptySpace(ComboAction* ca, Track* track, long point) -{ - QVector track_clips = track->GetAllClips(); - - long ripple_start = LONG_MAX; - long ripple_end = LONG_MAX; - - for (int i=0;itimeline_in() <= point && c->timeline_out() >= point) { - // This point is not actually empty, so there's nothing to do here - return; - } - - if (c->timeline_out() <= point) { - - ripple_start = qMin(c->timeline_out(), ripple_start); - - } else if (c->timeline_in() >= point) { - - ripple_end = qMin(c->timeline_in(), ripple_end); - - } - } - - // We now know the maximum ripple we could do to clear this empty space, but we need to ensure it won't cause - // overlaps of clips in other tracks - - if (ripple_start == ripple_end) { - return; - } - - RippleDeleteArea(ca, point, ripple_start - ripple_end); -} - -void Sequence::RippleDeleteArea(ComboAction* ca, long ripple_point, long ripple_length) { - - const QObjectList& all_tracks = children(); - - for (int j=0;j(all_tracks.at(j)); - - // We've already tested `track`, so we don't need to test it again - long first_in_point_after_point = LONG_MAX; - long out_point_just_before_first_in_point = 0; - - QVector track_clips = t->GetAllClips(); - - // Find the in point of the clip directly after the point - for (int k=0;ktimeline_in() >= ripple_point) { - first_in_point_after_point = qMin(first_in_point_after_point, c->timeline_in()); - } - } - - // Ensure we found a valid in point before proceeding - if (first_in_point_after_point != LONG_MAX) { - - // Find the out point of the clip directly before the clip found above - for (int k=0;ktimeline_out() <= first_in_point_after_point) { - out_point_just_before_first_in_point = qMax(out_point_just_before_first_in_point, c->timeline_out()); - } - } - - long ripple_test = first_in_point_after_point - out_point_just_before_first_in_point + ripple_length; - - if (ripple_test < 0) { - ripple_length -= ripple_test; - } - } - } - - if (ripple_length != 0) { - Ripple(ca, ripple_point, ripple_length); - } - -} - -OldEffectNode *Sequence::GetSelectedGizmo() -{ - OldEffectNode* gizmo_ptr = nullptr; - - QVector clips = GetAllClips(); - - for (int i=0;iIsActiveAt(playhead) - && c->IsSelected()) { - // This clip is selected and currently active - we'll use this for gizmos - - if (!c->effects.isEmpty()) { - - // find which effect has gizmos selected, or default to the first gizmo effect we find if there is - // none selected - - for (int j=0;jeffects.size();j++) { - OldEffectNode* e = c->effects.at(j).get(); - - // retrieve gizmo data from effect - if (e->are_gizmos_enabled()) { - if (gizmo_ptr == nullptr) { - gizmo_ptr = e; - } - if (panel_effect_controls->IsEffectSelected(e)) { - gizmo_ptr = e; - break; - } - } - } - } - - if (gizmo_ptr != nullptr) { - break; - } - } - } - - return gizmo_ptr; -} - -void Sequence::SelectAll() -{ - const QObjectList& all_tracks = children(); - for (int i=0;i(all_tracks.at(i))->SelectAll(); - } -} - -void Sequence::SelectAtPlayhead() -{ - const QObjectList& all_tracks = children(); - for (int i=0;i(all_tracks.at(i))->SelectAtPoint(playhead); - } -} - -void Sequence::ClearSelections() -{ - const QObjectList& all_tracks = children(); - for (int i=0;i(all_tracks.at(i))->ClearSelections(); - } -} - -void Sequence::AddSelectionsToClipboard(bool delete_originals) -{ - olive::clipboard.Clear(); - olive::clipboard.SetType(Clipboard::CLIPBOARD_TYPE_CLIP); - - QVector original_clips; - QVector copied_clips; - - long min_in = LONG_MAX; - - QVector selections = Selections(); - for (int i=0;i track_clips = s.track()->GetAllClips(); - - for (int j=0;jtimeline_out() < s.in() || c->timeline_in() > s.out())) { - - // If so, we'll be copying this clip - original_clips.append(c); - - ClipPtr copy = c->copy(nullptr); - - // If we only copied part of this clip, adjust the copy so it's only that part of the clip - if (copy->timeline_in() < s.in()) { - copy->set_clip_in(copy->clip_in() + (s.in() - copy->timeline_in())); - copy->set_timeline_in(s.in()); - } - - if (copy->timeline_out() > s.out()) { - copy->set_timeline_out(s.out()); - } - - // Store the minimum in point as all copies will be stored offset from 0 - min_in = qMin(min_in, s.in()); - - copied_clips.append(copy); - olive::clipboard.Append(copy); - - } - } - } - - // Determine whether we actually copied anything - if (min_in < LONG_MAX) { - - // Offset all copied clips to 0 - for (int i=0;iset_timeline_in(copy->timeline_in() - min_in); - copy->set_timeline_out(copy->timeline_out() - min_in); - } - - // Relink the copied clips with each other - olive::timeline::RelinkClips(original_clips, copied_clips); - - // If we're deleting the originals (i.e. cutting), delete them now - if (delete_originals) { - ComboAction* ca = new ComboAction(); - DeleteAreas(ca, selections, true); - olive::undo_stack.push(ca); - } - - } -} - -QVector Sequence::Selections() -{ - QVector selections; - - const QObjectList& all_tracks = children(); - - for (int i=0;i(all_tracks.at(i))->Selections()); - } - - return selections; -} - -void Sequence::SetSelections(const QVector &selections) -{ - ClearSelections(); - - for (int i=0;iSelectArea(s.in(), s.out()); - } -} - -void Sequence::TidySelections() -{ - QVector selections = Selections(); - Selection::Tidy(selections); - SetSelections(selections); -} - -Track *Sequence::PreviousTrack(Track *t) -{ - Track* previous_track = nullptr; - - // Loop through tracks - const QObjectList& all_tracks = children(); - for (int i=0;i(all_tracks.at(i)); - - if (comp_track == t) { - // If this is the track, we'll know the previous track by now - break; - } else if (comp_track->type() == t->type()) { - // Otherwise, we'll keep "track" of it - previous_track = t; - } - } - - return previous_track; -} - -Track *Sequence::NextTrack(Track *t) -{ - if (LastTrack(t->type()) == t) { - - return AddTrack(t->type()); - - } else { - - Track* next_track = nullptr; - - const QObjectList& all_tracks = children(); - - for (int i=all_tracks.size()-1;i>=0;i--) { - - Track* track = static_cast(all_tracks.at(i)); - - if (track == t) { - break; - } - - if (track->type() == t->type()) { - next_track = track; - } - - } - - return next_track; - } -} - -Track *Sequence::SiblingTrack(Track *t, int diff) -{ - if (diff == 0) { - return t; - } - - return TrackAt(t->type(), qMax(0, IndexOfTrack(t) + diff)); -} - -int Sequence::IndexOfTrack(Track *t) -{ - int counter = -1; - - const QObjectList& all_tracks = children(); - - for (int i=0;i(all_tracks.at(i)); - - if (track->type() == t->type()) { - counter++; - } - - if (track == t) { - return counter; - } - } - - return -1; -} - -Track *Sequence::FirstTrack(olive::TrackType type) -{ - const QObjectList& all_tracks = children(); - - for (int i=0;i(all_tracks.at(i)); - - if (track->type() == type) { - return track; - } - } - return nullptr; -} - -Track *Sequence::LastTrack(olive::TrackType type) -{ - const QObjectList& all_tracks = children(); - - for (int i=all_tracks.size()-1;i>=0;i--) { - - Track* track = static_cast(all_tracks.at(i)); - - if (track->type() == type) { - return track; - } - } - return nullptr; -} - -Track *Sequence::TrackAt(olive::TrackType type, int index) -{ - int counter = -1; - - const QObjectList& all_tracks = children(); - - for (int i=0;i(all_tracks.at(i)); - - if (track->type() == type) { - counter++; - } - - if (counter == index) { - return track; - } - } - - Track* t; - - do { - t = AddTrack(type); - counter++; - } while (index > counter); - - return t; -} - -int Sequence::TrackCount(olive::TrackType type) -{ - int counter = 0; - - const QObjectList& all_tracks = children(); - - for (int i=0;i(all_tracks.at(i)); - - if (track->type() == type) { - counter++; - } - } - - return counter; -} - -Track* Sequence::AddTrack(olive::TrackType type) -{ - Track* t = new Track(nullptr, type); - t->setParent(this); - return t; -} - -ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long frame) -{ - return SplitClip(ca, transitions, pre, frame, frame); -} - -ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long frame, long post_in) -{ - if (pre == nullptr) { - return nullptr; - } - - if (pre->timeline_in() < frame && pre->timeline_out() > frame) { - // duplicate clip without duplicating its transitions, we'll restore them later - - ClipPtr post = pre->copy(pre->track()); - - long new_clip_length = frame - pre->timeline_in(); - - post->set_timeline_in(post_in); - post->set_clip_in(pre->clip_in() + (post->timeline_in() - pre->timeline_in())); - - MoveClip(pre, ca, pre->timeline_in(), frame, pre->clip_in(), pre->track(), false); - - if (transitions) { - - // check if this clip has a closing transition - if (pre->closing_transition != nullptr) { - - // if so, move closing transition to the post clip - post->closing_transition = pre->closing_transition; - - // and set the original clip's closing transition to nothing - ca->append(new SetPointer(reinterpret_cast(&pre->closing_transition), nullptr)); - - // and set the transition's reference to the post clip - if (post->closing_transition->parent_clip == pre) { - ca->append(new SetPointer(reinterpret_cast(&post->closing_transition->parent_clip), post.get())); - } - if (post->closing_transition->secondary_clip == pre) { - ca->append(new SetPointer(reinterpret_cast(&post->closing_transition->secondary_clip), post.get())); - } - - // and make sure it's at the correct size to the closing clip - if (post->closing_transition != nullptr && post->closing_transition->get_true_length() > post->length()) { - ca->append(new ModifyTransitionCommand(post->closing_transition, post->length())); - post->closing_transition->set_length(post->length()); - } - - } - - // we're keeping the opening clip, so ensure that's a correct size too - if (pre->opening_transition != nullptr && pre->opening_transition->get_true_length() > new_clip_length) { - ca->append(new ModifyTransitionCommand(pre->opening_transition, new_clip_length)); - } - } - - return post; - - } else if (frame == pre->timeline_in() - && pre->opening_transition != nullptr - && pre->opening_transition->secondary_clip != nullptr) { - // special case for shared transitions to split it into two - - // set transition to single-clip mode - ca->append(new SetPointer(reinterpret_cast(&pre->opening_transition->secondary_clip), nullptr)); - - // clone transition for other clip - ca->append(new AddTransitionCommand(nullptr, - pre->opening_transition->secondary_clip, - pre->opening_transition, - kInvalidNode, - 0) - ); - - } - - return nullptr; -} - -bool Sequence::SplitSelection(ComboAction *ca, QVector selections) -{ - bool ret = false; - QVector all_clips = GetAllClips(); - - for (int i=0;i points; - - for (int j=0;jtrack()) { - if (c->timeline_in() < s.in() && c->timeline_out() > s.in()) { - points.append(s.in()); - } - if (c->timeline_in() < s.out() && c->timeline_out() > s.out()) { - points.append(s.out()); - } - } - } - - if (SplitClipAtPositions(ca, c, points, false)) { - ret = true; - } - } - - return ret; -} diff --git a/timeline/sequence.h b/timeline/sequence.h deleted file mode 100644 index 8cb58607a..000000000 --- a/timeline/sequence.h +++ /dev/null @@ -1,161 +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 SEQUENCE_H -#define SEQUENCE_H - -#include -#include - -#include "clip.h" -#include "marker.h" -#include "selection.h" -#include "ghost.h" -#include "nodes/nodegraph.h" - -class Sequence : public NodeGraph { - Q_OBJECT -public: - Sequence(); - SequencePtr copy(); - - void Save(QXmlStreamWriter& stream); - - const QString& name(); - void set_name(const QString& s); - - const double& frame_rate(); - void set_frame_rate(const double& d); - - const int& audio_frequency(); - void set_audio_frequency(const int& f); - - const int& audio_layout(); - void set_audio_layout(const int& l); - - long GetEndFrame(); - QVector GetAllClips(); - - /** - * @brief Close all open clips in a Sequence - * - * Closes any currently open clips on a Sequence and waits for them to close before returning. This may be slow as a - * result on large Sequence objects. If a Clip is a nested Sequence, this function calls itself recursively on that - * Sequence too. - * - * @param s - * - * The Sequence to close all clips on. - */ - void Close(); - - void RefreshClipsUsingMedia(Media* m = nullptr); - QVector SelectedClips(bool containing = true); - - void AddClipsFromGhosts(ComboAction *ca, const QVector &ghosts); - - void MoveClip(Clip* c, - ComboAction* ca, - long iin, - long iout, - long iclip_in, - Track *itrack, - bool verify_transitions = true, - bool relative = false); - - void EditToPoint(bool in, bool ripple); - - bool SnapPoint(long* l, double zoom, bool use_playhead, bool use_markers, bool use_workarea); - - void DeleteAreas(ComboAction* ca, QVector areas, bool deselect_areas = false, bool ripple = false); - void DeleteInToOut(bool ripple); - void DeleteClipsUsingMedia(const QVector &media); - - void Ripple(ComboAction *ca, long point, long length, const QVector &ignore = QVector()); - - void ChangeTrackHeightsRelatively(int diff); - - void ToggleLinksOnSelected(); - - void Split(); - bool SplitAllClipsAtPoint(ComboAction *ca, long point); - bool SplitClipAtPositions(ComboAction* ca, Clip *clip, QVector positions, bool also_split_links = true); - - void RippleDeleteEmptySpace(ComboAction *ca, Track *track, long point); - void RippleDeleteArea(ComboAction* ca, long ripple_point, long ripple_length); - - OldEffectNode* GetSelectedGizmo(); - - bool IsClipSelected(Clip* clip, bool containing = true); - bool IsTransitionSelected(Transition* t); - - void SelectAll(); - void SelectAtPlayhead(); - void ClearSelections(); - void AddSelectionsToClipboard(bool delete_originals); - QVector Selections(); - void SetSelections(const QVector& selections); - void TidySelections(); - - Track* PreviousTrack(Track* t); - Track* NextTrack(Track* t); - Track* SiblingTrack(Track* t, int diff); - int IndexOfTrack(Track* t); - Track* FirstTrack(olive::TrackType type); - Track* LastTrack(olive::TrackType type); - Track* TrackAt(olive::TrackType type, int index); - int TrackCount(olive::TrackType type); - QVector GetTrackList(olive::TrackType type); - - // FIXME: TEST CODE - GLuint texture(); - NodeIO* texture_io; - // END TEST CODE - - long playhead; - - bool using_workarea; - long workarea_in; - long workarea_out; - - bool wrapper_sequence; - - int save_id; - - QVector markers; - -private: - Track *AddTrack(olive::TrackType type); - - //QVector tracks_; - - ClipPtr SplitClip(ComboAction* ca, bool transitions, Clip *clip, long frame); - ClipPtr SplitClip(ComboAction* ca, bool transitions, Clip *clip, long frame, long post_in); - bool SplitSelection(ComboAction* ca, QVector selections); - - QString name_; - double frame_rate_; - int audio_frequency_; - int audio_layout_; -}; - -using SequencePtr = std::shared_ptr; - -#endif // SEQUENCE_H diff --git a/timeline/timelinefunctions.cpp b/timeline/timelinefunctions.cpp deleted file mode 100644 index d7f765610..000000000 --- a/timeline/timelinefunctions.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "timelinefunctions.h" - -#include "global/math.h" -#include "global/config.h" -#include "global/timing.h" -#include "sequence.h" - -// snapping -bool olive::timeline::snapping = true; -bool olive::timeline::snapped = false; -long olive::timeline::snap_point = 0; - -void olive::timeline::RelinkClips(QVector &pre_clips, QVector &post_clips) -{ - // Loop through each "pre" clip - for (int i=0;ilinked.size();j++) { - - // Loop again through the "pre" clips to determine which are linked to each other - for (int l=0;llinked.at(j) == pre_clips.at(l)) { - - // Check if we have an equivalent in the post_clips, and link it if so - if (post_clips.at(l) != nullptr) { - post_clips.at(i)->linked.append(post_clips.at(l).get()); - } - - } - } - } - } -} - -bool olive::timeline::SnapToPoint(long point, long* l, double zoom) { - long limit = getFrameFromScreenPoint(zoom, 10); // FIXME magic number 10 used for on screen pixel threshold to snap to - if (*l > point-limit-1 && *l < point+limit+1) { - olive::timeline::snap_point = point; - *l = point; - olive::timeline::snapped = true; - return true; - } - return false; -} - - -QVector olive::timeline::CreateGhostsFromMedia(Sequence *seq, - long entry_point, - QVector &media_list) -{ - QVector ghosts; - - for (int i=0;iget_type()) { - case MEDIA_TYPE_FOOTAGE: - m = medium->to_footage(); - can_import = m->ready; - 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; - } - 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()); - } - break; - case MEDIA_TYPE_SEQUENCE: - s = medium->to_sequence().get(); - sequence_length = s->GetEndFrame(); - if (seq != nullptr) sequence_length = rescale_frame_number(sequence_length, s->frame_rate(), seq->frame_rate()); - can_import = (s != seq && sequence_length != 0); - if (s->using_workarea) { - default_clip_in = rescale_frame_number(s->workarea_in, s->frame_rate(), seq->frame_rate()); - default_clip_out = rescale_frame_number(s->workarea_out, s->frame_rate(), seq->frame_rate()); - } - break; - default: - can_import = false; - } - - if (can_import) { - Ghost g; - g.clip = nullptr; - g.trim_type = olive::timeline::TRIM_NONE; - g.old_clip_in = g.clip_in = default_clip_in; - g.media = medium; - g.in = entry_point; - g.transition = nullptr; - - switch (medium->get_type()) { - case MEDIA_TYPE_FOOTAGE: - // is video source a still image? - if (m->video_tracks.size() > 0 && m->video_tracks.at(0).infinite_length && m->audio_tracks.size() == 0) { - g.out = g.in + 100; - } else { - long length = m->get_length_in_frames(seq->frame_rate()); - g.out = entry_point + length - default_clip_in; - if (m->using_inout) { - g.out -= (length - default_clip_out); - } - } - - 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 = seq->GetTrackList(olive::kTypeAudio).at(j); - g.media_stream = m->audio_tracks.at(j).file_index; - ghosts.append(g); - } - } - } - - 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 = seq->GetTrackList(olive::kTypeVideo).at(j); - g.media_stream = m->video_tracks.at(j).file_index; - ghosts.append(g); - } - } - } - break; - case MEDIA_TYPE_SEQUENCE: - g.out = entry_point + sequence_length - default_clip_in; - - if (s->using_workarea) { - g.out -= (sequence_length - default_clip_out); - } - - if (import_data.type() == olive::timeline::kImportVideoOnly - || import_data.type() == olive::timeline::kImportBoth) { - g.track = seq->GetTrackList(olive::kTypeVideo).first(); - ghosts.append(g); - } - - if (import_data.type() == olive::timeline::kImportAudioOnly - || import_data.type() == olive::timeline::kImportBoth) { - g.track = seq->GetTrackList(olive::kTypeAudio).first(); - ghosts.append(g); - } - - break; - } - entry_point = g.out; - } - } - for (int i=0;i - -#include "timeline/clip.h" -#include "timeline/mediaimportdata.h" -#include "ghost.h" - -namespace olive { -namespace timeline { - -enum CreateObjects { - ADD_OBJ_TITLE, - ADD_OBJ_SOLID, - ADD_OBJ_BARS, - ADD_OBJ_TONE, - ADD_OBJ_NOISE, - ADD_OBJ_AUDIO -}; - -enum Alignment { - kAlignmentTop, - kAlignmentBottom, - kAlignmentSingle -}; - -void RelinkClips(QVector& pre_clips, QVector &post_clips); - -bool SnapToPoint(long point, long* l, double zoom); - -QVector CreateGhostsFromMedia(Sequence *seq, long entry_point, QVector &media_list); - -// snapping -extern bool snapping; -extern bool snapped; -extern long snap_point; - -} -} - -#endif // TIMELINEFUNCTIONS_H diff --git a/timeline/timelineshared.cpp b/timeline/timelineshared.cpp deleted file mode 100644 index 6f5fd8337..000000000 --- a/timeline/timelineshared.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "timelineshared.h" - -TimelineShared::TimelineShared() -{ - -} diff --git a/timeline/timelineshared.h b/timeline/timelineshared.h deleted file mode 100644 index 0622ac154..000000000 --- a/timeline/timelineshared.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TIMELINESHARED_H -#define TIMELINESHARED_H - - -class TimelineShared -{ -public: - TimelineShared(); -}; - -#endif // TIMELINESHARED_H diff --git a/timeline/timelinetools.cpp b/timeline/timelinetools.cpp deleted file mode 100644 index fe3eea243..000000000 --- a/timeline/timelinetools.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "timelinetools.h" - -olive::timeline::Tool olive::timeline::current_tool = olive::timeline::TIMELINE_TOOL_POINTER; diff --git a/timeline/timelinetools.h b/timeline/timelinetools.h deleted file mode 100644 index dfbaec221..000000000 --- a/timeline/timelinetools.h +++ /dev/null @@ -1,47 +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 TIMELINETOOLS_H -#define TIMELINETOOLS_H - -namespace olive { -namespace timeline { - -enum Tool { - TIMELINE_TOOL_POINTER, - TIMELINE_TOOL_EDIT, - TIMELINE_TOOL_RAZOR, - TIMELINE_TOOL_RIPPLE, - TIMELINE_TOOL_ROLLING, - TIMELINE_TOOL_SLIP, - TIMELINE_TOOL_SLIDE, - TIMELINE_TOOL_HAND, - TIMELINE_TOOL_ZOOM, - TIMELINE_TOOL_MENU, - TIMELINE_TOOL_TRANSITION, - TIMELINE_TOOL_COUNT -}; - -extern Tool current_tool; - -} -} - -#endif // TIMELINETOOLS_H diff --git a/timeline/track.cpp b/timeline/track.cpp deleted file mode 100644 index 5749651de..000000000 --- a/timeline/track.cpp +++ /dev/null @@ -1,421 +0,0 @@ -#include "track.h" - -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "global/math.h" - -int olive::timeline::kTrackDefaultHeight = 40; -int olive::timeline::kTrackMinHeight = 30; -int olive::timeline::kTrackHeightIncrement = 10; - -Track::Track(Sequence* parent, olive::TrackType type) : - Node(parent), - type_(type), - muted_(false), - soloed_(false), - locked_(false), - height_(olive::timeline::kTrackDefaultHeight) -{ -} - -Track *Track::copy(Sequence *parent) -{ - Track* t = new Track(parent, type_); - - t->ResizeClipArray(ClipCount()); - for (int i=0;icopy(t); - copy->linked = c->linked; - t->clips_[i] = copy; - } - - return t; -} - -Sequence *Track::sequence() -{ - return static_cast(parent()); -} - -void Track::Save(QXmlStreamWriter &stream) -{ - stream.writeStartElement("track"); - - for (int j=0;jSave(stream); - - } - - stream.writeEndElement(); // track -} - -olive::TrackType Track::type() -{ - return type_; -} - -int Track::height() -{ - return height_; -} - -void Track::set_height(int h) -{ - height_ = qMax(h, olive::timeline::kTrackMinHeight); - emit HeightChanged(h); -} - -QString Track::name() -{ - if (name_.isEmpty()) { - int display_index = Index() + 1; - - switch (type_) { - case olive::kTypeVideo: - return tr("Video %1").arg(display_index); - case olive::kTypeAudio: - return tr("Audio %1").arg(display_index); - case olive::kTypeSubtitle: - return tr("Subtitle %1").arg(display_index); - default: - return tr("Unknown %1").arg(display_index); - } - } - - return name_; -} - -void Track::SetName(const QString &s) -{ - name_ = s; -} - -void Track::AddClip(ClipPtr clip) -{ - if (clips_.contains(clip)) { - return; - } - - clips_.append(clip); - if (clip->track() != nullptr && clip->track() != this) { - clip->track()->RemoveClip(clip.get()); - } - clip->set_track(this); -} - -int Track::ClipCount() -{ - return clips_.size(); -} - -ClipPtr Track::GetClip(int i) -{ - return clips_.at(i); -} - -void Track::RemoveClip(int i) -{ - clips_.removeAt(i); -} - -void Track::RemoveClip(Clip *c) -{ - for (int i=0;i Track::GetAllClips() -{ - QVector clips; - - clips.resize(clips_.size()); - for (int i=0;i Track::GetSelectedClips(bool containing) -{ - QVector selected_clips; - - for (int i=0;itimeline_in() <= point && c->timeline_out() > point) { - return c; - } - } - - return nullptr; -} - -bool Track::ContainsClip(Clip *c) -{ - ClipPtr clip; - foreach (clip, clips_) { - if (clip.get() == c) { - return true; - } - } - return false; -} - -Track *Track::Previous() -{ - return sequence()->PreviousTrack(this); -} - -Track *Track::Next() -{ - return sequence()->NextTrack(this); -} - -Track *Track::Sibling(int diff) -{ - return sequence()->SiblingTrack(this, diff); -} - -int Track::Index() -{ - return sequence()->IndexOfTrack(this); -} - -bool Track::IsClipSelected(int clip_index, bool containing) -{ - return IsClipSelected(clips_.at(clip_index).get(), containing); -} - -bool Track::IsClipSelected(Clip *clip, bool containing) -{ - for (int i=0;itimeline_in() >= s.in() && clip->timeline_out() <= s.out()) - || (!containing && !(clip->timeline_in() >= s.out() || clip->timeline_out() <= s.in())))) { - return true; - } - } - return false; -} - -bool Track::IsTransitionSelected(Transition *t) -{ - if (t == nullptr) { - return false; - } - - Clip* c = t->parent_clip; - - long transition_in_point; - long transition_out_point; - - // Get positions of the transition on the timeline - - if (t == c->opening_transition.get()) { - transition_in_point = c->timeline_in(); - transition_out_point = c->timeline_in() + t->get_true_length(); - - if (t->secondary_clip != nullptr) { - transition_in_point -= t->get_true_length(); - } - } else { - transition_in_point = c->timeline_out() - t->get_true_length(); - transition_out_point = c->timeline_out(); - - if (t->secondary_clip != nullptr) { - transition_out_point += t->get_true_length(); - } - } - - // See if there's a selection matching this - for (int i=0;i= transition_out_point) { - return true; - } - } - - return false; -} - -void Track::SelectArea(long in, long out) -{ - selections_.append(Selection(in, out, this)); - Selection::Tidy(selections_); -} - -void Track::SelectClip(Clip* c) -{ - SelectArea(c->timeline_in(), c->timeline_out()); -} - -void Track::SelectAll() -{ - ClearSelections(); - - // Select every clip - for (int i=0;itimeline_in() <= point - && c->timeline_out() > point) { - SelectClip(c); - } - } -} - -void Track::ClearSelections() -{ - selections_.clear(); -} - -void Track::DeselectArea(long in, long out) -{ - int selection_count = selections_.size(); - for (int i=0;i= in && s.out() <= out) { - // whole selection is in deselect area - selections_.removeAt(i); - i--; - selection_count--; - } else if (s.in() < in && s.out() > out) { - // middle of selection is in deselect area - Selection new_sel(out, s.out(), s.track()); - selections_.append(new_sel); - - s.set_out(in); - } else if (s.in() < in && s.out() > in) { - // only out point is in deselect area - s.set_out(in); - } else if (s.in() < out && s.out() > out) { - // only in point is in deselect area - s.set_in(out); - } - } -} - -QVector Track::Selections() -{ - return selections_; -} - -long Track::GetEndFrame() -{ - long end_frame = 0; - - for (int i=0;itimeline_out(true)); - } - } - - return end_frame; -} - -bool Track::IsEffectivelyMuted() -{ - // Check if this track is muted - if (muted_) { - return true; - } - - // Check if any tracks are soloed - bool a_track_is_soloed = false; - - QVector siblings = sequence()->GetTrackList(type_); - for (int i=0;iIsSoloed()) { - a_track_is_soloed = true; - break; - } - } - - // Return if a track is soloed and this track is not soloed - return (a_track_is_soloed && !soloed_); -} - -bool Track::IsMuted() -{ - return muted_; -} - -void Track::SetMuted(bool muted) -{ - muted_ = muted; -} - -bool Track::IsSoloed() -{ - return soloed_; -} - -void Track::SetSoloed(bool soloed) -{ - soloed_ = soloed; -} - -bool Track::IsLocked() -{ - return locked_; -} - -void Track::SetLocked(bool locked) -{ - locked_ = locked; -} diff --git a/timeline/track.h b/timeline/track.h deleted file mode 100644 index fe79ecbd4..000000000 --- a/timeline/track.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef TRACK_H -#define TRACK_H - -#include -#include - -#include "nodes/oldeffectnode.h" -#include "tracktypes.h" -#include "undo/comboaction.h" -#include "timeline/selection.h" -#include "nodes/node.h" - -class Sequence; -class Transition; - -namespace olive { - namespace timeline { - const int kGhostThickness = 2; - const int kClipTextPadding = 3; - - /** - * @brief Set default track sizes - * - * Olive has a few default constants used for adjusting track heights in the Timeline. For HiDPI, it makes - * sense to multiply these by the current DPI scale. It uses a variable from QApplication to do this multiplication, - * which means the QApplication instance needs to be instantiated before these are calculated. Therefore, call this - * function ONCE after QApplication is created to multiply the track heights correctly. - */ - void MultiplyTrackSizesByDPI(); - - extern int kTrackDefaultHeight; - extern int kTrackMinHeight; - extern int kTrackHeightIncrement; - - extern int kTimelineLabelFixedWidth; - } -} - -class Sequence; - -class Track : public Node -{ - Q_OBJECT -public: - Track(Sequence* parent, olive::TrackType type); - Track* copy(Sequence* parent); - - Sequence* sequence(); - - void Save(QXmlStreamWriter& stream); - - olive::TrackType type(); - - int height(); - void set_height(int h); - - QString name(); - void SetName(const QString& s); - - void AddClip(ClipPtr clip); - int ClipCount(); - ClipPtr GetClip(int i); - void RemoveClip(int i); - void RemoveClip(Clip* c); - QVector GetAllClips(); - QVector GetSelectedClips(bool containing); - ClipPtr GetClipObjectFromRawPtr(Clip* c); - Clip* GetClipFromPoint(long point); - bool ContainsClip(Clip* c); - - Track* Previous(); - Track* Next(); - Track* Sibling(int diff); - - int Index(); - - bool IsClipSelected(int clip_index, bool containing = true); - bool IsClipSelected(Clip* clip, bool containing = true); - bool IsTransitionSelected(Transition* t); - - void DeleteArea(ComboAction *ca, const Selection& s); - void DeleteArea(ComboAction *ca, long in, long out); - - void SelectArea(long in, long out); - void SelectClip(Clip *c); - void SelectAll(); - void SelectAtPoint(long point); - void TidySelections(); - void ClearSelections(); - void DeselectArea(long in, long out); - QVector Selections(); - - long GetEndFrame(); - - bool IsEffectivelyMuted(); - bool IsMuted(); - bool IsSoloed(); - bool IsLocked(); - -public slots: - void SetMuted(bool muted); - void SetSoloed(bool soloed); - void SetLocked(bool locked); - -signals: - void HeightChanged(int height); - -private: - void ResizeClipArray(int new_size); - - olive::TrackType type_; - int height_; - QVector clips_; - QVector effects_; - QVector selections_; - - bool muted_; - bool soloed_; - bool locked_; - - QString name_; -}; - -#endif // TRACK_H diff --git a/timeline/tracktypes.h b/timeline/tracktypes.h deleted file mode 100644 index c49b049a7..000000000 --- a/timeline/tracktypes.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TRACKTYPES_H -#define TRACKTYPES_H - -namespace olive { - enum TrackType { - kTypeVideo, - kTypeAudio, - kTypeSubtitle, - kTypeCount - }; -}; - -#endif // TRACKTYPES_H diff --git a/ts/olive_ar.ts b/ts/olive_ar.ts deleted file mode 100644 index c33f59421..000000000 --- a/ts/olive_ar.ts +++ /dev/null @@ -1,4866 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - زيتون هو محرر فيديو غير خطي. هذا البرنامج حر ومحمي بموجب رخصة جنو العمومية. - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - فريق زيتون ملزم بإخبار مستخدميه بأن الشفرة المصدرية لزيتون متوفرة للتنزيل عبر موقعه الإلكتروني. - - - - ActionSearch - - - Search for action... - ابحث عن إجراء... - - - - AdvancedVideoDialog - - - Advanced Video Settings - - - - - Pixel Format: - - - - - Threads: - - - - - Audio - - Audio - الصوت - - - Recording - تسجيل - - - - %1 Audio - - - - - Recording %1 - - - - - AudioNoiseEffect - - - Amount - المقدار - - - - Mix - دمج - - - - Noise - ضجيج - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - - - - - Attack Threshold: - - - - - Attack Time: - - - - - Release Threshold: - - - - - Release Time: - - - - - Cacher - - - - Could not open %1 - %2 - - - - - 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 - منظور - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - DebugDialog - - - Debug Log - سجل التنقيح - - - - DemoNotice - - - - Welcome to 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. - زيتون هو محرر فيديو حر ومفتوح المصدر تحت مظلة رخصة رخصة جنو العمومية. أن دفعت ﻷجل الحصول على هذا البرنامج فقد غُششت. - - - - 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! - شكراً لتجربتك زيتون ونحن نأمل أن تستمتع به! - - - - Effect - - Invalid effect - تأثير غير صالح - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - لا وجود للتأثير '%1'. هذا التأثير قد يكون فاسد حاول إعادة تثبيته مجدداً أو زيتون. - - - Cu&t - قط&ع - - - &Copy - &نسخ - - - Move &Up - حرك &للاعلى - - - Move &Down - حرك &لﻷسفل - - - D&elete - ح&ذف - - - Load Settings From File - حمل اﻹعدادات من ملف - - - Save Settings to File - أحفظ اﻷعدادات في ملف - - - Save Effect Settings - أحفظ أعدادات المؤثر - - - Effect XML Settings %1 - غير إعدادات XML %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 - - - Effects: - المؤثرات: - - - &Paste - &لصق - - - - (none) - (لا شيء) - - - - 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? - تعطيل اﻹطارات المفتاحية سوف يحذف جميع اﻹطارات المفتاحية الحالية هل أنت متأكد من ما ستقدم عليه؟ - - - - EffectUI - - - %1 (Opening) - - - - - %1 (Closing) - - - - - %1 (multiple) - - - - - Cu&t - قط&ع - - - - &Copy - &نسخ - - - - Move &Up - حرك &للاعلى - - - - Move &Down - حرك &لﻷسفل - - - - D&elete - ح&ذف - - - - Load Settings From File - حمل اﻹعدادات من ملف - - - - Save Settings to File - أحفظ اﻷعدادات في ملف - - - - EmbeddedFileChooser - - - File: - ملف: - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - صدّر "%1" - - - - Unknown codec name %1 - - - - - Export Failed - فشل التصدير - - - - Export failed - %1 - فشل تصدير - %1 - - - - Invalid dimensions - أبعاد خاطئة - - - - Export width and height must both be even numbers/divisible by 2. - تصدير العرض والطول يجب أن يكون عدد زوجي/قابل للقسمة ب 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% (ETA: %1:%2:%3) - - - - - Quality-based (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: - نوع الضغط: - - - - Advanced - - - - - Audio - الصوت - - - - Sampling Rate: - معدل الإعتيان: - - - - Bitrate (Kbps/CBR): - نسبة البت (Kbps/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) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - النوع - - - - Fill Left with Right - املأ اليسار مع اليمين - - - - Fill Right with Left - املأ اليمين مع اليسار - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - 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. - ملحوظة: لا يمكنك تحميل إضافة Frei0r 32-بت لنسخة زيتون مبنية ل64-بت. رجاءً جد نسخة 64-بت من هذه الإضافة أو أنتقل لنسخة زيتون مبنية على 32-بت. - - - 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. - ملحوظة: لا يمكنك تحميل إضافة Frei0r 64-بت لنسخة زيتون مبنية ل32-بت. رجاءً جد نسخة 32-بت من هذه الإضافة أو أنتقل لنسخة زيتون مبنية على 64-بت. - - - - Error loading Frei0r plugin - خطأ تحميل إضافة Frei0r - - - - GraphEditor - - - Graph Editor - محرر المخطط - - - - Linear - خطي - - - - Bezier - بيزير - - - - Hold - أمسك - - - - GraphView - - - Zoom to Selection - قرّب للمُحدد - - - - Zoom to Show All - تقريب لرؤية الكل - - - - Reset View - صفّر الرؤية - - - - InterlacingName - - - None (Progressive) - لا شيء (متفاقم) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - الحقل العلوي أولاً - - - Bottom Field First - الحقل السفلي أولاً - - - - Invalid - غير صالح - - - - KeyframeNavigator - - - Enable Keyframes - فعّل اﻹطارات المفتاحية - - - - KeyframeView - - - Linear - خطي - - - - Bezier - بيزير - - - - Hold - أمسك - - - - LabelSlider - - - &Edit - &تعديل - - - - &Reset to Default - - - - - - Set Value - حدد القيمة - - - - - New value: - قيمة جديدة: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - 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? - هذا المشروع كان محفوظاً بنسخة مختلفة من زيتون وقد لا تكون متوافقة بشكل كامل مع هذه النسخة. هل تريد محاولة تحميله على إي حال؟ - - - 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 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - - Welcome to %1 - مرحباً في %1 - - - Auto-recovery - اﻷستعادة التلقائية - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - زيتون لم يغلق بشكل سليم وتم التعرف على ملف اﻷستعادة التلقائة. هل تريد فتحه؟ - - - &Project - &المشروع - - - &Sequence - &مقطع - - - &Folder - &مجلد - - - Set In Point - ضع في نقطة - - - Set Out Point - ضع خارج نقطة - - - Reset In Point - صفر في النقطة - - - Reset Out Point - صفّر النقطة - - - Clear In/Out Point - محو نقطة الدخل/الخرج - - - No active sequence - لا مقاطع نشطة - - - Please open the sequence you wish to export. - رجاءً أفتح المقطع المراد تصديره. - - - Save Project As... - أحفظ المشروع ك... - - - Unsaved Project - مشروع غير محفوظ - - - This project has changed since it was last saved. Would you like to save it before closing? - هذا المشروع غُيِرَ منذ أخر مرة. أتريد حفظه قبل اﻹغلاق؟ - - - - &File - &ملف - - - - &New - &جديد - - - - &Open Project - &أفتح مشروع - - - - Clear Recent List - أفرغ قائمة مؤخراً - - - - Open Recent - أفتح مؤخراً - - - - &Save Project - &أحفظ المشروع - - - - Save Project &As - أحفظ المشروع &ك - - - - &Import... - &أستيراد - - - - &Export... - &تصدير - - - - E&xit - خ&روج - - - - &Edit - &تعديل - - - - &Undo - &تراجع - - - - Redo - أعد - - - Cu&t - قط&ع - - - Cop&y - &نسخ - - - &Paste - &لصق - - - Paste Insert - ألصق أدرج - - - Duplicate - أستنساخ - - - Delete - حذف - - - Ripple Delete - حذف موجة - - - Split - أنقسام - - - - Select &All - تحديد &الكل - - - - Deselect All - إلغاء تحديد الكل - - - Add Default Transition - أضف اﻷنتقال الأفتراضي - - - Link/Unlink - ربط/فصل - - - Enable/Disable - تفعيل/تعطيل - - - Nest - للمراجعة - تداخل - - - - 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 - تعقب السطور - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - 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 - محرر المخطط - - - - Node 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 - فعّل السحب - - - - Auto-Cut Silence - - - - Selecting Also Seeks - للمراجعة - تحديد العروضات إيضاً - - - Edit Tool Also Seeks - أداة التحرير تعرض إيضاً - - - Edit Tool Selects Links - أداة التحرير تحدد الروابط - - - Seek Also Selects - للمراجعة - العرض يحدد إيضاً - - - Seek to the End of Pastes - أعرض لنهاية الملصوقات - - - Scroll Wheel Zooms - العجلة الدوراة تُقرّب - - - 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> - <غير معنون> - - - Open Project... - أفتح مشروع... - - - Missing recent project - مشروع ماضي ضائع - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - المشروع '%1' غير بعد اﻷن. هل ترغب بحذفه من من قائمة مشاريع مؤخراً؟ - - - 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): - - - Nested Sequence - مقطع متشعب - - - - Marker - - - - Set Marker - ضع وسم - - - - Set clip marker name: - ضع أسم وسم المقطوعة: - - - - Set sequence marker name: - ضع أسم وسم المقطع: - - - - Media - - - New Folder - مجلد جديد - - - - Name: - اﻷسم: - - - - Filename: - أسم الملف: - - - - Video Dimensions: - أبعاد الفيديو: - - - - Frame Rate: - معدل اﻹطارات: - - - %1 fields (%2 frames) - %1 الحقل (%2 إطارات) - - - - %1 field(s) (%2 frame(s)) - - - - - 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إطار/ث - - - Audio %1: %2Hz %3 channels - الصوت %1: %2هرتز %3 قنوات - - - - Audio %1: %2Hz %3 - - - - - %n channel(s) - - - - - - - - - - - - Conform to Frame Rate: - المصادقة لمستوى اﻹطارات: - - - - Alpha is Premultiplied - ألفا مضاعفة مسبقاً - - - - Auto (%1) - تلقائي (%1) - - - - Interlacing: - المشابكة: - - - - Color Space: - - - - - 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 - فلم 4K - - - - TV 4K (Ultra HD/2160p) - 4K تلفاز (أقصى-عالي الدقة/2160p) - - - - 1080p - - - - - 720p - - - - - 480p - - - - - 360p - - - - - 240p - - - - - 144p - - - - - NTSC (480i) - - - - - PAL (576i) - - - - - Custom - مخصوص - - - - Video - فيديو - - - - Width: - العرض: - - - - Height: - الطول: - - - - Frame Rate: - معدل اﻹطارات: - - - - Pixel Aspect Ratio: - للمراجعة - معدل نسبة البيكسل: - - - - Square Pixels (1.0) - بكسيل مربع (1.0) - - - - Interlacing: - المشابكة: - - - - None (Progressive) - لا شيء (متفاقم) - - - - Audio - الصوت - - - - Sample Rate: - معدل الإعتيان: - - - - Name: - اﻷسم: - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - عطّل اﻹطارت المفتاحية - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - تعطيل اﻹطارات المفتاحية سوف يحذف جميع اﻹطارات المفتاحية الحالية هل أنت متأكد من ما ستقدم عليه؟ - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - الوسائط - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - أحفظ أعدادات المؤثر - - - - - Effect XML Settings %1 - غير إعدادات XML %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. - ملف اﻷعدادات هذا لا يطابق هذا المؤثر. - - - - OliveGlobal - - - Olive Project %1 - - - - - Auto-recovery - اﻷستعادة التلقائية - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - زيتون لم يغلق بشكل سليم وتم التعرف على ملف اﻷستعادة التلقائة. هل تريد فتحه؟ - - - - 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 - أفعل هذا مع كل التعارضات الموجودة - - - - 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? - هذا المشروع غُيِرَ منذ أخر مرة. أتريد حفظه قبل اﻹغلاق؟ - - - - Import media... - أستيراد وسائط... - - - - All Files - كل الملفات - - - - No active sequence - لا مقاطع نشطة - - - - Please open the sequence to perform this action. - - - - - No clips selected - - - - - Select the clips you wish to auto-cut - - - - Please open the sequence you wish to export. - رجاءً أفتح المقطع المراد تصديره. - - - - Missing Project File - - - - - Specified project '%1' does not exist. - - - - - PanEffect - - - - Pan - بحاجة لمتابعة - تسطّح - - - - Modifying the panning on a stereo audio clip. - - - - - Playback - - Generating Proxy: %1% - توليد وسيط: %1% - - - - PreferencesDialog - - - Preferences - التفضيلات - - - - Invalid CSS File - ملف CSS غير صالح - - - - CSS file '%1' does not exist. - ملف CSS '%1' غير موجود. - - - Warning - تحذير - - - Some changed settings will require restarting Olive to take effect - بعض اﻹعدادات المعدلة تتطلب من زيتون إعادة التشغيل لتأخذ تأثيرها - - - - 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 - - - - - Language: - اللغة: - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - Default Sequence Settings - - - - - Add Default Effects to New Clips - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - 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 - - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - أسمح بسحب الملفات للخط الزمني - - - - Auto-Scale By Default - التحجيم-التلقائي إفتراضياً - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - حكّ شريط الصوت - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - فعّل التركيز الحائم - - - - Ask For Name When Setting Marker - أسال عن اﻷسم حين وضع المؤشر - - - - Appearance - - - - - Theme - - - - - Olive Dark (Default) - - - - - Olive Light - - - - - Native - - - - - Native (Light Icons) - - - - - Use Native Menu Styling - - - - - Custom CSS: - CSS مخصوص: - - - - - Browse - تصفّح - - - - Image sequence formats: - صيغ صور المقاطع: - - - - Audio Recording: - تسجيل الصوت: - - - - Mono - اُحادي - - - - Stereo - مُجسم - - - - Effect Textbox Lines: - للمراجعة - أثر بسطور صندوق النص: - - - - Default Sequence - - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - دقّة الصورة المصغرة: - - - - Waveform Resolution: - دقّة الشكل الموجي: - - - - Delete Previews - - - - - Use Software Fallbacks When Possible - أستعمل معالجة البرمجيات حين اﻹمكان - - - - General - عام - - - - Behavior - السلوك - - - Disable Multithreading on Images - عطل تعدد المعالجات بالصور - - - 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 - الصوت - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - 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 - - - New - جديد - - - - Open Project - - - - - Save Project - - - - - Undo - - - - - Redo - أعد - - - - Tree View - مظهر الشجرة - - - - Icon View - مظهر الإيقونات - - - - List View - - - - - 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 - تخطى - - - 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. - لا مقطع نشط, رجاءً أفتح المقطع المراد حذف جزء منه. - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - - - - - Image sequence detected - تم التعرف على مقاطع صور - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - الملف '%1' يبدو كأنه جزء من سلسلة صور. هل تريد أستيراده هكذا؟ - - - - 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 - عتمة الظل - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - %1 (نسخ) - - - - ShakeEffect - - - Intensity - للمراجعة(كثافة أم شدة) - الكثافة - - - - Rotation - الدوران - - - - Frequency - التردد - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - النوع - - - - Solid Color - لون صلب - - - - SMPTE Bars - ألواح SMPTE - - - - Checkerboard - لوح التدقيق - - - - Opacity - العتمة - - - - Color - اللون - - - - Checkerboard Size - حجم لوح التدقيق - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - أستيراد... - - - - New - جديد - - - - View - أظهر - - - - Tree View - مظهر الشجرة - - - - Icon View - مظهر الإيقونات - - - - Show Toolbar - أظهر لوح اﻷدوات - - - - Show Sequences - أظهر المقاطع - - - - Replace/Relink Media - أستبدل/أعد ربط الوسائط - - - - Reveal in Explorer - أظهر في الكاشف - - - - Reveal in 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 '%1' - أستبدل '%1' - - - - All Files - كل الملفات - - - - 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 - عدّل النص - - - - Thin - - - - - Extra Light - - - - - Light - - - - - Normal - عادي - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - عدّل النص - - - - &Edit Text - &عدل النص - - - - TextEffect - - - - Text - النص - - - - Font - الخط - - - - Size - الحجم - - - - Color - اللون - - - Alignment - محاذاة - - - - Horizontal Alignment - - - - - Left - يسار - - - - - Center - المركز - - - - Right - يمين - - - - Justify - تسوية - - - - Vertical Alignment - - - - - Top - أعلى - - - - Bottom - القاع - - - - Word Wrap - لُف الكلمة - - - - Padding - - - - - Position - الموضع - - - - Outline - الخلاصة - - - - Outline Color - لون الخلاصة - - - - Outline Width - عرض الخلاصة - - - - Shadow - الظل - - - - Shadow Color - لون الظل - - - - Shadow Angle - - - - - Shadow Distance - مسافة الظل - - - - Shadow Softness - نعومة الظل - - - - Shadow Opacity - عتمة الظل - - - - Sample Text - عينة نص - - - - Render - - - - - Generate simple text over this clip - - - - &Edit Text - &عدل النص - - - - TimecodeEffect - - - - Timecode - شفرة الوقت - - - - Sequence - مقطع - - - - Media - الوسائط - - - - Scale - المقياس - - - - Color - اللون - - - - Background Color - لون الخلفية - - - - Background Opacity - عتمة الخلفية - - - - Offset - اﻷزاحة - - - - Prepend - باحجة للمراجعة - البادئة - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - Timeline: - الخط الزمني: - - - <none> - <لا شيء> - - - - 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) - أنقر على الخط الزمني حيث تريد بدء التسجيل (أسحب لوضع حد للتسجيل في إطار وقت معين) - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (لا شيء) - - - - 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. - أضف عنوان, صلب, ألواح, إلخ. - - - - TimelineHeader - - - Center Timecodes - وسّط رمز الوقت - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - &تراجع - - - - &Redo - &أعد - - - - R&ipple Delete Empty Space - - - - - Sequence Settings - اﻷعدادات المقطع - - - - &Speed/Duration - &السرعة/المدّة - - - - Auto-Cut Silence - - - - - 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: - المدة: - - - - TimelineWidget - - - &Undo - &تراجع - - - - &Redo - &أعد - - - C&ut - قط&ع - - - Cop&y - &نسخ - - - &Paste - &لصق - - - R&ipple Delete - حذف مو&جة - - - - Sequence Settings - اﻷعدادات المقطع - - - - &Speed/Duration - &السرعة/المدّة - - - Auto-s&cale - التحجيم-التلقا&ئي - - - Enable/Disable - تفعيل/تعطيل - - - Link/Unlink - ربط/فصل - - - &Nest - &تداخل - - - - &Reveal in Project - &أبرّز في المشروع - - - R&ename - أ&عد تسمية - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -بدء: %2 -أنتهاء: %3 -المدة: %4 - - - Rename '%1' - أعد تسمية '%1' - - - Rename multiple clips - أعد تسمية عدة مقاطع - - - Enter a new name for this clip: - أدخل أسم جديد لهذا المقطع: - - - - R&ipple Delete Empty Space - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - Properties - - - - - Error - خطأ - - - - Couldn't locate media wrapper for sequence. - لم يتم رصد موقع غلاف الوسائط للمقطع. - - - - Title - عنوان - - - - Solid Color - لون صلب - - - - Bars - ألواح - - - - Tone - نغّم - - - - Noise - ضجيج - - - - Duration: - المدة: - - - - ToneEffect - - - Type - نوع - - - - Sine - - - - - Frequency - التردد - - - - Amount - مقدار - - - - Mix - دمج - - - - Tone - نغّم - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - الموضع - - - - Scale - المقياس - - - - Uniform Scale - المقياس الموحد - - - - Rotation - الدوران - - - - Anchor Point - نقطة المرساة - - - - Opacity - العتمة - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - 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: - الطول: - - - - Length - - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - - - - - 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. - ملحوظة: لا يمكنك تحميل إضافة VST 32-بت لنسخة زيتون مبنية ل64-بت. رجاءً جد نسخة 64-بت من هذه الإضافة أو أنتقل لنسخة زيتون مبنية على 32-بت. - - - 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. - ملحوظة: لا يمكنك تحميل إضافة VST 64-بت لنسخة زيتون مبنية ل32-بت. رجاءً جد نسخة 32-بت من هذه الإضافة أو أنتقل لنسخة زيتون مبنية على 64-بت. - - - - Failed to locate entry point for dynamic library. - - - - - VST Error - خطأ VST - - - - Plugin's magic number is invalid - رقم اﻹضافة السحري غير صالح - - - - Plugin - إضافة - - - - Interface - واجهة - - - - Show - أظهر - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - إضافة VST - - - - Viewer - - Sequence Viewer - عارض المقطع - - - Media Viewer - عارض الوسائط - - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (لا شيء) - - - - Drag video only - - - - - Drag audio only - - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - 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 - درجة الصوت - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - - transition - - Invalid transition - أنتقال غير صالح - - - No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. - لا مرشح للأنتقال '%1'. هذه اﻷنتقالة قد تكون فاسدة. جرب إعادة تثبيتها أو زيتون. - - - diff --git a/ts/olive_bs.ts b/ts/olive_bs.ts deleted file mode 100644 index 081f4188d..000000000 --- a/ts/olive_bs.ts +++ /dev/null @@ -1,4362 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - To the best of my knowledge, there is no translation for free as in libre that sounds quite as nicely as slobodan. - Olive je nelinearni video uređivač. Ovaj software je slobodan i zaštićen GNU GPL-om. - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - Olive tim je pod obavezom da obavijesti svoje korisnike da je Olive-ov izvorni kod dostupan za preuzimanje sa njegove web stranice - - - - ActionSearch - - - Search for action... - Potražite radnju... - - - - AdvancedVideoDialog - - - Advanced Video Settings - Napredne video postavke - - - - Pixel Format: - Format piksela: - - - - Threads: - - - - - Audio - - Audio - Audio - - - Recording - Snimanje - - - - %1 Audio - %1 Audio - - - - Recording %1 - Snimanje %1 - - - - AudioNoiseEffect - - - Amount - Količina - - - - Mix - Miks - - - - Noise - - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - - - - - Attack Threshold: - - - - - Attack Time: - - - - - Release Threshold: - - - - - Release Time: - - - - - Cacher - - - - Could not open %1 - %2 - - - - - ChannelLayoutName - - - Invalid - Nevažeće - - - - Mono - Mono - - - - Stereo - Stereo - - - - ClipPropertiesDialog - - - "%1" Properties - - - - - Multiple Clip Properties - - - - - Name: - - - - - Duration: - - - - - (multiple) - - - - - CollapsibleWidget - - - <untitled> - <neimenovano> - - - - ColorButton - - - Set Color - Postavi boju - - - - CornerPinEffect - - - Top Left - Gornje lijevo - - - - Top Right - Gornje desno - - - - Bottom Left - Donje lijevo - - - - Bottom Right - Donje desno - - - - Perspective - Perspektiva - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - DebugDialog - - - Debug Log - Zapis za debugiranje - - - - DemoNotice - - - - Welcome to Olive! - Dobrodošli u 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 je slobodan video uređivač sa otvorenim izvornim kodom izdan pod GNU GPL-om. Ako ste platili za ovaj software, vi ste bili prevareni. - - - - 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 - Ovaj software je trenutno u ALFA stanju, što znači da je nestabilan i veoma je vjerovatno da će se srušiti, imati greške i da ne dostaje nekih mogućnosti. Mi ne dajemo nikakvu garanciju, tako da koristite na svoj sopstveni rizik. Molimo da prijavite sve greške i željene funkcije na %1 - - - - Thank you for trying Olive and we hope you enjoy it! - Hvala što isprobavate Olive i nadamo se da ćete uživati u njemu! - - - - Effect - - Invalid effect - Nevažeći efekat - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - Nema kandidata za efekat '%1'. Moguće je da je ovaj efekat koruptiran. Pokušajte ponovno instalirati njega ili Olive. - - - Cu&t - I'll have to check back on this later to see how it works with the keyboard in practice - &Reži - - - &Copy - &Kopiraj - - - Move &Up - Pomjeri &gore - - - Move &Down - Pomjeri &dolje - - - D&elete - &Obriši - - - Load Settings From File - Učitaj postavke iz datoteke - - - Save Settings to File - Spasi postavke u datoteku - - - Save Effect Settings - Spasi postavke efekata - - - Effect XML Settings %1 - XML postavke-efekta %1 - - - Save Settings Failed - Spašavanje postavki neuspješno - - - Failed to open "%1" for writing. - Neuspješno otvaranje "%1" za uređivanje. - - - Load Effect Settings - Učitaj postavke efekta - - - Load Settings Failed - Učitavanje postavki neuspješno - - - Failed to open "%1" for reading. - Neuspješno otvaranje "%1" za čitanje. - - - This settings file doesn't match this effect. - Ova datoteka postavki nije prikladna za ovaj efekat. - - - - EffectControls - - - Effects: - Efekti: - - - &Paste - &Zalijepi - - - - (none) - (nema) - - - - Add Video Effect - Dodaj video efekat - - - - VIDEO EFFECTS - VIDEO EFEKTI - - - - Add Video Transition - Dodaj video prelaz - - - - Add Audio Effect - Dodaj audio efekat - - - - AUDIO EFFECTS - AUDIO EFEKTI - - - - Add Audio Transition - Dodaj audio prelaz - - - (Multiple clips selected) - (Vše snimki je odabrano) - - - - EffectRow - - Disable Keyframes - Onemogući ključne kadrove - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Onemogućavanje ključnih kadrova će obrisati sve trenutne ključne kadrove. Da li ste sigurni da želite ovo uraditi? - - - - EffectUI - - - %1 (Opening) - - - - - %1 (Closing) - - - - - %1 (multiple) - - - - - Cu&t - &Reži - - - - &Copy - &Kopiraj - - - - Move &Up - Pomjeri &gore - - - - Move &Down - Pomjeri &dolje - - - - D&elete - &Obriši - - - - Load Settings From File - Učitaj postavke iz datoteke - - - - Save Settings to File - Spasi postavke u datoteku - - - - EmbeddedFileChooser - - - File: - Datoteka: - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - Izvoz "%1" - - - - Unknown codec name %1 - Nepoznato ime kodeka %1 - - - - Export Failed - Izvoz neuspješan - - - - Export failed - %1 - Izvoz neuspješan - %1 - - - - Invalid dimensions - Nevažeće dimenzije - - - - Export width and height must both be even numbers/divisible by 2. - Visina i širina izvoza obje moraju biti parni brojevi/djeljive sa dva. - - - - Invalid codec - Nevažeći kodek - - - - Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. - Parametri odabranog kodeka se nisu mogli odrediti. Ovo je greška, molimo da kontaktirate developere. - - - - Invalid format - Nevažeći format - - - - Couldn't determine output format. This is a bug, please contact the developers. - Izlazni format se nije mogao odrediti. Ovo je greška, molimo da kontaktirate developere. - - - - Export Media - Izvoz medija - - - - %p% (Total: %1:%2:%3) - - - - - %p% (ETA: %1:%2:%3) - - - - - Quality-based (Constant Rate Factor) - Bazirano na kvaliteti (Faktor stalne stope/Constant Rate Factor) - - - - Constant Bitrate - Stalna stopa bitova - - - - - Invalid Codec - Nevažeći kodek - - - - Failed to find a suitable encoder for this codec. Export will likely fail. - Traganje za prikladnim koderom za ovaj kodek nije uspjelo. Izvoz najvjerovatnije neće uspjeti. - - - - Failed to find pixel format for this encoder. Export will likely fail. - Traganje za prikladnim formatom piksela za ovaj kodek nije uspjelo. Izvoz najvjerovatnije neće uspjeti. - - - - Bitrate (Mbps): - Stopa bitova (Mbps): - - - - Quality (CRF): - Kvaliteta (CRF): - - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - Faktor kvalitete: - -0 = besprijekorno -17-18 = oku besprijekorno (komprimirano, ali neprimjetno) -23 = visoka kvaliteta -51 = najniža kvaliteta moguća - - - - Target File Size (MB): - Željena veličina datoteke (MB): - - - - Format: - Format: - - - - Range: - Raspon: - - - - Entire Sequence - Čitava sekvenca - - - - In to Out - I have no clue what to call this really, it only plays sound, but that's not in the name, so I can't mention sound, so I assume that "in" and "out" reference the in and out points respectively. - Od početka do kraja - - - - Video - Video - - - - - Codec: - Kodek: - - - - Width: - Širina: - - - - Height: - Visina: - - - - Frame Rate: - Okvirna stopa: - - - - Compression Type: - Tip komprimacije: - - - - Advanced - Napredno - - - - Audio - Audio - - - - Sampling Rate: - Stopa uzoraka: - - - - Bitrate (Kbps/CBR): - Stopa bitova (Kbps/CBR): - - - - ExportThread - - - failed to send frame to encoder (%1) - Slanje okvira koderu nije uspjelo (%1) - - - - failed to receive packet from encoder (%1) - Primanje paketa od kodera nije uspjelo (%1) - - - - could not video encoder for %1 - Nije mogao video koder za %1 - - - - could not allocate video stream - Video tok se nije mogao zauzeti - - - - could not allocate video encoding context - Kontekst video kodiranja se nije moago zauzeti - - - - could not open output video encoder (%1) - Izlazni video koder se nije moago otvoriti (%1) - - - - could not copy video encoder parameters to output stream (%1) - Parametri video kodera se nisu mogli kopirati u izlazni tok (%1) - - - - could not audio encoder for %1 - Not sure if there should be anything in between "not" and "audio" - Nije mogao audio koder za %1 - - - - could not allocate audio stream - Audio tok se nije mogao zauzeti - - - - could not allocate audio encoding context - Kontekst audio kodiranja se nije mogao zauzeti - - - - could not open output audio encoder (%1) - Izlaz audio kodera se nije mogao otvoriti (%1) - - - - could not copy audio encoder parameters to output stream (%1) - Parametri audio kodera se nisu mogli kopirati u izlazni tok (%1) - - - - could not allocate audio buffer (%1) - Audio međuspremnik se nije mogao zauzeti (%1) - - - - could not create output format context - Kontekst izlaznog formata se nije mogao stvoriti - - - - could not open output file (%1) - Izlazna datoteka se nije mogla otvoriti (%1) - - - - could not write output file header (%1) - Zaglavlje izlazne datoteke se nije moglo ispisati (%1) - - - - could not write output file trailer (%1) - Zaglavlje izlazne datoteke se nije moglo ispisati (%1) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Tip - - - - Fill Left with Right - Popuni lijevo sa desnim - - - - Fill Right with Left - Popuni desno sa lijevim - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - Not sure if that's completely accurate, as I have not seen this dialog and the text itself is somewhat ambiguous regarding the placeholders' functions - Učitavanje Frei0r dodatka nije uspjelo "%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. - PAŽNJA: Vi ne možete učitavati 32-bitne Frei0r dodatke u 64-bitno izdanje Olive-a. Molimo nađite 64-bitno izdanje ovih dodataka, ili pređite na 32-bitno izdanje Olive-a. - - - 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. - PAŽNJA: Vi ne možete učitavati 64-bitne Frei0r dodatke u 32-bitno izdanje Olive-a. Molimo nađite 32-bitno izdanje ovih dodataka, ili pređite na 64-bitno izdanje Olive-a. - - - - Error loading Frei0r plugin - Greška pri učitavanju Frei0r dodataka - - - - GraphEditor - - - Graph Editor - Uređivač grafikona - - - - Linear - Linearno - - - - Bezier - Bezier - - - - Hold - Drži - - - - GraphView - - - Zoom to Selection - Povećaj ka odabiru - - - - Zoom to Show All - Povećaj ka svemu - - - - Reset View - Vrati prvobitni prikaz - - - - InterlacingName - - - None (Progressive) - Nema (progresivno) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - Gornje polje prvo - - - Bottom Field First - Donje polje prvo - - - - Invalid - Nevažeće - - - - KeyframeNavigator - - - Enable Keyframes - Omogući ključne kadrove - - - - KeyframeView - - - Linear - Linearno - - - - Bezier - Bezier - - - - Hold - Drži - - - - LabelSlider - - - &Edit - - - - - &Reset to Default - - - - - - Set Value - Odredi vrijednost - - - - - New value: - Nova vrijednost: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - LoadDialog - - - Loading... - Učitavanje... - - - - Loading '%1'... - Učitavanje "%1"... - - - - Cancel - Prekini - - - - LoadThread - - - Version Mismatch - Verzije se ne poklapaju - - - - 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? - Ovaj projekat je bio spašen u drugačijoj verziji Olive-a i moguće je da nije u potpunosti kompatibilan sa ovom verzijom. Da li još uvijek želite probati učitati projekat? - - - Invalid Clip Link - Nevažeća veza snimke - - - This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? - Ovaj projekat sadrži nevažeću vezu snimke. Moguće je da je koruptiran. Da li biste htjeli da ga nastavite učitavati? - - - - %1 - Line: %2 Col: %3 - %1 - Red: %2 Kolona: %3 - - - - User aborted loading - Korisnik je prekinuo učitavanje - - - - XML Parsing Error - Greška u parsiranju XML-a - - - - Couldn't load '%1'. %2 - "%1": %2 se nije moglo učitati - - - - Project Load Error - Greška pri učitavanju projekta - - - - Error loading project: %1 - Greška pri učitavanju projekta: %1 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - - Welcome to %1 - Dobrodišli u %1 - - - Auto-recovery - Automatski oporavak - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive se nije pravilno zatvorio i datoteka za automatsko obnavljanje je primjećena. Da li želite da ju otvorite? - - - - &File - - - - - &New - - - - - &Open Project - - - - - Clear Recent List - - - - - Open Recent - - - - - &Save Project - - - - - Save Project &As - - - - - &Import... - - - - - &Export... - - - - - E&xit - - - - - &Edit - - - - - &Undo - - - - - Redo - - - - Cu&t - &Reži - - - &Paste - &Zalijepi - - - - 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 - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - - - - - Frames - - - - - Drop Frame - - - - - Non-Drop Frame - - - - - Milliseconds - - - - - Title/Action Safe Area - - - - - Off - - - - - Default - - - - - 4:3 - - - - - 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 - Uređivač grafikona - - - - Node 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 - - - - - Auto-Cut Silence - - - - - No Auto-Scroll - - - - - Page Auto-Scroll - - - - - Smooth Auto-Scroll - - - - - Preferences - - - - - Clear Undo - - - - - &Help - - - - - A&ction Search - - - - - Debug Log - Zapis za debugiranje - - - - &About... - - - - - <untitled> - <neimenovano> - - - - Marker - - - - Set Marker - - - - - Set clip marker name: - - - - - Set sequence marker name: - - - - - Media - - - New Folder - - - - - Name: - - - - - Filename: - - - - - Video Dimensions: - - - - - Frame Rate: - Okvirna stopa: - - - - %1 field(s) (%2 frame(s)) - - - - - Interlacing: - - - - - Audio Frequency: - - - - - Audio Channels: - - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - - - - - Name - - - - - Duration - - - - - Rate - - - - - MediaPropertiesDialog - - - "%1" Properties - - - - - Tracks: - - - - - Video %1: %2x%3 %4FPS - - - - - Audio %1: %2Hz %3 - - - - - %n channel(s) - - - - - - - - - Conform to Frame Rate: - - - - - Alpha is Premultiplied - - - - - Auto (%1) - - - - - Interlacing: - - - - - Color Space: - - - - - 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 - &Reži - - - - Cop&y - - - - - - &Paste - &Zalijepi - - - - Paste Insert - - - - - Duplicate - - - - - Delete - - - - - Ripple Delete - - - - - Split - - - - - Invalid aspect ratio - - - - - The aspect ratio '%1' is invalid. Please try again. - - - - - Enter custom aspect ratio - - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - - - - - NewSequenceDialog - - - Editing "%1" - - - - - New Sequence - - - - - Preset: - - - - - Film 4K - - - - - TV 4K (Ultra HD/2160p) - - - - - 1080p - - - - - 720p - - - - - 480p - - - - - 360p - - - - - 240p - - - - - 144p - - - - - NTSC (480i) - - - - - PAL (576i) - - - - - Custom - - - - - Video - Video - - - - Width: - Širina: - - - - Height: - Visina: - - - - Frame Rate: - Okvirna stopa: - - - - Pixel Aspect Ratio: - - - - - Square Pixels (1.0) - - - - - Interlacing: - - - - - None (Progressive) - Nema (progresivno) - - - - Audio - Audio - - - - Sample Rate: - - - - - Name: - - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - Onemogući ključne kadrove - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Onemogućavanje ključnih kadrova će obrisati sve trenutne ključne kadrove. Da li ste sigurni da želite ovo uraditi? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - Spasi postavke efekata - - - - - Effect XML Settings %1 - XML postavke-efekta %1 - - - - Save Settings Failed - Spašavanje postavki neuspješno - - - - Failed to open "%1" for writing. - Neuspješno otvaranje "%1" za uređivanje. - - - - Load Effect Settings - Učitaj postavke efekta - - - - - Load Settings Failed - Učitavanje postavki neuspješno - - - - Failed to open "%1" for reading. - Neuspješno otvaranje "%1" za čitanje. - - - - This settings file doesn't match this effect. - Ova datoteka postavki nije prikladna za ovaj efekat. - - - - OliveGlobal - - - Olive Project %1 - - - - - Auto-recovery - Automatski oporavak - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive se nije pravilno zatvorio i datoteka za automatsko obnavljanje je primjećena. Da li želite da ju otvorite? - - - - 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? - - - - - Add - - - - - Replace - - - - - Skip - - - - - Do this for all conflicts found - - - - - Open Project... - - - - - Missing recent project - - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - - - - - Save Project As... - - - - - Unsaved Project - - - - - This project has changed since it was last saved. Would you like to save it before closing? - - - - - Import media... - - - - - All Files - - - - - No active sequence - - - - - Please open the sequence to perform this action. - - - - - No clips selected - - - - - Select the clips you wish to auto-cut - - - - - Missing Project File - - - - - Specified project '%1' does not exist. - - - - - PanEffect - - - - Pan - - - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - - Preferences - - - - - Default Sequence - - - - - Invalid CSS File - - - - - CSS file '%1' does not exist. - - - - - 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 - - - - - Delete All Previews - - - - - Are you sure you want to delete all previews? - - - - - Previews Deleted - - - - - Language: - - - - - Default Sequence Settings - - - - - Add Default Effects to New Clips - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - 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 - - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - - - - - Auto-Scale By Default - - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - - - - - Ask For Name When Setting Marker - - - - - Appearance - - - - - Theme - - - - - Olive Dark (Default) - - - - - Olive Light - - - - - Native - - - - - Native (Light Icons) - - - - - Use Native Menu Styling - - - - - Custom CSS: - - - - - - Browse - - - - - Image sequence formats: - - - - - Audio Recording: - - - - - Mono - Mono - - - - Stereo - Stereo - - - - Effect Textbox Lines: - - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - - - - - Waveform Resolution: - - - - - Delete Previews - - - - - Use Software Fallbacks When Possible - - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - General - - - - - Behavior - - - - - Memory Usage - - - - - Upcoming Frame Queue: - - - - - - frames - - - - - - seconds - - - - - Previous Frame Queue: - - - - - Playback - - - - - Output Device: - - - - - - Default - - - - - Input Device: - - - - - Sample Rate: - - - - - Audio - Audio - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - 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 - - - - - Could not find stream information - %1 - - - - - Project - - - New - - - - - Open Project - - - - - Save Project - - - - - Undo - - - - - Redo - - - - - Tree View - - - - - Icon View - - - - - List View - - - - - Search media, markers, etc. - - - - - Project - - - - - - 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' - - - - - 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? - - - - - Skip - - - - - No sequence is active, please open the sequence you want to delete clips from. - - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - - - - - Image sequence detected - - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - - - - - ProxyDialog - - - Create Proxy - - - - - Proxy - - - - - Dimensions: - - - - - Same Size as Source - - - - - Half Resolution (1/2) - - - - - Quarter Resolution (1/4) - - - - - Eighth Resolution (1/8) - - - - - Sixteenth Resolution (1/16) - - - - - Format: - Format: - - - - ProRes HQ - - - - - Location: - - - - - Same as Source (in "%1" folder) - - - - - Proxy file exists - - - - - The file "%1" already exists. Do you wish to replace it? - - - - - Custom Location - - - - - ProxyGenerator - - - Finished generating proxy for "%1" - - - - - ReplaceClipMediaDialog - - - Replace clips using "%1" - - - - - Select which media you want to replace this media's clips with: - - - - - Keep the same media in-points - - - - - Replace - - - - - Cancel - Prekini - - - - 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 - - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - - - - - ShakeEffect - - - Intensity - - - - - Rotation - - - - - Frequency - - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Tip - - - - Solid Color - - - - - SMPTE Bars - - - - - Checkerboard - - - - - Opacity - - - - - Color - - - - - Checkerboard Size - - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - - - - - New - - - - - View - - - - - Tree View - - - - - Icon View - - - - - Show Toolbar - - - - - Show Sequences - - - - - Replace/Relink Media - - - - - Reveal in Explorer - - - - - Reveal in 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 - - - - - Create/Modify Proxy - - - - - Create Proxy - - - - - Modify Proxy - - - - - Restore Original - - - - - Delete - - - - - Preview in Media Viewer - - - - - Properties... - - - - - Replace '%1' - - - - - All Files - - - - - Replace Media - - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - - - - - Delete proxy - - - - - Would you like to delete the proxy file "%1" as well? - - - - - SpeedDialog - - - Speed/Duration - - - - - Speed: - - - - - Frame Rate: - Okvirna stopa: - - - - Duration: - - - - - Reverse - - - - - Maintain Audio Pitch - - - - - Ripple Changes - - - - - TextEditDialog - - - Edit Text - - - - - Thin - - - - - Extra Light - - - - - Light - - - - - Normal - - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - - - - - &Edit Text - - - - - TextEffect - - - - Text - - - - - Font - - - - - Size - - - - - Color - - - - - Horizontal Alignment - - - - - Left - - - - - - Center - - - - - Right - - - - - Justify - - - - - Vertical Alignment - - - - - Top - - - - - Bottom - - - - - Word Wrap - - - - - Padding - - - - - Position - - - - - Outline - - - - - Outline Color - - - - - Outline Width - - - - - Shadow - - - - - Shadow Color - - - - - Shadow Angle - - - - - Shadow Distance - - - - - Shadow Softness - - - - - Shadow Opacity - - - - - Sample Text - - - - - Render - - - - - Generate simple text over this clip - - - - - TimecodeEffect - - - - Timecode - - - - - Sequence - - - - - Media - - - - - Scale - - - - - Color - - - - - Background Color - - - - - Background Opacity - - - - - Offset - - - - - Prepend - - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - - Nested Sequence - - - - - 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) - - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (nema) - - - - 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. - - - - - TimelineHeader - - - Center Timecodes - - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - - - - - &Redo - - - - - R&ipple Delete Empty Space - - - - - Sequence Settings - - - - - &Speed/Duration - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - &Reveal in Project - - - - - Properties - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - - - - - Error - - - - - Couldn't locate media wrapper for sequence. - - - - - Title - - - - - Solid Color - - - - - Bars - - - - - Tone - - - - - Noise - - - - - Duration: - - - - - TimelineWidget - - - &Undo - - - - - &Redo - - - - &Paste - &Zalijepi - - - - Sequence Settings - - - - - &Speed/Duration - - - - - &Reveal in Project - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - - - - - R&ipple Delete Empty Space - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - Properties - - - - - Error - - - - - Couldn't locate media wrapper for sequence. - - - - - Title - - - - - Solid Color - - - - - Bars - - - - - Tone - - - - - Noise - - - - - Duration: - - - - - ToneEffect - - - Type - Tip - - - - Sine - - - - - Frequency - - - - - Amount - Količina - - - - Mix - Miks - - - - Tone - - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - - - - - Scale - - - - - Uniform Scale - - - - - Rotation - - - - - Anchor Point - - - - - Opacity - - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - - Transition - - - Length - - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - - - - - VSTHost - - - - Error loading VST plugin - - - - - Failed to load VST plugin "%1": %2 - - - - - Failed to locate entry point for dynamic library. - - - - - VST Error - - - - - Plugin's magic number is invalid - - - - - Plugin - - - - - Interface - - - - - Show - - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - - - - - Viewer - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (nema) - - - - Drag video only - - - - - Drag audio only - - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - - - - - Show Fullscreen - - - - - Disable - - - - - Screen %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 - - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - diff --git a/ts/olive_cs.ts b/ts/olive_cs.ts deleted file mode 100644 index 2bb4bf754..000000000 --- a/ts/olive_cs.ts +++ /dev/null @@ -1,3841 +0,0 @@ - - - - - AboutDialog - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - Olive je nelineární editor obrazového záznamu. Tento program je zdarma a chráněn GNU GPL. - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - Družstvo Olive se dává na vědomí, že zdrojové kódy Olive jsou dostupné pro stažení na internetové stránce projektu. - - - - ActionSearch - - Search for action... - Hledat činnost... - - - - AdvancedVideoDialog - - Advanced Video Settings - Pokročilá nastavení obrazu - - - Pixel Format: - Formát pixelu: - - - Threads: - - - - - Audio - - %1 Audio - %1 Zvuk - - - Recording %1 - Nahrávání %1 - - - - AudioNoiseEffect - - Mix - Smíchat - - - Amount - Množství - - - Noise - Šum - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - Cut Silence - - - - Attack Threshold: - - - - Attack Time: - - - - Release Threshold: - - - - Release Time: - - - - - Cacher - - Could not open %1 - %2 - - - - - ChannelLayoutName - - Mono - Mono - - - Invalid - Neplatný - - - Stereo - Stereo - - - - ClipPropertiesDialog - - "%1" Properties - "%1" Vlastnosti - - - Multiple Clip Properties - - - - Name: - Název: - - - Duration: - Doba trvání: - - - (multiple) - - - - - CollapsibleWidget - - <untitled> - - - - - ColorButton - - Set Color - Nastavit barvu - - - - CornerPinEffect - - Top Right - Nahoře vpravo - - - Bottom Left - Dole vlevo - - - Top Left - Nahoře vlevo - - - Perspective - Perspektiva - - - Bottom Right - Dole vpravo - - - Corner Pin - - - - Distort - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - Cross Dissolve - - - - Dissolves - - - - Dissolve clips evenly. - - - - - DebugDialog - - Debug Log - Zápis ladění - - - - DemoNotice - - Welcome to Olive! - Vítejte v Olive! - - - 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 - Tento program je v současnosti v Alfa verzi, což znamená, že je nestálý a velice pravděpodobně náchylný k pádům, má chyby a chybí mu funkce. Není poskytována žádná záruka, takže jej používejte na vlastní nebezpečí. Hlašte, prosím, jakékoli chyby nebo žádosti o funkce na %1 - - - Thank you for trying Olive and we hope you enjoy it! - Děkujeme vám za zkoušení Olive. Přejeme si, aby vám dělal radost! - - - 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 je editor obrazového záznamu s otevřeným zdrojovým kódem vydaný pod GNU GPL. - - - - Effect - - Cu&t - Vyjmou&t - - - &Copy - &Kopírovat - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - Žádný uchazeč pro efekt '%1'. Tento přechod může být poškozen. Pokuste se jej nebo Olive znovu nainstalovat. - - - Invalid effect - Neplatný efekt - - - Load Settings From File - Nahrát nastavení ze souboru - - - Load Effect Settings - Nahrát nastavení efektu - - - Move &Up - Posunout &nahoru - - - D&elete - S&mazat - - - Move &Down - Posunout &dolů - - - Save Settings Failed - Nastavení se nepodařilo uložit - - - Save Effect Settings - Uložit nastavení efektu - - - Load Settings Failed - Nastavení se nepodařilo nahrát - - - This settings file doesn't match this effect. - Tento soubor s nastavením neodpovídá tomuto efektu. - - - Effect XML Settings %1 - Nastavení XML efektu %1 - - - Failed to open "%1" for reading. - Nepodařilo se otevřít "%1" pro čtení. - - - Save Settings to File - Uložit nastavení do souboru - - - Failed to open "%1" for writing. - Nepodařilo se otevřít "%1" pro zápis. - - - - EffectControls - - Add Audio Effect - Přidat zvukový efekt - - - Add Video Effect - Přidat obrazový efekt - - - &Paste - &Vložit - - - (none) - (žádný) - - - VIDEO EFFECTS - OBRAZOVÉ EFEKTY - - - Add Audio Transition - Přidat zvukový přechod - - - Add Video Transition - Přidat obrazový přechod - - - Effects: - Efekty: - - - (Multiple clips selected) - (vybráno více záběrů) - - - AUDIO EFFECTS - ZVUKOVÉ EFEKTY - - - - EffectRow - - Disable Keyframes - Zakázat klíčové snímky - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Zákázání klíčových snímků smaže všechny nynější klíčové snímky. Opravdu to chcete udělat? - - - - EffectUI - - %1 (Opening) - - - - %1 (Closing) - - - - %1 (multiple) - - - - Cu&t - Vyjmou&t - - - &Copy - &Kopírovat - - - Move &Up - Posunout &nahoru - - - Move &Down - Posunout &dolů - - - D&elete - S&mazat - - - Load Settings From File - Nahrát nastavení ze souboru - - - Save Settings to File - Uložit nastavení do souboru - - - - EmbeddedFileChooser - - File: - Soubor: - - - - ExponentialFadeTransition - - Exponential Fade - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - Audio - Zvuk - - - Video - Obraz - - - Sampling Rate: - Rychlost vzorkování: - - - Invalid dimensions - Neplatné rozměry - - - Export Media - Vyvést záznam - - - Invalid format - Neplatný formát - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - Faktor kvality: - -0 = bezztrátová -17-18 = beze ztrát na obraze (komprimace, ale nepozorovatelná) -23 = vysoká jakost -51 = nejnižší možná jakost - - - Constant Bitrate - Stálý datový tok - - - Codec: - Kodek: - - - Couldn't determine output format. This is a bug, please contact the developers. - Nepodařilo se určit výstupní formát. Toto je chyba. Spojte se, prosím, s vývojáři. - - - Range: - Rozsah: - - - Width: - Šířka: - - - Invalid Codec - Neplatný kodek - - - Invalid codec - Neplatný kodek - - - Frame Rate: - Snímkování: - - - Entire Sequence - Celý úryvek (sled záběrů) - - - In to Out - Vstup do výstupu - - - Export Failed - Nepodařilo se vyvést - - - Unknown codec name %1 - Neznámý název kodeku %1 - - - Target File Size (MB): - Velikost cílového souboru (MB): - - - Bitrate (Mbps): - Datový tok (MB/s): - - - Compression Type: - Typ komprese: - - - Export "%1" - Vyvést "%1" - - - Export width and height must both be even numbers/divisible by 2. - Šířka a výška pro vyvedení musí být sudá čísla dělitelná 2. - - - Quality (CRF): - Kvalita (CRF): - - - Quality-based (Constant Rate Factor) - Kvalita (Constant Rate Factor) - - - Export failed - %1 - Nepodařilo se vyvést - %1 - - - Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. - Nepodařilo se určit výstupní parametry pro vybraný kodek. Toto je chyba. Spojte se, prosím, s vývojáři. - - - Advanced - Pokročilé - - - Bitrate (Kbps/CBR): - Datový tok (KB/s/stálý datový tok): - - - Failed to find a suitable encoder for this codec. Export will likely fail. - Nepodařilo se najít vhodný kodér pro tento kodek. Vyvedení pravděpodobně selže. - - - Failed to find pixel format for this encoder. Export will likely fail. - Nepodařilo se najít formát pixelu pro tento kodér. Vyvedení pravděpodobně selže. - - - Format: - Formát: - - - Height: - Výška: - - - %p% (Total: %1:%2:%3) - - - - %p% (ETA: %1:%2:%3) - - - - - ExportThread - - could not create output format context - Nepodařilo se vytvořit kontext výstupního formátu - - - could not open output file (%1) - Nepodařilo se otevřít výstupní soubor (%1) - - - failed to receive packet from encoder (%1) - Chyba při přijetí paketu od kodéru (%1) - - - could not copy audio encoder parameters to output stream (%1) - Nepodařilo se kopírovat parametry kodéru zvuku do výstupního proudu (%1) - - - could not allocate audio encoding context - Nepodařilo se přiřadit kontext kódování zvuku - - - could not copy video encoder parameters to output stream (%1) - Nepodařilo se kopírovat parametry kodéru obrazu do výstupního proudu (%1) - - - failed to send frame to encoder (%1) - Chyba při poslání snímku kodéru (%1) - - - could not open output audio encoder (%1) - Nepodařilo se otevřít kodér zvuku (%1) - - - could not write output file trailer (%1) - Nepodařilo se zapsat ukázku výstupního souboru (%1) - - - could not audio encoder for %1 - Nepodařilo se najít kodér zvuku pro %1 - - - could not allocate video encoding context - Nepodařilo se přiřadit kontext kódování obrazu - - - could not write output file header (%1) - Nepodařilo se zapsat hlavičku výstupního souboru (%1) - - - could not video encoder for %1 - Nepodařilo se najít kodér obrazu pro %1 - - - could not allocate video stream - Nepodařilo se přiřadit datový proud obrazu - - - could not open output video encoder (%1) - Nepodařilo se otevřít kodér obrazu (%1) - - - could not allocate audio buffer (%1) - Nepodařilo se přiřadit vyrovnávací paměť zvuku (%1) - - - could not allocate audio stream - Nepodařilo se přiřadit datový proud zvuku - - - - FFmpegDecoder - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - Failed to allocate codec context (%1 :: %2) - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - Type - Typ - - - Fill Left with Right - Vyplnit levý pravým - - - Fill Right with Left - Vyplnit pravý levým - - - Fill Left/Right - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - Failed to load Frei0r plugin "%1": %2 - Nepodařilo se nahrát přídavný modul Frei0r "%1": %2 - - - Error loading Frei0r plugin - Chyba při nahrávání přídavného modulu Frei0r - - - 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. - Poznámka: Nemůžete nahrát 64 bitové přídavné moduly Frei0r do 32 bitového sestavení Olive. Najděte, prosím, 32 bitovou verzi tohoto přídavného modulu nebo přepněte na 64 bitové sestavení Olive. - - - 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. - Poznámka: Nemůžete nahrát 32 bitové přídavné moduly Frei0r do 64 bitového sestavení Olive. Najděte, prosím, 64 bitovou verzi tohoto přídavného modulu nebo přepněte na 32 bitové sestavení Olive. - - - - GraphEditor - - Hold - Držet - - - Graph Editor - Editor grafu - - - Bezier - Bézier - - - Linear - Lineární - - - - GraphView - - Zoom to Show All - Přiblížit pro ukázání všeho - - - Zoom to Selection - Přiblížit na výběr - - - Reset View - Obnovit výchozí zvětšení - - - - InterlacingName - - Invalid - Neplatný - - - Top Field First - Nejprve horní pole - - - None (Progressive) - Žádný (progresivní) - - - Bottom Field First - Nejprve dolní pole - - - Upper Field First - - - - Lower Field First - - - - - KeyframeNavigator - - Enable Keyframes - Povolit klíčové snímky - - - - KeyframeView - - Hold - Držet - - - Bezier - Bézier - - - Linear - Lineární - - - - LabelSlider - - Set Value - Nastavit hodnotu - - - New value: - Nová hodnota: - - - &Edit - Úp&ravy - - - &Reset to Default - - - - - LinearFadeTransition - - Linear Fade - - - - An linear audio fade that fades evenly at a constant rate. - - - - - LoadDialog - - Cancel - Zrušit - - - Loading... - Nahrává se... - - - Loading '%1'... - Nahrává se '%1'... - - - - LoadThread - - Invalid Clip Link - Neplatný odkaz na záběr - - - %1 - Line: %2 Col: %3 - %1 - Řádek: %2 Sloupec: %3 - - - This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? - Tento projekt obsahuje neplatný odkaz na záběr. Tento může být poškozen. Chcete pokračovat v jeho nahrávání? - - - Project Load Error - Chyba při nahrávání projektu - - - Couldn't load '%1'. %2 - Nepodařilo se nahrát '%1'. %2 - - - Version Mismatch - Rozdílná verze - - - 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? - Tento projekt byl uložen v jiné verzi Olive a nemusí být plně slučitelný s touto verzí. Přesto se jej chcete pokusit nahrát? - - - Error loading project: %1 - Chyba při nahrávání projektu: %1 - - - User aborted loading - Uživatelem přerušené nahrávání - - - XML Parsing Error - Chyba při zpracování XML - - - - LogarithmicFadeTransition - - Logarithmic Fade - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - 4:3 - 4:3 - - - Off - Vypnuto - - - &New - &Nový - - - 16:9 - 16:9 - - - Loop - Smyčka - - - Redo - Znovu - - - Slip Tool - Roztočení se ztotožněním - - - &Edit - Úp&ravy - - - &File - &Soubor - - - &Help - Nápo&věda - - - &Undo - &Zpět - - - &View - &Pohled - - - Timeline - Časová osa - - - E&xit - &Ukončit - - - Graph Editor - Editor grafu - - - Edit Tool - Nástroj pro úpravy - - - Media Viewer - Prohlížeč záznamu - - - Go to Start - Jít na začátek - - - Go to In Point - Jít na bod začátku - - - Zoom In - Přiblížit - - - Clear Recent List - Vyprázdnit seznam naposledy otevřených souborů - - - Edit to Out Point - Upravit po bod konce - - - Go to Out Point - Jít na bod konce - - - Seek to the End of Pastes - Vyhledávat po konec vložení - - - Ripple Tool - Vložení a posunutí - - - Enable Drag Files to Timeline - Povolit tažení souborů na časovou osu - - - Drop Frame - Zahodit snímek - - - &Playback - &Přehrávání - - - Title/Action Safe Area - Bezpečná oblast - - - Audio Scrubbing - Přehrávání zvuku při tažení ukazatele - - - &Tools - &Nástroje - - - Ripple to In Point - Vložit a posunout k bodu začátku - - - Enable Snapping - Povolit přichytávání - - - No Auto-Scroll - Žádné automatické projíždění - - - Auto-Scale By Default - Automaticky měnit velikost - - - Set/Edit Marker - Nastavit/Upravit značku - - - Non-Drop Frame - Nezahodit snímek - - - Hand Tool - Ručička - - - Toggle Show All - Přepnout ukázání všeho - - - Custom - Vlastní - - - Frames - Snímky - - - Lock Panels - Uzamknout panely - - - Play In to Out - Přehrát od začátku po konec - - - Scroll Wheel Zooms - Kolečko myši přibližuje - - - Page Auto-Scroll - Stránkové automatické projíždění - - - Full Screen - Celá obrazovka - - - Open Recent - Otevřít nedávné - - - Edit to In Point - Upravit po bod začátku - - - Razor Tool - Nástroj břitvy - - - Next Frame - Další snímek - - - Zoom Out - Oddálit - - - Go to Previous Cut - Jít na předchozí záběr - - - &Export... - &Vyvést... - - - &Import... - &Zavést... - - - Project - Projekt - - - Go to End - Jít na konec - - - Enable Hover Focus - Povolit zaměření při přejetí - - - Shuttle Stop - Zastavit pendlování - - - Shuttle Left - Jezdit tam a zpět vlevo - - - Delete In/Out Point - Smazat bod začátku/konce - - - Clear Undo - Vyprázdnit minulost kroků zpět - - - Ripple Delete In/Out Point - Vytáhnout bod začátku/konce - - - Full Screen Viewer - Prohlížeč na celou obrazovku - - - Ripple to Out Point - Vložit a posunout k bodu konce - - - Enable Seek to Import - Povolit vyhledávání k zavedení - - - Edit Tool Selects Links - Nástroj pro úpravy vybírá odkazy - - - A&ction Search - Hledání č&inností - - - Pointer Tool - Ukazovátko - - - &About... - &O programu... - - - Debug Log - Zápis ladění - - - Selecting Also Seeks - Výběr také vyhledává - - - Select &All - Vybrat &vše - - - Slide Tool - Roztočení - - - Welcome to %1 - Vítejte v %1 - - - Default - Výchozí - - - Reset to Default Layout - Obnovit výchozí rozvržení - - - Effect Controls - Ovládání efektů - - - Enable Drop on Media to Replace - Povolit upuštění na záznam pro nahrazení - - - <untitled> - <bez názvu> - - - Rectified Waveforms - Vlnový tvar odspodu - - - Decrease Track Height - Zmenšit výšku stopy - - - Increase Track Height - Zvětšit výšku stopy - - - &Window - &Okno - - - Ask For Name When Setting Marker - Požádat o název při nastavení značky - - - &Save Project - &Uložit projekt - - - Play/Pause - Přehrát/Pozastavit - - - Preferences - Nastavení - - - Save Project &As - Uložit projekt j&ako - - - &Open Project - &Otevřít projekt - - - Milliseconds - Milisekundy - - - Track Lines - Řádky stop - - - Sequence Viewer - Prohlížeč úryvku (sledu záběrů) - - - Smooth Auto-Scroll - Jemné automatické projíždění - - - Previous Frame - Předchozí snímek - - - Go to Next Cut - Jít na další záběr - - - Seek Also Selects - Vyhledávání také vybírá - - - Transition Tool - Přechod - - - Shuttle Right - Jezdit tam a zpět vpravo - - - Deselect All - Zrušit výběr všeho - - - Maximize Panel - Zvětšit panel - - - Edit Tool Also Seeks - Nástroj pro úpravy také vyhledává - - - Auto-Cut Silence - - - - OpenColorIO Config Error - - - - Failed to set OpenColorIO configuration: %1 - - - - Node Editor - - - - - Marker - - Set Marker - Nastavit značku - - - Set clip marker name: - Nastavit název značky záběru: - - - Set sequence marker name: - Nastavit název značky úryvku (sledu záběrů): - - - - Media - - Name - Název - - - Rate - Rychlost - - - Name: - Název: - - - Filename: - Název souboru: - - - Video Dimensions: - Rozměry obrazu: - - - New Folder - Nová složka - - - Frame Rate: - Snímkování: - - - Interlacing: - Prokládání: - - - Audio Frequency: - Kmitočet zvuku: - - - %1 field(s) (%2 frame(s)) - %1 pole(í) (%2 snímek(y)) - - - Duration - Doba trvání - - - Audio Channels: - Zvukové kanály: - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - Název: %1 -Rozměry obrazu: %2x%3 -Snímkování: %4 -Kmitočet zvuku: %5 -Rozložení zvuku: %6 - - - - MediaPropertiesDialog - - Name: - Název: - - - Video %1: %2x%3 %4FPS - Obraz %1: %2x%3 %4 FPS - - - Alpha is Premultiplied - Alfa je předznásobena - - - "%1" Properties - "%1" Vlastnosti - - - Interlacing: - Prokládání: - - - Audio %1: %2Hz %3 - Zvuk %1: %2Hz %3 - - - %n channel(s) - - %n kanál - %n kanály - %n kanálů - - - - Auto (%1) - Auto (%1) - - - Conform to Frame Rate: - Odpovídá snímkování: - - - Tracks: - Stopy: - - - Color Space: - - - - - MenuHelper - - Cu&t - Vyjmou&t - - - Nest - Vnořovat - - - The aspect ratio '%1' is invalid. Please try again. - Poměr stran '%1' je neplatný. Zkuste to, prosím, znovu. - - - Cop&y - &Kopírovat - - - Split - Rozdělit - - - Paste Insert - Vložit/Přidat - - - Add Default Transition - Přidat výchozí přechod - - - &Paste - &Vložit - - - Delete - Smazat - - - Link/Unlink - Spojit/Oddělit - - - Invalid aspect ratio - Neplatný poměr stran - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Zadejte poměr stran k použití pro bezpečnou oblast (např. 16:9): - - - Set In Point - Nastavit bod začátku - - - Clear In/Out Point - Vymazat bod začátku/konce - - - Enter custom aspect ratio - Zadat vlastní poměr stran - - - Duplicate - Zdvojit - - - &Project - &Projekt - - - &Folder - &Složka - - - &Sequence - Ú&ryvek - - - Reset In Point - Obnovit výchozí bod začátku - - - Ripple Delete - Vytáhnout - - - Enable/Disable - Povolit/Zakázat - - - Set Out Point - Nastavit bod konce - - - Reset Out Point - Obnovit výchozí bod konce - - - - NewSequenceDialog - - 144p - 144p - - - 240p - 240p - - - 360p - 360p - - - 480p - 480p - - - 720p - 720p - - - Editing "%1" - Upravení "%1" - - - 1080p - 1080p - - - Audio - Zvuk - - - Name: - Název: - - - Video - Obraz - - - TV 4K (Ultra HD/2160p) - TV 4K (Ultra HD/2160p) - - - PAL (576i) - PAL (576i) - - - NTSC (480i) - NTSC (480i) - - - None (Progressive) - Žádné (progresivní) - - - Custom - Vlastní - - - Width: - Šířka: - - - Frame Rate: - Snímkování: - - - Interlacing: - Prokládání: - - - Preset: - Přednastavení: - - - New Sequence - Nový úryvek (sled záběrů) - - - Pixel Aspect Ratio: - Poměr stran pixelu: - - - Square Pixels (1.0) - Čtvercové pixely (1.0) - - - Sample Rate: - Vzorkovací kmitočet: - - - Film 4K - Film 4K - - - Height: - Výška: - - - - Node - - Node - - - - - NodeBlock - - Previous - - - - Next - - - - Block - - - - - NodeEditor - - Node Editor - - - - - NodeIO - - Disable Keyframes - Zakázat klíčové snímky - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Zákázání klíčových snímků smaže všechny nynější klíčové snímky. Opravdu to chcete udělat? - - - - NodeMedia - - Matrix - - - - Texture - - - - Media - Záznamy - - - - NodeTexturePassthru - - Texture - - - - Image Output - - - - - NodeVideoClip - - Texture - - - - - NodeView - - Node Editor - - - - - OldEffectNode - - Save Effect Settings - Uložit nastavení efektu - - - Effect XML Settings %1 - Nastavení XML efektu %1 - - - Save Settings Failed - Nastavení se nepodařilo uložit - - - Failed to open "%1" for writing. - Nepodařilo se otevřít "%1" pro zápis. - - - Load Effect Settings - Nahrát nastavení efektu - - - Load Settings Failed - Nastavení se nepodařilo nahrát - - - Failed to open "%1" for reading. - Nepodařilo se otevřít "%1" pro čtení. - - - This settings file doesn't match this effect. - Tento soubor s nastavením neodpovídá tomuto efektu. - - - - OliveGlobal - - Auto-recovery - Automatické obnovení - - - Save Project As... - Uložit projekt jako... - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive nebyl zavřen řádně a byl zjištěn soubor pro automatické obnovení. Chcete jej otevřít? - - - Missing recent project - Chybí nedávný projekt - - - Please open the sequence you wish to export. - Otevřete, prosím, úryvek (sled záběrů), jejž chcete vyvést. - - - This project has changed since it was last saved. Would you like to save it before closing? - Tento projekt se od doby, kdy byl naposledy uložen, změnil. Chcete jej před zavřením uložit? - - - Open Project... - Otevřít projekt... - - - Olive Project %1 - Projekt Olive %1 - - - No active sequence - Žádný činný úryvek (sled záběrů) - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Projekt '%1' už neexistuje. Chcete jej odstranit ze seznamu nedávných projektů? - - - Unsaved Project - Neuložený projekt - - - Missing Project File - Chybí soubor projektu - - - Specified project '%1' does not exist. - Daný projekt '%1' neexistuje. - - - Please open the sequence to perform this action. - - - - No clips selected - - - - Select the clips you wish to auto-cut - - - - Effect already exists - Efekt již existuje - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Záběr '%1' již obsahuje '%2' efekt. Chcete jej nahradit vloženým nebo jej přidat jako samostatný efekt? - - - Add - Přidat - - - Replace - Nahradit - - - Skip - Přeskočit - - - Do this for all conflicts found - Použít na všechny nalezené střety - - - Import media... - Zavést záznam... - - - All Files - Všechny soubory - - - - PanEffect - - Pan - Vyvážení - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - Mono - Mono - - - Export Shortcuts - Vyvést zkratky - - - Audio - Zvuk - - - Invalid CSS File - Neplatný soubor CSS - - - All previews deleted succesfully. You may have to re-open your current project for changes to take effect. - Všechny náhledy byly úspěšně smazány. Možná budete muset nynější projekt otevřít znovu, aby se změny projevily. - - - Thumbnail Resolution: - Rozlišení náhledu: - - - Playback - Přehrávání - - - Search for action or shortcut - Hledat činnosti nebo klávesové zkratky - - - Sample Rate: - Vzorkovací kmitočet: - - - Waveform Resolution: - Rozlišení tvaru vlny: - - - Use Software Fallbacks When Possible - Zajištění skrze softwarovou zálohu - - - Action - Činnost - - - Browse - Procházet - - - Export - Vyvést - - - Language: - Jazyk: - - - Import - Zavést - - - Effect Textbox Lines: - Řádky textového pole efektu: - - - Stereo - Stereo - - - Custom CSS: - Vlastní CSS: - - - Delete All Previews - Smazat všechny náhledy - - - Previews Deleted - Náhledy smazány - - - Output Device: - Výstupní zařízení: - - - Audio Recording: - Nahrávání zvuku: - - - frames - snímků - - - Fast Seeking -Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) - Rychlé vyhledávání -Vyhledávat rychle (při hledání se mohou krátce ukázat nepřesné snímky - neovlivňuje přehrávání/vyvádění) - - - Browse for CSS file - Hledat soubor CSS - - - Export Keyboard Shortcuts - Vyvést klávesové zkratky - - - Reset Selected - Obnovit výchozí hodnotu u vybraného - - - Failed to open file for writing - Soubor se nepodařilo otevřít pro zápis - - - Shortcuts exported successfully - Zkratky úspěšně vyvedeny - - - seconds - sekund - - - Seeking - Vyhledávání - - - Reset All - Obnovit výchozí hodnotu u všeho - - - Delete Previews - Smazat náhledy - - - Input Device: - Vstupní zařízení: - - - Confirm Reset All Shortcuts - Potvrdit obnovení výchozího nastavení všech klávesových zkratek - - - Default - Výchozí - - - Upcoming Frame Queue: - Nadcházející řada snímků: - - - Import Keyboard Shortcuts - Zavést klávesové zkratky - - - Behavior - Chování - - - Image sequence formats: - Formáty obrázkového úryvku (sledu záběrů): - - - Error saving shortcuts - Chyba při ukládání klávesových zkratek - - - Preferences - Nastavení - - - Keyboard - Klávesnice - - - Previous Frame Queue: - Předchozí řada snímků: - - - Are you sure you want to delete all previews? - Opravdu chcete smazat všechny náhledy? - - - General - Obecné - - - Memory Usage - Využití paměti - - - CSS file '%1' does not exist. - Soubor CSS '%1' neexistuje. - - - Accurate Seeking -Always show the correct frame (visual may pause briefly as correct frame is retrieved) - Přesné vyhledávání -Vždy ukazovat správný snímek (obraz se při získávání správného snímku může na krátkou dobu pozastavit) - - - Failed to open file for reading - Soubor se nepodařilo otevřít pro čtení - - - Shortcut - Zkratka - - - Are you sure you wish to reset all keyboard shortcuts to their defaults? - Jste si jistý, že chcete vrátit nastavení všech klávesových zkratek do jejich výchozího stavu? - - - Default Sequence - - - - Default Sequence Settings - - - - Add Default Effects to New Clips - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - Selecting Also Seeks - Výběr také vyhledává - - - Edit Tool Also Seeks - Nástroj pro úpravy také vyhledává - - - Edit Tool Selects Links - Nástroj pro úpravy vybírá odkazy - - - Seek Also Selects - Vyhledávání také vybírá - - - Seek to the End of Pastes - Vyhledávat po konec vložení - - - Scroll Wheel Zooms - Kolečko myši přibližuje - - - Hold CTRL to toggle this setting - - - - Invert Timeline Scroll Axes - - - - Enable Drag Files to Timeline - Povolit tažení souborů na časovou osu - - - Auto-Scale By Default - Automaticky měnit velikost - - - Auto-Seek to Imported Clips - - - - Audio Scrubbing - Přehrávání zvuku při tažení ukazatele - - - Drop Files on Media to Replace - - - - Enable Hover Focus - Povolit zaměření při přejetí - - - Ask For Name When Setting Marker - Požádat o název při nastavení značky - - - Appearance - - - - Theme - - - - Olive Dark (Default) - - - - Olive Light - - - - Native - - - - Native (Light Icons) - - - - Use Native Menu Styling - - - - (None) - - - - OpenColorIO Config Error - - - - Failed to set OpenColorIO configuration: %1 - - - - Invalid OpenColorIO Configuration File - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - OpenColorIO configuration file '%1' does not exist. - - - - Browse for OpenColorIO configuration - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - Don't Use Proxies When Exporting - - - - Use originals instead of proxies when exporting - - - - Enable Color Management - - - - OpenColorIO Config File: - - - - Default Input Color Space: - - - - Display: - - - - View: - - - - Look: - - - - Bit Depth - - - - Playback (Offline): - - - - Export (Online): - - - - Color Management - - - - - PreviewGenerator - - Could not find stream information - %1 - Nepodařilo se najít údaje o proudu - %1 - - - Could not open file - %1 - Nepodařilo se otevřít soubor - %1 - - - Failed to find any valid video/audio streams - - - - - Project - - Skip - Přeskočit - - - 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? - Záznam '%1' se nyní používá v '%2'. Jeho smazání odstraní všechny instance v úryvku (sledu záběrů). Opravdu to chcete udělat? - - - Delete media in use? - Smazat používaný záznam? - - - Image sequence detected - Zjištěn obrázkový úryvek (sled záběrů) - - - Rename '%1' - Přejmenovat '%1' - - - Active sequence selected - Vybrán činný úryvek (sled záběrů) - - - Enter new name: - Zadat nový název: - - - Search media, markers, etc. - Hledat záznam, značky atd. - - - Project - Projekt - - - Sequence - Úryvek - - - You cannot insert a sequence into itself, so no clips of this media would be in this sequence. - Úryvek (sled záběrů) nemůžete vložit do něj samého, aby žádné záběry z tohoto záznamu nebyly v tomto úryvku (sledu záběrů). - - - Import media... - Zavést záznam... - - - No active sequence - Žádný činný úryvek (sled záběrů) - - - No sequence is active, please open the sequence you want to delete clips from. - Žádný úryvek (sled záběrů) není činný. Otevřete, prosím, úryvek (sled záběrů), ve kterém chcete smazat záběry. - - - Replace '%1' - Nahradit '%1' - - - All Files - Všechny soubory - - - No sequence is active, please open the sequence you want to replace clips from. - Žádný úryvek (sled záběrů) není činný. Otevřete, prosím, úryvek (sled záběrů), ve kterém chcete nahradit záběry. - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Soubor '%1' se zdá být součástí obrázkového úryvku (sledu záběrů). Chcete jej zavést jako takový? - - - New - Nový - - - Open Project - - - - Save Project - - - - Undo - - - - Redo - Znovu - - - Tree View - Stromový pohled - - - Icon View - Pohled s ikonami - - - List View - - - - - ProjectModel - - Sequence %1 - - - - Import a Project - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - - - - Image sequence detected - Zjištěn obrázkový úryvek (sled záběrů) - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Soubor '%1' se zdá být součástí obrázkového úryvku (sledu záběrů). Chcete jej zavést jako takový? - - - - ProxyDialog - - Proxy - Proxy - - - Eighth Resolution (1/8) - Osminové rozlišení (1/8) - - - Create Proxy - Vytvořit proxy - - - Sixteenth Resolution (1/16) - Šestnáctinové rozlišení (1/16) - - - ProRes HQ - ProRes HQ - - - The file "%1" already exists. Do you wish to replace it? - Soubor "%1" již existuje. Chcete jej nahradit? - - - Dimensions: - Rozměry: - - - Half Resolution (1/2) - Poloviční rozlišení (1/2) - - - Location: - Umístění: - - - Same as Source (in "%1" folder) - Stejné jako zdroj (ve složce "%1") - - - Format: - Formát: - - - Quarter Resolution (1/4) - Čtvrtinové rozlišení (1/4) - - - Proxy file exists - Soubor proxy existuje - - - Same Size as Source - Stejná velikost jako zdroj - - - Custom Location - Vlastní umístění - - - - ProxyGenerator - - Finished generating proxy for "%1" - Dokončeno vytvoření proxy pro "%1" - - - - ReplaceClipMediaDialog - - No media selected - Nevybrán žádný záznam - - - You cannot replace footage with a folder. - Záběry nemůžete nahradit složkou. - - - Active sequence selected - Vybrán činný úryvek (sled záběrů) - - - Cancel - Zrušit - - - Please select a media to replace with or click 'Cancel'. - Vyberte, prosím, záznam k nahrazení nebo klepněte na Zrušit. - - - You cannot insert a sequence into itself. - Nemůžete vložit úryvek (sled záběrů) do něj samého. - - - Replace - Nahradit - - - Same media selected - Vybrán stejný záznam - - - Folder selected - Složka vybrána - - - You selected the same media that you're replacing. Please select a different one or click 'Cancel'. - Vybral jste stejný záznam, jejž chcete nahradit. Vyberte, prosím, jiný nebo klepněte na Zrušit. - - - Replace clips using "%1" - Nahradit záběry pomocí "%1" - - - Keep the same media in-points - Zachovat stejné začáteční body záznamu - - - Select which media you want to replace this media's clips with: - Vyberte, kterým záznamem chcete nahradit záběry tohoto záznamu: - - - - RichTextEffect - - Text - Text - - - Padding - - - - Position - Poloha - - - Vertical Align: - - - - Top - Nahoře - - - Center - Na střed - - - Bottom - Dole - - - Auto-Scroll - - - - Off - Vypnuto - - - Up - - - - Down - - - - Left - Vlevo - - - Right - Vpravo - - - Shadow - Stín - - - Shadow Color - Barva stínu - - - Shadow Angle - Úhel stínu - - - Shadow Distance - Vzdálenost stínu - - - Shadow Softness - Měkkost stínu - - - Shadow Opacity - Neprůhlednost stínu - - - Rich Text - - - - Render - - - - Render formatted rich text over a clip. - - - - - Sequence - - %1 (copy) - %1 (kopírovat) - - - - ShakeEffect - - Rotation - Otočení - - - Intensity - Síla - - - Frequency - Kmitočet - - - Shake - - - - Distort - - - - Simulate a camera shake movement. - - - - - SolidEffect - - Type - Typ - - - Color - Barva - - - Solid Color - Plná barva - - - Opacity - Neprůhlednost - - - Checkerboard - Šachovnice - - - SMPTE Bars - Pruhy SMPTE - - - Checkerboard Size - Velikost šachovnice - - - Solid - - - - Render - - - - Render a solid color over this clip. - - - - - SourcesCommon - - New - Nový - - - View - Pohled - - - Proxy - Proxy - - - Show Toolbar - Ukázat nástrojový pruh - - - Create/Modify Proxy - Vytvořit/Změnit proxy - - - Restore Original - Obnovit původní - - - Delete proxy - Smazat proxy - - - Create Proxy - Vytvořit proxy - - - Create Sequence With This Media - Vytvořit úryvek (sled záběrů) pomocí tohoto záznamu - - - Reveal in Explorer - Ukázat v průzkumníku - - - Delete - Smazat - - - Replace/Relink Media - Nahradit/Znovuspojit záznamy - - - Icon View - Pohled s ikonami - - - Delete All Clips Using This Media - Smazat všechny záběry pomocí tohoto záznamu - - - Duplicate - Zdvojit - - - Import... - Zavést... - - - Show Sequences - Ukázat úryvky (sledy záběrů) - - - Preview in Media Viewer - Náhled v prohlížeči záznamu - - - Replace Clips Using This Media - Nahradit záběry pomocí tohoto záznamu - - - Tree View - Stromový pohled - - - Generating proxy: %1% complete - Vytvoření proxy: %1% hotovo - - - Reveal in File Manager - Ukázat ve správci souborů - - - Properties... - Vlastnosti... - - - Modify Proxy - Změnit proxy - - - Replace Media - Nahradit záznam - - - Reveal in Finder - Ukázat v hledači - - - Would you like to delete the proxy file "%1" as well? - Chcete smazat i soubor proxy "%1"? - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - Upustil jste soubor na '%1'. Chcete jej nahradit upuštěným souborem? - - - Replace '%1' - Nahradit '%1' - - - All Files - Všechny soubory - - - - SpeedDialog - - Speed: - Rychlost: - - - Frame Rate: - Snímkování: - - - Duration: - Doba trvání: - - - Reverse - Obrátit - - - Maintain Audio Pitch - Udržovat výšku tónu zvuku - - - Ripple Changes - Změny vytažení - - - Speed/Duration - Rychlost/Doba trvání - - - - TextEditDialog - - Edit Text - Upravit text - - - Thin - - - - Extra Light - - - - Light - - - - Normal - Normální - - - Medium - - - - Demi Bold - - - - Bold - - - - Extra Bold - - - - Black - - - - - TextEditEx - - Edit Text - Upravit text - - - &Edit Text - &Upravit text - - - - TextEffect - - Top - Nahoře - - - Font - Písmo - - - Left - Vlevo - - - Size - Velikost - - - Text - Text - - - Color - Barva - - - Right - Vpravo - - - &Edit Text - &Upravit text - - - Outline Color - Barva obrysu - - - Outline Width - Šířka obrysu - - - Justify - Do bloku - - - Sample Text - Text příkladu - - - Shadow Softness - Měkkost stínu - - - Bottom - Dole - - - Center - Na střed - - - Shadow - Stín - - - Outline - Obrys - - - Shadow Distance - Vzdálenost stínu - - - Shadow Opacity - Neprůhlednost stínu - - - Word Wrap - Zalamování slov - - - Shadow Color - Barva stínu - - - Shadow Angle - Úhel stínu - - - Alignment - Zarovnání - - - Padding - - - - Position - Poloha - - - Horizontal Alignment - - - - Vertical Alignment - - - - Render - - - - Generate simple text over this clip - - - - - TimecodeEffect - - Timecode - Časový kód - - - Color - Barva - - - Media - Záznamy - - - Scale - Měřítko - - - Offset - Posun - - - Prepend - Uvést na začátku - - - Background Color - Barva pozadí - - - Background Opacity - Neprůhlednost pozadí - - - Sequence - Úryvek - - - Render - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - Add - Přidat - - - Skip - Přeskočit - - - Slip Tool - Roztočení se ztotožněním - - - Edit Tool - Nástroj pro úpravy - - - Title... - Název... - - - Zoom In - Přiblížit - - - Ripple Tool - Nástroj pro vložení a posunutí - - - (none) - (žádný) - - - Record audio - Nahrát zvuk - - - Solid Color... - Plná barva... - - - Hand Tool - Nástroj ručičky - - - Snapping - Přichytávání - - - Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) - Klepněte na časovou osu, kde chcete začít s nahráváním (táhněte pro omezení nahrávky na určitý časový snímek) - - - Noise... - Šum... - - - Nested Sequence - Vnořený úryvek (sled záběrů) - - - Razor Tool - Nástroj břitvy - - - Zoom Out - Oddálit - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Záběr '%1' již obsahuje '%2' efekt. Chcete jej nahradit vloženým nebo jej přidat jako samostatný efekt? - - - Bars... - Zkušební tabulka... - - - Replace - Nahradit - - - Pointer Tool - Nástroj ukazovátka - - - You must save this project before you can record audio in it. - Musíte tento projekt uložit, předtím než do něj můžete nahrát zvuk. - - - Effect already exists - Efekt již existuje - - - Slide Tool - Roztočení - - - Add title, solid, bars, etc. - Přidat název, plný, zkušební tabulky atd. - - - Tone... - Tón... - - - Do this for all conflicts found - Použít na všechny nalezené střety - - - Timeline: - Časová osa: - - - Unsaved Project - Neuložený projekt - - - Transition Tool - Nástroj pro přechod - - - Video Transitions - - - - Audio Transitions - - - - Timeline: %1 - - - - - TimelineHeader - - Center Timecodes - Vystředit časové kódy - - - - TimelineLabel - - Rename Track - - - - Enter the new name for this track - - - - - TimelineView - - &Undo - &Zpět - - - &Redo - &Znovu - - - R&ipple Delete Empty Space - - - - Sequence Settings - Nastavení úryvku (sledu záběrů) - - - &Speed/Duration - &Rychlost/Doba trvání - - - Auto-Cut Silence - - - - Auto-S&cale - - - - &Reveal in Project - &Odkrýt v projektu - - - Properties - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Začátek: %2 -Konec: %3 -Doba trvání: %4 - - - Error - Chyba - - - Couldn't locate media wrapper for sequence. - Nepodařilo se najít obal záznamu pro tento úryvek (sled záběrů). - - - Title - Název - - - Solid Color - Plná barva - - - Bars - Zkušební tabulka - - - Tone - Tón - - - Noise - Šum - - - Duration: - Doba trvání: - - - - TimelineWidget - - C&ut - Vyj&mout - - - Bars - Zkušební tabulka - - - Tone - Tón - - - &Redo - &Znovu - - - &Undo - &Zpět - - - Cop&y - &Kopírovat - - - Error - Chyba - - - Noise - Šum - - - Title - Název - - - Sequence Settings - Nastavení úryvku (sledu záběrů) - - - &Paste - &Vložit - - - &Reveal in Project - &Odkrýt v projektu - - - Rename '%1' - Přejmenovat '%1' - - - Auto-s&cale - Automatická &změna velikosti - - - R&ename - &Přejmenovat - - - Solid Color - Plná barva - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Začátek: %2 -Konec: %3 -Doba trvání: %4 - - - Rename multiple clips - Přejmenovat více záběrů - - - Enter a new name for this clip: - zadejte nový název pro tento záběr: - - - Duration: - Doba trvání: - - - R&ipple Delete - &Vytáhnout (smazat a posunout) - - - &Speed/Duration - &Rychlost/Doba trvání - - - Couldn't locate media wrapper for sequence. - Nepodařilo se najít obal záznamu pro tento úryvek (sled záběrů). - - - R&ipple Delete Empty Space - - - - Auto-Cut Silence - - - - Auto-S&cale - - - - Properties - - - - - ToneEffect - - Mix - Směs - - - Type - Typ - - - Amount - Množství - - - Frequency - Kmitočet - - - Sine - - - - Tone - Tón - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - Video %1 - - - - Audio %1 - - - - Subtitle %1 - - - - Unknown %1 - - - - - TransformEffect - - Glow - Záře - - - Pin Light - Připíchnout světlo - - - Scale - Měřítko - - - Anchor Point - Bod ukotvení - - - Linear Light - Přímé světlo - - - Lighten - Vypálit - - - Uniform Scale - Jednotné měřítko - - - Color Dodge - Uskočení barvy - - - Blend Mode - Režim mísení - - - Darken - Ztmavit - - - Normal - Normální - - - Screen - Obrazovka - - - Vivid Light - Jasné světlo - - - Color Burn - Vypálení barvy - - - Hard Light - Ostré světlo - - - Soft Light - Tlumené světlo - - - Linear Dodge (Add) - Lineární uskočení (Přidat) - - - Opacity - Neprůhlednost - - - Position - Poloha - - - Rotation - Otočení - - - Overlay - Překrytí - - - Phoenix - Fénix - - - Linear Burn - Přímé vypálení - - - Hard Mix - Tvrdá směs - - - Reflect - Zrcadlit - - - Average - Průměr - - - Substract - Odečíst - - - Exclusion - Ohraničení - - - Negation - Odmítnutí - - - Multiply - Znásobit - - - Difference - Rozdíl - - - Transform - - - - Distort - - - - Transform the position, scale, and rotation of this clip. - - - - - Transition - - Length - Délka - - - - UpdateNotification - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - - - - - VSTHost - - Show - Ukázat - - - Error loading VST plugin - Chyba při nahrávání přídavného modulu VST - - - Plugin's magic number is invalid - Kouzelné číslo přídavného modulu je neplatné - - - 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. - Poznámka: Nemůžete nahrát 64 bitové přídavné moduly VST do 32 bitového sestavení Olive. Najděte, prosím, 32 bitovou verzi tohoto přídavného modulu nebo přepněte na 64 bitové sestavení Olive. - - - Plugin - Přídavný modul - - - VST Plugin - Přídavný modul VST - - - VST Error - Chyba VST - - - Interface - Rozhraní - - - 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. - Poznámka: Nemůžete nahrát 32 bitové přídavné moduly VST do 64 bitového sestavení Olive. Najděte, prosím, 64 bitovou verzi tohoto přídavného modulu nebo přepněte na 32 bitové sestavení Olive. - - - Failed to locate entry point for dynamic library. - Nepodařilo se najít vstupní bod pro dynamickou knihovnu. - - - Failed to create VST reference - Nepodařilo se vytvořit odkaz na VST - - - Failed to load VST plugin "%1": %2 - Nepodařilo se nahrát přídavný modul "%1": %2 - - - VST Plugin 2.x - - - - Use a VST 2.x plugin on this clip's audio. - - - - - Viewer - - Media Viewer - Prohlížeč záznamu - - - (none) - (žádný) - - - Sequence Viewer - Prohlížeč úryvku (sledu záběrů) - - - Drag video only - - - - Drag audio only - - - - Viewer: %1 - - - - Failed to import recorded file - - - - An error occurred trying to import the recorded audio - - - - Sequence Viewer: %1 - - - - Media Viewer: %1 - - - - - ViewerWidget - - Fit - Vejít se - - - Zoom - Zvětšení - - - Save Frame as Image... - Uložit snímek jako obrázek... - - - Custom - Vlastní - - - Show Fullscreen - Ukázat na celou obrazovku - - - Close Media - Zavřít záznam - - - Save Frame - Uložit snímek - - - Screen %1: %2x%3 - Obrazovka %1: %2x%3 - - - Set Custom Zoom Value: - Nastavit vlastní hodnotu zvětšení: - - - Disable - Zakázat - - - Viewer Zoom - Zvětšení prohlížeče - - - - ViewerWindow - - Exit Fullscreen - Opustit celou obrazovku - - - - VoidEffect - - Missing Effect - Chybí efekt - - - (unknown) - (neznámý) - - - - VolumeEffect - - Volume - Hlasitost - - - Adjust the volume of this clip's audio - - - - - bitdepths - - 8-bit - - - - 16-bit Integer - - - - Half-Float (16-bit) - - - - Full-Float (32-bit) - - - - - transition - - Invalid transition - Neplatný přechod - - - No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. - Žádný uchazeč o přechod '%1'. Tento přechod může být poškozen. Pokuste se jej nebo Olive znovu nainstalovat. - - - diff --git a/ts/olive_de.ts b/ts/olive_de.ts deleted file mode 100644 index 9ee9d2ded..000000000 --- a/ts/olive_de.ts +++ /dev/null @@ -1,4902 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - Olive ist ein nicht-lineares Videoschnittprogramm. Diese Software ist frei und durch die GNU GPL geschützt. - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - Das Olive Team ist dazu verpflichtet, die Nutzer darüber zu informieren, dass der Quellcode von der Webseite heruntergeladen werden kann. - - - - ActionSearch - - - Search for action... - Nach Aktion suchen... - - - - AdvancedVideoDialog - - - Advanced Video Settings - Erweiterte Video-Einstellungen - - - - Pixel Format: - Pixelformat: - - - - Threads: - Threads: - - - - Audio - - Audio - Same as in english - Audio - - - Recording - Aufnahme - - - - %1 Audio - %1 Audio - - - - Recording %1 - %1 aufnehmen - - - - AudioNoiseEffect - - - Amount - In this case the intensity is meant - Stärke - - - - Mix - Same as in english? - Mix - - - - Noise - Rauschen - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - - - - - Attack Threshold: - - - - - Attack Time: - - - - - Release Threshold: - - - - - Release Time: - - - - - Cacher - - - - Could not open %1 - %2 - Konnte %1 nicht öffnen - %2 - - - - ChannelLayoutName - - - Invalid - ungültig - - - - Mono - Same as in english - Mono - - - - Stereo - Same as in english - Stereo - - - - ClipPropertiesDialog - - - "%1" Properties - "%1" Eigenschaften - - - - Multiple Clip Properties - - - - - Name: - Name: - - - - Duration: - Dauer: - - - - (multiple) - (mehrere) - - - - CollapsibleWidget - - - <untitled> - <unbenannt> - - - - ColorButton - - - Set Color - Farbe übernehmen - - - - CornerPinEffect - - - Top Left - Oben Links - - - - Top Right - Oben Rechts - - - - Bottom Left - Unten Links - - - - Bottom Right - Unten Rechts - - - - Perspective - Perspektive - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - DebugDialog - - - Debug Log - Could be also different but is understandable in german - Debug-Log - - - - DemoNotice - - - - Welcome to Olive! - Willkommen in 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 ist ein freies, offenes Videoschnittprogramm welches unter der GNU GPL lizensiert ist. Sofern Sie für diese Software bezahlt haben, wurden Sie betrogen. - - - - 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 - Diese Software ist aktuell in einem ALPHA-Stadium, was bedeutet, dass die Software instabil ist, abstürzen könnte, Fehler enthält und einige Funktionen fehlen. Wir leisten keine Garantie, die Benutzung der Software erfolgt auf eigenes Risiko. Bitte melden Sie Fehler oder Funktionswünsche auf %1 - - - - Thank you for trying Olive and we hope you enjoy it! - Danke das Sie Olive ausprobieren, wir hoffen es gefällt Ihnen! - - - - Effect - - Invalid effect - Ungültiger Effekt - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - The last sentence does not make real sense in german. I changed it to "a reinstallation is recommended" - Kein Kandidat für Effekt '%1'. Dieser Effekt ist möglicherweise beschädigt. Eine Neuinstallation wird empfohlen. - - - Cu&t - &Ausschneiden - - - &Copy - &Kopieren - - - Move &Up - Nach &oben - - - Move &Down - Nach &unten - - - D&elete - L&öschen - - - Load Settings From File - Einstellungen aus Datei laden - - - Save Settings to File - Einstellungen in Datei speichern - - - Save Effect Settings - Effekt-Einstellungen speichern - - - Effect XML Settings %1 - XML Effekt-Einstellungen %1 - - - Save Settings Failed - Speichern der Einstellungen fehlgeschlagen - - - Failed to open "%1" for writing. - Fehler beim Öffnen von "%1" - - - Load Effect Settings - Effekt-Einstellungen laden - - - Load Settings Failed - Laden von Einstellungen fehlgeschlagen - - - Failed to open "%1" for reading. - Fehler beim Öffnen von "%1" - - - This settings file doesn't match this effect. - Die Einstellungsdatei stimmt nicht mit diesem Effekt überein. - - - - EffectControls - - - Effects: - Effekte: - - - &Paste - &Einfügen - - - - (none) - (keine) - - - - Add Video Effect - Video-Effekt hinzufügen - - - - VIDEO EFFECTS - VIDEO-EFFEKTE - - - - Add Video Transition - Video-Übergang hinzufügen - - - - Add Audio Effect - Audio-Effekt hinzufügen - - - - AUDIO EFFECTS - AUDIO-EFFEKTE - - - - Add Audio Transition - Audio-Übergang hinzufügen - - - (Multiple clips selected) - (mehrere Clips ausgewählt) - - - - EffectRow - - Disable Keyframes - Keyframes deaktivieren - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Ein Deaktivieren von Keyframes löscht alle aktuellen Keyframes. Sind Sie sicher? - - - - EffectUI - - - %1 (Opening) - - - - - %1 (Closing) - - - - - %1 (multiple) - - - - - Cu&t - &Ausschneiden - - - - &Copy - &Kopieren - - - - Move &Up - Nach &oben - - - - Move &Down - Nach &unten - - - - D&elete - L&öschen - - - - Load Settings From File - Einstellungen aus Datei laden - - - - Save Settings to File - Einstellungen in Datei speichern - - - - EmbeddedFileChooser - - - File: - Datei: - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - Exportieren von "%1" - - - - Unknown codec name %1 - Unbekannter Codec-Name %1 - - - - Export Failed - Exportieren fehlgeschlagen - - - - Export failed - %1 - Exportieren fehlgeschlagen - %1 - - - - Invalid dimensions - Ungültige Dimensionen - - - - Export width and height must both be even numbers/divisible by 2. - Breite und Höhe müssen Zahlen sein, die durch 2 teilbar sind. - - - - Invalid codec - Ungültiger Codec - - - - Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. - Ausgabe-Parameter für den ausgewählten Codec konnte nicht erkannt werden. Dies ist ein Fehler, bitte kontaktieren Sie den Entwickler. - - - - Invalid format - Ungültiges Format - - - - Couldn't determine output format. This is a bug, please contact the developers. - Ausgabe-Format konnte nicht erkannt werden. Dies ist ein Fehler, bitte kontaktieren Sie den Entwickler. - - - - Export Media - In german it would be not good to add media to the title - Exportieren - - - - %p% (Total: %1:%2:%3) - - - - - %p% (ETA: %1:%2:%3) - - - - - Quality-based (Constant Rate Factor) - Qualität (Constant Rate Factor) - - - - Constant Bitrate - Konstante Bitrate - - - - - Invalid Codec - Ungültiger Codec - - - - Failed to find a suitable encoder for this codec. Export will likely fail. - Es wurde kein passender Encoder für diesen Codec gefunden. Exportieren könnte fehlschlagen. - - - - Failed to find pixel format for this encoder. Export will likely fail. - - - - - Bitrate (Mbps): - Bitrate (Mbps): - - - - Quality (CRF): - Qualität (CRF): - - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - Qualitätsfaktor: - -0 = verlustfrei (lossless) -17-18 = optisch verlustfrei (komprimiert, aber nicht bemerkbar) -23 = höchste Qualität -51 = kleinstmögliche Qualität - - - - Target File Size (MB): - Ziel-Dateigröße (MB): - - - - Format: - Same as in english - Format: - - - - Range: - Bereich: - - - - Entire Sequence - Komplette Sequenz - - - - In to Out - In to Out - - - - Video - Same as in english - Video - - - - - Codec: - Same as in english - Codec: - - - - Width: - Breite: - - - - Height: - Höhe: - - - - Frame Rate: - Bildfrequenz: - - - - Compression Type: - Komprimierungsverfahren: - - - - Advanced - Erweitert - - - - Audio - Audio - - - - Sampling Rate: - Abtastrate: - - - - Bitrate (Kbps/CBR): - Same as in english - Bitrate (Kbps/CBR): - - - - ExportThread - - - failed to send frame to encoder (%1) - Fehler beim Senden des Frames zum Encoder (%1) - - - - failed to receive packet from encoder (%1) - Fehler beim Empfangen des Pakets vom Encoder (%1) - - - - could not video encoder for %1 - Video-Encoder für %1 konnte nicht gefunden werden - - - - could not allocate video stream - Videostream konnte nicht zugewiesen werden - - - - could not allocate video encoding context - - - - - could not open output video encoder (%1) - Video-Encoder konnte nicht geöffnet werden (%1) - - - - could not copy video encoder parameters to output stream (%1) - Video-Encoder-Parameter konnten nicht in den Ausgabe-Stream kopiert werden (%1) - - - - could not audio encoder for %1 - Audio-Encoder für %1 konnte nicht gefunden werden - - - - could not allocate audio stream - Audiostream konnte nicht zugewiesen werden - - - - could not allocate audio encoding context - Audio-Encoding-Kontext konnte nicht zugewiesen werden - - - - could not open output audio encoder (%1) - Audio-Encoder konnte nicht geöffnet werden (%1) - - - - could not copy audio encoder parameters to output stream (%1) - Audio-Encoder-Parameter konnten nicht in den Ausgabe-Stream kopiert werden (%1) - - - - could not allocate audio buffer (%1) - Audio-Buffer konnte nicht zugewiesen werden (%1) - - - - could not create output format context - Ausgabe-Format-Kontext konnte nicht erstellt werden - - - - could not open output file (%1) - Ausgabe konnte nicht geöffnet werden (%1) - - - - could not write output file header (%1) - Ausgabe-Datei-Header konnte nicht geschrieben werden (%1) - - - - could not write output file trailer (%1) - Ausgabe-Datei-Trailer konnte nicht geschrieben werden (%1) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Typ - - - - Fill Left with Right - Linke Seite mit Rechter füllen - - - - Fill Right with Left - Rechte Seite mit Linker füllen - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - Frei0r plugin konnte nicht geladen werden (%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. - HINWEIS: Sie können keine 32-bit Frei0r Plugins in einer 64-bit Version von Olive laden. Sie benötigen entweder eine 64-bit Version des Plugins oder eine 32-bit Version von 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. - HINWEIS: Sie können keine 64-bit Frei0r Plugins in einer 32-bit Version von Olive laden. Sie benötigen entweder eine 32-bit Version des Plugins oder eine 64-bit Version von Olive. - - - - Error loading Frei0r plugin - Fehler beim Laden des Frei0r Plugins - - - - GraphEditor - - - Graph Editor - Grafischer Editor - - - - Linear - Same as in english - Linear - - - - Bezier - Same as in english - Bezier - - - - Hold - Does this make sense? (is a handle button meant?) - Halten - - - - GraphView - - - Zoom to Selection - In die Auswahl zoomen - - - - Zoom to Show All - Zommen, um alles anzuzeigen - - - - Reset View - Ansicht zurücksetzen - - - - InterlacingName - - - None (Progressive) - Keine (Progressive) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - Oberes Feld zuerst - - - Bottom Field First - Unteres Feld zuerst - - - - Invalid - Ungültig - - - - KeyframeNavigator - - - Enable Keyframes - Keyframes aktivieren - - - - KeyframeView - - - Linear - Same as in english - Linear - - - - Bezier - Same as in english - Bezier - - - - Hold - Does this make sense? - Halten - - - - LabelSlider - - - &Edit - &Bearbeiten - - - - &Reset to Default - - - - - - Set Value - Wert ändern - - - - - New value: - Neuer Wert: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - LoadDialog - - - Loading... - Lädt... - - - - Loading '%1'... - Lädt '%1'... - - - - Cancel - Abbrechen - - - - LoadThread - - - Version Mismatch - Unterschiedliche Versionen - - - - 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? - Dieses Projekt wurde mit einer anderen Version von Olive gespeichert und ist möglicherweise nicht vollständig kompatibel. Wollen Sie trotzdem versuchen, es zu laden? - - - Invalid Clip Link - Ungültiger Clip Link - - - This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? - Sounds better in German but has same sense - Dieses Projekt enthält eine ungültige Verlinkung zu einem Clip. Das Projekt ist möglicherweise beschädigt. Wollen Sie es dennoch versuchen? - - - - %1 - Line: %2 Col: %3 - %1 - Zeile: %2 Spalte: %3 - - - - User aborted loading - Ladevorgang durch Nutzer abgebrochen - - - - XML Parsing Error - Does not make sense to translate this - XML Parsing Error - - - - Couldn't load '%1'. %2 - '%1' konnte nicht geladen werden. (%2) - - - - Project Load Error - Projektladefehler - - - - Error loading project: %1 - Fehler beim Laden des Projektes: %1 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - Auto-recovery - Auto-Wiederherstellung - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive wurde nicht richtig beendet und eine Wiederherstellungsdatei wurde gefunden. Möchten Sie diese öffnen? - - - &Project - &Projekt - - - &Sequence - &Sequenz - - - &Folder - &Ordner - - - Set In Point - Also for following translations: Not sure if sense is matched - Anfangspunkt festlegen - - - Set Out Point - Endpunkt festlegen - - - Enable/Disable In/Out Point - Anfangs-/Endpunkt aktivieren/deaktiviern - - - - Welcome to %1 - Willkommen in %1 - - - Reset In Point - Anfangspunkt zurücksetzen - - - Reset Out Point - Endpunkt zurücksetzen - - - Clear In/Out Point - Anfangs-/Endpunkt löschen - - - No active sequence - Keine aktive Sequenz - - - Please open the sequence you wish to export. - Bitte öffnen Sie die Sequenz, die Sie exportieren möchten. - - - Save Project As... - Projekt speichern als... - - - Unsaved Project - Ungespeichertes Projekt - - - This project has changed since it was last saved. Would you like to save it before closing? - Das Projekt enthält ungespeicherte Änderungen. Wollen Sie diese jetzt speichern? - - - - &File - &Datei - - - - &New - &Neu - - - - &Open Project - Projekt &öffnen - - - - Clear Recent List - 'Zuletzt geöffnet' leeren - - - - Open Recent - Zuletzt Verwendete öffnen - - - - &Save Project - &Projekt speichern - - - - Save Project &As - Projekt speichern &als... - - - - &Import... - &Importieren... - - - - &Export... - &Exportieren - - - - E&xit - B&eenden - - - - &Edit - &Bearbeiten - - - - &Undo - &Rückgängig - - - - Redo - Wiederholen - - - Cu&t - &Ausschneiden - - - Cop&y - &Kopieren - - - &Paste - &Einfügen - - - Duplicate - Duplizieren - - - Delete - Löschen - - - Ripple Delete - In Premiere's translations its also called "Ripple Delete" - Ripple Delete - - - Split - Teilen - - - - Select &All - Alles &auswählen - - - - Deselect All - Auswahl aufheben - - - Add Default Transition - Standardübergang einfügen - - - Link/Unlink - Verbinden/Trennen - - - Enable/Disable - Einblenden/Ausblenden - - - Nest - Schachteln - - - - 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 - Marker setzen/bearbeiten - - - - &View - &Ansicht - - - - Zoom In - Hereinzoomen - - - - Zoom Out - Herauszoomen - - - - Increase Track Height - Spurhöhe erhöhen - - - - Decrease Track Height - Spurhöhe verringern - - - - Toggle Show All - - - - Track Lines - Spurlinien - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - Nachgebesserte Waveforms - - - - Frames - Frames - - - - Drop Frame - Same word used in German - Drop Frame - - - - Non-Drop Frame - Same word used in German - Non-Drop Frame - - - - Milliseconds - Millisekunden - - - - Title/Action Safe Area - Sicherer Titelbereich - - - - Off - Aus - - - - Default - Standard - - - - 4:3 - 4:3 - - - - 16:9 - 16:9 - - - - Custom - Benutzerdefiniert - - - - Full Screen - Vollbild - - - - Full Screen Viewer - Does this make sense? - Vollbild-Viewer - - - - &Playback - Should we translate this? Playback is also known - &Wiedergabe - - - - Go to Start - Zum Start gehen - - - - Previous Frame - Vorheriger Frame - - - - Play/Pause - Does not make sense to translate - Play/Pause - - - - Play In to Out - Von Anfang bis Ende wiedergeben - - - - Next Frame - Nächster Frame - - - - Go to End - Zum Ende springen - - - - Go to Previous Cut - Zum vorherigen Schnitt springen - - - - Go to Next Cut - Zum nächsten Schnitt springen - - - - Go to In Point - Zum Anfangspunkt springen - - - - Go to Out Point - Zum Endpunkt springen - - - - Shuttle Left - - - - - Shuttle Stop - - - - - Shuttle Right - - - - - Node Editor - - - - - Auto-Cut Silence - - - - Decrease Speed - Geschwindigkeit verringern - - - Pause - Same as in english - Pause - - - Increase Speed - Geschwindigkeit erhöhen - - - - Loop - Schleife - - - - &Window - &Fenster - - - - Project - Projekt - - - - Effect Controls - Effektsteuerung - - - - Timeline - Same as in english - Timeline - - - - Graph Editor - Grafischer Editor - - - - Media Viewer - Does this make sense to translate? - Media Viewer - - - - Sequence Viewer - Does this make sense to translate? - Sequence Viewer - - - - Maximize Panel - Panel maximieren - - - - Lock Panels - Panel sperren - - - - Reset to Default Layout - Zum Standard-Layout zurücksetzen - - - - &Tools - &Werkzeuge - - - - Pointer Tool - Does this make sense? - Zeiger - - - - Edit Tool - Bearbeitungs-Werkzeug - - - - Ripple Tool - Same as 'Ripple Delete' - Ripple-Werkzeug - - - - Razor Tool - Schneide-Werkzeug - - - - Slip Tool - - - - - Slide Tool - - - - - Hand Tool - Hand-Werkzeug - - - - Transition Tool - Übergangs-Werkzeug - - - - Enable Snapping - Snapping aktivieren - - - Scroll Wheel Zooms - Could be better - Scrollrad zoomt - - - Enable Drag Files to Timeline - Dateien auf Timeline ziehen aktivieren - - - Auto-Scale By Default - Skaliere automatisch - - - Audio Scrubbing - Same as in english - Audio Scrubbing - - - Enable Drop on Media to Replace - Auf Medien zum Ersetzen ziehen aktivieren - - - Ask For Name When Setting Marker - Nach Namen fragen, wenn Marker gesetzt wird - - - - No Auto-Scroll - Kein Auto-Scroll - - - - Page Auto-Scroll - Seiten Auto-Scroll - - - - Smooth Auto-Scroll - Weiches Auto-Scroll - - - - Preferences - Einstellungen - - - - Clear Undo - Rückgängig-Historie leeren - - - - &Help - &Hilfe - - - - A&ction Search - &Aktionensuche - - - - Debug Log - Same as in english - Debug-Log - - - - &About... - &Über... - - - - <untitled> - <unbenannt> - - - Open Project... - Projekt öffnen... - - - Missing recent project - Zuletzt geöffnetes Projekt existiert nicht - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Das Projekt '%1' existiert nicht mehr oder wurde verschoben. Möchten Sie es aus der Liste entfernen? - - - Invalid aspect ratio - Ungültiges Seitenverhältnis - - - The aspect ratio '%1' is invalid. Please try again. - Das Seitenverhältnis '%1' ist ungültig. Bitte versuchen Sie es erneut. - - - Enter custom aspect ratio - Benutzerdefiniertes Seitenverhältnis eingeben - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Geben Sie das Seitenverhältnis für den sicheren Bereich ein (z.B. 16:9): - - - Nested Sequence - Geschachtelte Sequenz - - - - Marker - - - - Set Marker - Marker setzen - - - - Set clip marker name: - - - - - Set sequence marker name: - - - - - Media - - - New Folder - Neuer Ordner: - - - - Name: - Name: - - - - Filename: - Dateiname: - - - - Video Dimensions: - Video-Dimensionen: - - - - Frame Rate: - Bildrate: - - - %1 fields (%2 frames) - %1 Felder (%2 frames) - - - - %1 field(s) (%2 frame(s)) - - - - - Interlacing: - Same as in english - Interlacing: - - - - Audio Frequency: - Audiofrequenz: - - - - Audio Channels: - Audiokanäle: - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - Name: %1 -Video-Dimensionen: %2x%3 -Bildrate: %4 -Audiofrequenz: %5 -Audio Layout: %6 - - - - Name - Name - - - - Duration - Dauer - - - - Rate - Same as in english, differently spoken, but same meaning - Rate - - - - MediaPropertiesDialog - - - "%1" Properties - "%1" Eigenschaften - - - - Tracks: - Spuren: - - - - Video %1: %2x%3 %4FPS - Same as in english - Video %1: %2x%3 %4FPS - - - Audio %1: %2Hz %3 channels - Audio %1: %2Hz %3 Kanäle - - - - Audio %1: %2Hz %3 - Audio %1: %2Hz %3 - - - - %n channel(s) - - %n Kanal - %n Kanäle - - - - - Conform to Frame Rate: - Entspricht Bildrate: - - - - Alpha is Premultiplied - Alpha ist vormultipliziert - - - - Auto (%1) - Same? - Auto (%1) - - - - Interlacing: - Same as in english - Interlacing: - - - - Color Space: - - - - - Name: - Same as in english - Name: - - - - MenuHelper - - - &Project - &Projekt - - - - &Sequence - &Sequenz - - - - &Folder - &Ordner - - - - Set In Point - Anfangspunkt festlegen - - - - Set Out Point - Endpunkt festlegen - - - - Reset In Point - Anfangspunkt zurücksetzen - - - - Reset Out Point - Endpunkt zurücksetzen - - - - Clear In/Out Point - Anfangs-/Endpunkt löschen - - - - Add Default Transition - Standardübergang einfügen - - - - Link/Unlink - Verbinden/Trennen - - - - Enable/Disable - Einblenden/Ausblenden - - - - Nest - Schachteln - - - - Cu&t - &Ausschneiden - - - - Cop&y - &Kopieren - - - - - &Paste - &Einfügen - - - - Paste Insert - - - - - Duplicate - Duplizieren - - - - Delete - Löschen - - - - Ripple Delete - Ripple Delete - - - - Split - Teilen - - - - Invalid aspect ratio - Ungültiges Seitenverhältnis - - - - The aspect ratio '%1' is invalid. Please try again. - Das Seitenverhältnis '%1' ist ungültig. Bitte versuchen Sie es erneut. - - - - Enter custom aspect ratio - Benutzerdefiniertes Seitenverhältnis eingeben - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Geben Sie das Seitenverhältnis für den sicheren Bereich ein (z.B. 16:9): - - - - NewSequenceDialog - - - Editing "%1" - Bearbeitung von "%1" - - - - New Sequence - Neue Sequenz - - - - Preset: - Could be also preset - Vorgabe: - - - - Film 4K - Film 4K - - - - 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 - Benutzerdefiniert - - - - Video - Same as in english - Video - - - - Width: - Breite: - - - - Height: - Höhe: - - - - Frame Rate: - Bildrate: - - - - Pixel Aspect Ratio: - Pixel-Seitenverhältnis: - - - - Square Pixels (1.0) - Quadratische Pixel (1.0) - - - - Interlacing: - Same as in english - Interlacing: - - - - None (Progressive) - Keine (Progressive) - - - - Audio - Same as in english - Audio - - - - Sample Rate: - Abtastrate: - - - - Name: - Name: - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - Keyframes deaktivieren - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Ein Deaktivieren von Keyframes löscht alle aktuellen Keyframes. Sind Sie sicher? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - Medien - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - Effekt-Einstellungen speichern - - - - - Effect XML Settings %1 - XML Effekt-Einstellungen %1 - - - - Save Settings Failed - Speichern der Einstellungen fehlgeschlagen - - - - Failed to open "%1" for writing. - Fehler beim Öffnen von "%1" - - - - Load Effect Settings - Effekt-Einstellungen laden - - - - - Load Settings Failed - Laden von Einstellungen fehlgeschlagen - - - - Failed to open "%1" for reading. - Fehler beim Öffnen von "%1" - - - - This settings file doesn't match this effect. - Die Einstellungsdatei stimmt nicht mit diesem Effekt überein. - - - - OliveGlobal - - - Olive Project %1 - Olive-Projekt %1 - - - - Auto-recovery - Auto-Wiederherstellung - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive wurde nicht richtig beendet und eine Wiederherstellungsdatei wurde gefunden. Möchten Sie diese öffnen? - - - - Effect already exists - Effekt existiert bereits - - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Der Clip '%1' enthält bereits den Effekt '%2'. Möchten Sie diesen ersetzen oder ihn als separaten Effekt hinzufügen? - - - - Add - Hinzufügen - - - - Replace - Ersetzen - - - - Skip - Überspringen - - - - Do this for all conflicts found - Auf alle gefundenen Konflikte anwenden - - - - Open Project... - Projekt öffnen... - - - - Missing recent project - Zuletzt geöffnetes Projekt existiert nicht - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Das Projekt '%1' existiert nicht mehr oder wurde verschoben. Möchten Sie es aus der Liste entfernen? - - - - Save Project As... - Projekt speichern als... - - - - Unsaved Project - Ungespeichertes Projekt - - - - This project has changed since it was last saved. Would you like to save it before closing? - Das Projekt enthält ungespeicherte Änderungen. Wollen Sie diese jetzt speichern? - - - - Import media... - Medien importieren... - - - - All Files - Alle Dateien - - - - No active sequence - Keine aktive Sequenz - - - - Please open the sequence to perform this action. - Bitte öffnen Sie die Sequenz um diese Aktion auszuführen. - - - - No clips selected - Keine Clips ausgewählt - - - - Select the clips you wish to auto-cut - - - - Please open the sequence you wish to export. - Bitte öffnen Sie die Sequenz, die Sie exportieren möchten. - - - - Missing Project File - Projektdatei fehlt - - - - Specified project '%1' does not exist. - Das Projekt '%1' existiert nicht. - - - - PanEffect - - - - Pan - Schwenken - - - - Modifying the panning on a stereo audio clip. - - - - - Playback - - Generating Proxy: %1% - Proxy wird generiert: %1% - - - - PreferencesDialog - - - Preferences - Einstellungen - - - - Invalid CSS File - Ungültige CSS Datei - - - - CSS file '%1' does not exist. - CSS Datei '%1' existiert nicht. - - - Warning - Achtung - - - Some changed settings will require restarting Olive to take effect - Einige Änderungen erfordern einen Neustart von Olive, um angwendet zu werden - - - - Confirm Reset All Shortcuts - Bestätige das Zurücksetzen aller Shortcuts - - - - Are you sure you wish to reset all keyboard shortcuts to their defaults? - Sind Sie sicher, dass Sie alle Tastatur-Shortcuts zurücksetzen wollen? - - - - Import Keyboard Shortcuts - Tastatur-Shortcuts importieren - - - - - Error saving shortcuts - Fehler beim Speichern der Shortcuts - - - - Failed to open file for reading - Fehler beim öffnen der Datei - - - - Export Keyboard Shortcuts - Tastatur-Shortcuts exportieren - - - - Export Shortcuts - Shortcuts exportieren - - - - Shortcuts exported successfully - Shortcuts wurden erfolgreich exportiert - - - - Failed to open file for writing - Fehler beim Schreiben der Datei - - - - Browse for CSS file - Nach CSS Datei suchen - - - - Delete All Previews - - - - - Are you sure you want to delete all previews? - - - - - Previews Deleted - - - - - Language: - Sprache: - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - Default Sequence Settings - Sequenzeinstellungen auf Standard setzen - - - - Add Default Effects to New Clips - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - Selecting Also Seeks - - - - - Edit Tool Also Seeks - - - - - Edit Tool Selects Links - - - - - Seek Also Selects - - - - - Seek to the End of Pastes - - - - - Scroll Wheel Zooms - Scrollrad zoomt - - - - Hold CTRL to toggle this setting - Halten Sie STRG um diese Einstellung anzuzeigen - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - Dateien auf Timeline ziehen aktivieren - - - - Auto-Scale By Default - Skaliere automatisch - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - Audio Scrubbing - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - - - - - Ask For Name When Setting Marker - Nach Namen fragen, wenn Marker gesetzt wird - - - - Appearance - Erscheinungsbild - - - - Theme - Thema - - - - Olive Dark (Default) - Olive Dunkel (Standard) - - - - Olive Light - Olive Hell - - - - Native - Nativ (System UI) - - - - Native (Light Icons) - Nativ (Helle Icons) - - - - Use Native Menu Styling - - - - - Custom CSS: - Benutzerdefiniertes CSS: - - - - - Browse - Durchsuchen - - - - Image sequence formats: - Bilddateiformate: - - - - Audio Recording: - Audioaufnahmen: - - - - Mono - Same as in english - Mono - - - - Stereo - Same as in english - Stereo - - - - Effect Textbox Lines: - Effekt Textbox-Linien: - - - - Default Sequence - Standard Sequenz: - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - Thumbnail-Auflösung: - - - - Waveform Resolution: - - - - - Delete Previews - - - - - Use Software Fallbacks When Possible - Absicherung durch Software-Defaults - - - - General - Allgemein - - - - Behavior - Verhalten - - - Disable Multithreading on Images - Multithreading auf Bildern deaktiviern - - - Seeking - Suche - - - Accurate Seeking -Always show the correct frame (visual may pause briefly as correct frame is retrieved) - Genaue Suche -Zeigt immer den richtigen Frame (kann optisch kurzzeitig anhalten, wenn Frame abgefragt wird) - - - Fast Seeking -Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) - Schnelle Suche -Sucht schneller (kann kurzzeitig ungenaue Frame anzeigen - wirkt sich nicht auf Plaback aus) - - - - Memory Usage - Speicherauslastung - - - - Upcoming Frame Queue: - Anstehende Frame-Warteschlange: - - - - - frames - Could also use 'Bilder' - Frames - - - - - seconds - Sekunden - - - - Previous Frame Queue: - Vorherige Frame-Warteschlange: - - - - Playback - Wiedergabe - - - - Output Device: - Ausgabegerät: - - - - - Default - Standard - - - - Input Device: - Eingabegerät: - - - - Sample Rate: - Abtastrate: - - - - Audio - Audio - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - Search for action or shortcut - Nach Eintrag oder Shortcut suchen - - - - Action - Eintrag - - - - Shortcut - Shortcut - - - - Import - Importieren - - - - Export - Exportieren - - - - Reset Selected - Ausgewählte zurücksetzen - - - - Reset All - Alle zurücksetzen - - - - Keyboard - Tastatur - - - - PreviewGenerator - - - Failed to find any valid video/audio streams - - - - - Could not open file - %1 - Konnte Datei nicht öffnen - %1 - - - - Could not find stream information - %1 - Konnte Stream-Informationen nicht finden - %1 - - - - Project - - - New - Neu - - - - Open Project - Projekt öffnen - - - - Save Project - Projekt speichern - - - - Undo - - - - - Redo - Wiederholen - - - - Tree View - Tree View - - - - Icon View - Icon View - - - - List View - - - - - Search media, markers, etc. - - - - - Project - Projekt - - - Sequence - Sequenz - - - Replace '%1' - Ersetze '%1' - - - All Files - Alle Dateien - - - - - No active sequence - Keine aktive Sequenz - - - - No sequence is active, please open the sequence you want to replace clips from. - Keine Sequenz ist aktiv. Bitten öffnen Sie die Sequenz, bei der Sie Clips ersetzen möchten. - - - - Active sequence selected - Aktive Sequenz ausgewählt - - - - You cannot insert a sequence into itself, so no clips of this media would be in this sequence. - Sequenz kann nicht sich selbst zugewiesen werden, da es keine Medien enthalten würde. - - - - Rename '%1' - '%1' umbenennen - - - - Enter new name: - Neuen Namen eingeben: - - - - Delete media in use? - Verwendete Datei löschen? - - - - 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? - Die Datei '%1' wird aktuell in '%2' benutzt. Wenn Sie sie löschen, werden alle Instanzen in der Sequenz entfernt. Sind Sie sicher? - - - - Skip - Überspringen - - - Import a Project - Ein Projekt importieren - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - "%1" ist eine Olive-Projektdatei. Das Projekt wird automatisch mit diesem Projekt zusammengeführt. Möchten Sie fortfahren? - - - Image sequence detected - Bildsequenz erkannt - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Die Datei '%1' scheint eine Bildsequenz zu enthalten. Möchten Sie sie als solche importieren? - - - Import media... - Medien importieren... - - - - No sequence is active, please open the sequence you want to delete clips from. - Keine Sequenz ist aktiv. Bitten öffnen Sie die Sequenz, bei der Sie Clips löschen möchten. - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - Ein Projekt importieren - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - "%1" ist eine Olive-Projektdatei. Das Projekt wird automatisch mit diesem Projekt zusammengeführt. Möchten Sie fortfahren? - - - - Image sequence detected - Bildsequenz erkannt - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Die Datei '%1' scheint eine Bildsequenz zu enthalten. Möchten Sie sie als solche importieren? - - - - ProxyDialog - - - Create Proxy - Proxy erstellen - - - - Proxy - Same as in english - Proxy - - - - Dimensions: - Dimensionen: - - - - Same Size as Source - Selbe Größe wie Quelle - - - - Half Resolution (1/2) - - - - - Quarter Resolution (1/4) - - - - - Eighth Resolution (1/8) - - - - - Sixteenth Resolution (1/16) - - - - - Format: - Format: - - - - ProRes HQ - ProRes HQ - - - - Location: - Pfad: - - - - Same as Source (in "%1" folder) - Genau wie Quelle (in Ordner "%1") - - - - Proxy file exists - Proxy-Datei existiert bereits - - - - The file "%1" already exists. Do you wish to replace it? - Die Datei "%1" existiert bereits. Möchten Sie sie ersetzen? - - - - Custom Location - Benutzerdefinierter Pfad - - - - ProxyGenerator - - - Finished generating proxy for "%1" - Proxy-Generierung für "%1" wurde abgeschlossen - - - - ReplaceClipMediaDialog - - - Replace clips using "%1" - Ersetze Clips unter Verwendung von "%1" - - - - Select which media you want to replace this media's clips with: - Wählen Sie, welche Medien mit den Clips dieser Medien ersetzt werden sollen - - - - Keep the same media in-points - Anfangspunkte der Medien behalten - - - - Replace - Ersetzen - - - - Cancel - Abbrechen - - - - No media selected - Keine Medien ausgewählt - - - - Please select a media to replace with or click 'Cancel'. - Bitten wählen Sie Medien zum Ersetzen aus oder klicken Sie auf 'Abbrechen'. - - - - Same media selected - Identische Medien ausgewählt - - - - You selected the same media that you're replacing. Please select a different one or click 'Cancel'. - Sie haben die gleichen Medien ausgewählt, die Sie ersetzen möchten. Bitte wählen Sie andere Medien oder klicken Sie auf 'Abbrechen'. - - - - Folder selected - Ordner ausgewählt - - - - You cannot replace footage with a folder. - Sie können Footage nicht mit einem Ordner austauschen. - - - - Active sequence selected - Aktive Sequenz ausgewählt - - - - You cannot insert a sequence into itself. - Sie können keine Sequenz in die selbe einsetzen. - - - - RichTextEffect - - - Text - Text - - - - Padding - - - - - Position - Position - - - - Vertical Align: - Vertikale Ausrichtung: - - - - Top - Oben - - - - Center - Mitte - - - - Bottom - Unten - - - - Auto-Scroll - - - - - Off - Aus - - - - Up - Hoch - - - - Down - Runter - - - - Left - Links - - - - Right - Rechts - - - - Shadow - Schatten - - - - Shadow Color - Schattenfarbe - - - - Shadow Angle - - - - - Shadow Distance - Schattenentfernung - - - - Shadow Softness - Schattensoftness - - - - Shadow Opacity - Schattendeckkraft - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - %1 (kopieren) - - - - ShakeEffect - - - Intensity - Intentsität - - - - Rotation - Sames as in english, but differently spoken - Rotation - - - - Frequency - Frequenz - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Typ - - - - Solid Color - AE and Premiere handle this in the same way - Solid - - - - SMPTE Bars - SMPTE Farbstreifen - - - - Checkerboard - Schachbrettmuster - - - - Opacity - Deckkraft - - - - Color - Farbe - - - - Checkerboard Size - Größe Schachbrettmuster - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - Importieren... - - - - New - Neu - - - - View - Ansicht - - - - Tree View - A translation would be not recommended due to misunderstanding - Tree View - - - - Icon View - A translation would be not recommended due to misunderstanding - Icon View - - - - Show Toolbar - Toolbar anzeigen - - - - Show Sequences - Sequenzen anzeigen - - - - Replace/Relink Media - Medien ersetzen/neu verbinden - - - - Reveal in Explorer - Im Explorer anzeigen - - - - Reveal in Finder - Im Finder anzeigen - - - - Reveal in File Manager - Im File Manager anzeigen - - - - Replace Clips Using This Media - Ersetze Clips die diese Medien benutzen - - - - Create Sequence With This Media - Sequenz mit diesen Medien erstellen - - - - Duplicate - Duplizieren - - - - Delete All Clips Using This Media - Alle Clips, die diese Medien enthalten löschen - - - - Proxy - Proxy - - - - Generating proxy: %1% complete - Proxy wird generiert: %1% fertig - - - - Create/Modify Proxy - Erstelle/Modifiziere Proxy - - - - Create Proxy - Proxy erstellen - - - - Modify Proxy - Proxy modifizieren - - - - Restore Original - Original wiederherstellen - - - - Delete - Löschen - - - - Preview in Media Viewer - Vorschau im Media Viewer - - - - Properties... - Eigenschaften... - - - - Replace '%1' - Ersetze '%1' - - - - All Files - Alle Dateien - - - - Replace Media - Medien ersetzen - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - Sie haben eine Datei auf '%1' gezogen. Möchten Sie diese ersetzen? - - - - Delete proxy - Proxy löschen - - - - Would you like to delete the proxy file "%1" as well? - Möchten Sie die Proxy-Datei "%1" ebenfalls löschen? - - - - SpeedDialog - - - Speed/Duration - Geschwindigkeit/Dauer - - - - Speed: - Geschwindigkeit: - - - - Frame Rate: - Bildrate: - - - - Duration: - Dauer: - - - - Reverse - Rückwärts - - - - Maintain Audio Pitch - Tonhöhe erhalten - - - - Ripple Changes - Ripple-Änderungen - - - - TextEditDialog - - - Edit Text - Text bearbeiten - - - - Thin - Dünn - - - - Extra Light - - - - - Light - - - - - Normal - Normal - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - Text bearbeiten - - - - &Edit Text - &Text bearbeiten - - - - TextEffect - - - - Text - Same as in english - Text - - - - Font - Schriftart - - - - Size - Größe - - - - Color - Farbe - - - Alignment - Ausrichtung - - - - Horizontal Alignment - - - - - Left - Links - - - - - Center - Mitte - - - - Right - Rechts - - - - Justify - Ausrichten - - - - Vertical Alignment - - - - - Top - Oben - - - - Bottom - Unten - - - - Word Wrap - Zeilenumbruch - - - - Padding - - - - - Position - Position - - - - Outline - Umriss - - - - Outline Color - Umrissfarbe - - - - Outline Width - Umrissbreite - - - - Shadow - Schatten - - - - Shadow Color - Schattenfarbe - - - - Shadow Angle - - - - - Shadow Distance - Schattenentfernung - - - - Shadow Softness - Schattensoftness - - - - Shadow Opacity - Schattendeckkraft - - - - Sample Text - Beispieltext - - - - Render - - - - - Generate simple text over this clip - - - - &Edit Text - &Text bearbeiten - - - - TimecodeEffect - - - - Timecode - Zeitstempel - - - - Sequence - Sequenz - - - - Media - Medien - - - - Scale - Skalierung - - - - Color - Farbe - - - - Background Color - Hintergrundfarbe - - - - Background Opacity - Hintergrunddeckkraft - - - - Offset - Versatz - - - - Prepend - Voreinstellung - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - Timeline: - Makes no sense to translate - Timeline: - - - <none> - <keine> - - - Effect already exists - Effekt existiert bereits - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Der Clip '%1' enthält bereits den Effekt '%2'. Möchten Sie diesen ersetzen oder ihn als separaten Effekt hinzufügen? - - - Add - Hinzufügen - - - Replace - Ersetzen - - - Skip - Überspringen - - - Do this for all conflicts found - Auf alle gefundenen Konflikte anwenden - - - Set Marker - Marker setzen - - - Set marker name: - Marker-Name setzen: - - - - Title... - Titel... - - - - Solid Color... - Solid... - - - - Bars... - Balken... - - - - Tone... - Ton... - - - - Noise... - Rauschen... - - - - Unsaved Project - Ungespeichertes Projekt - - - - You must save this project before you can record audio in it. - Sie müssen das Projekt speichern, bevor Sie Audio aufnehmen können. - - - - Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) - Klicken Sie auf die Timeline, an welcher Stelle Sie mit der Aufnahme beginnen möchten (Ziehen, um das Limit der Aufnahme auf einen bestimmten Timeframe zu setzen) - - - - Pointer Tool - Pointer-Werkzeug - - - - Edit Tool - Bearbeitungs-Werkzeug - - - - Ripple Tool - Ripple-Werkzeug - - - - Razor Tool - Schneide-Werkzeug - - - - Slip Tool - - - - - Slide Tool - - - - - Hand Tool - Hand-Werkzeug - - - - Transition Tool - Übergangs-Werkzeug - - - - Snapping - Same as in english - Snapping - - - - Zoom In - Hereinzommen - - - - Zoom Out - Herauszoomen - - - - Record audio - Audio aufnehmen - - - - Add title, solid, bars, etc. - Titel, Solid, Balken, etc. Hinzufügen - - - - Nested Sequence - Geschachtelte Sequenz - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (keine) - - - - TimelineHeader - - - Center Timecodes - Timecodes zentrieren - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - &Rückgängig - - - - &Redo - - - - - R&ipple Delete Empty Space - - - - - Sequence Settings - Sequenz-Einstellungen - - - - &Speed/Duration - &Geschwindigkeit/Dauer - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - &Reveal in Project - &Im Projekt anzeigen - - - - Properties - Eigenschaften - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Start: %2 -Ende: %3 -Dauer: %4 - - - - Error - Fehler - - - - Couldn't locate media wrapper for sequence. - Konnte den Medienwrapper für diese Sequenz nicht finden. - - - - Title - Titel - - - - Solid Color - Solid - - - - Bars - Balken - - - - Tone - Ton - - - - Noise - Rauschen - - - - Duration: - Dauer: - - - - TimelineWidget - - - &Undo - &Rückgängig - - - - &Redo - - - - C&ut - &Ausschneiden - - - Cop&y - &Kopieren - - - &Paste - &Einfügen - - - R&ipple Delete - Taken from Premiere - R&ipple Delete - - - - Sequence Settings - Sequenz-Einstellungen - - - - &Speed/Duration - &Geschwindigkeit/Dauer - - - Auto-s&cale - Auto-&Skalierung - - - Enable/Disable - Einblenden/Ausblenden - - - Link/Unlink - Verbinden/Trennen - - - - &Reveal in Project - &Im Projekt anzeigen - - - R&ename - U&mbenennen - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Start: %2 -Ende: %3 -Dauer: %4 - - - Rename '%1' - '%1' umbenennen - - - Rename multiple clips - Mehrere Clips umbenennen - - - Enter a new name for this clip: - Geben Sie einen neuen Namen für den Clip ein: - - - - R&ipple Delete Empty Space - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - Properties - Eigenschaften - - - - Error - Fehler - - - - Couldn't locate media wrapper for sequence. - Konnte den Medienwrapper für diese Sequenz nicht finden. - - - - Title - Titel - - - - Solid Color - Solid - - - - Bars - Balken - - - - Tone - Ton - - - - Noise - Rauschen - - - - Duration: - Dauer: - - - - ToneEffect - - - Type - Typ - - - - Sine - Sinus - - - - Frequency - Frequenz - - - - Amount - Menge - - - - Mix - Same as in english - Mix - - - - Tone - Ton - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - Same as in english, differently spoken - Position - - - - Scale - Skalierung - - - - Uniform Scale - Einheitliche Skalierung - - - - Rotation - Same as in english, differently spoken - Rotation - - - - Anchor Point - Ankerpunkt - - - - Opacity - Deckkraft - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - Blend Mode - Mischmodus - - - Normal - Same as in english, differently spoken - Normal - - - Darken - Verdunkeln - - - Multiply - Vervielfachen - - - Color Burn - Makes no sense to translate - Color Burn - - - Linear Burn - Makes no sense to translate - Linear Burn - - - Lighten - Aufhellen - - - Screen - Makes no sense to translate - Screen - - - Color Dodge - Color-Dodge - - - Linear Dodge (Add) - Addieren - - - Overlay - Überlagern - - - Soft Light - Weiches Licht - - - Hard Light - Hartes Licht - - - Vivid Light - Lebhaftes Licht - - - Linear Light - Lineares Licht - - - Pin Light - Scharfes Licht - - - Hard Mix - Hartes Mischen - - - Difference - Differenz - - - Exclusion - Ausgrenzung - - - Reflect - Spiegeln - - - Substract - Abziehen - - - Average - Durschnitt - - - Glow - Leuchten - - - Negation - Negativ - - - Phoenix - Same as in english - Phoenix - - - - Transition - - Length: - Länge: - - - - Length - Länge - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - Ein Update ist für Olive ist verfügbar. Besuchen Sie www.olivevideoeditor.org um es herunterzuladen. - - - - VSTHost - - - - Error loading VST plugin - Fehler beim Laden des VST Plugins - - - Failed to create VST reference - Fehler beim Herstellen einer VST Referenz - - - - Failed to load VST plugin "%1": %2 - Fehler beim Laden des VST Plugins "%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. - HINWEIS: Sie können keine 32-bit VST Plugins in einer 64-bit Version von Olive laden. Sie benötigen entweder eine 64-bit Version des Plugins oder eine 32-bit Version von 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. - HINWEIS: Sie können keine 64-bit VST Plugins in einer 32-bit Version von Olive laden. Sie benötigen entweder eine 32-bit Version des Plugins oder eine 64-bit Version von Olive. - - - - Failed to locate entry point for dynamic library. - Kein Einstiegspunkt für dynamische Bibliothek gefunden. - - - - VST Error - VST Fehler - - - - Plugin's magic number is invalid - Die Magic Number des Plugins ist ungültig - - - - Plugin - Same as in english - Plugin - - - - Interface - Benutzeroberfläche - - - - Show - Anzeigen - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - Same as in english - VST Plugin - - - - Viewer - - Sequence Viewer - Sequenz-Viewer - - - Media Viewer - Medien-Viewer - - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (keine) - - - - Drag video only - - - - - Drag audio only - - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - Frame als Bild speichern... - - - - Show Fullscreen - Vollbildschirm - - - - Disable - Ausblenden - - - - Screen %1: %2x%3 - Screen %1:%2x%3 - - - - Zoom - Same as in english - Zoom - - - - Fit - Einpassen - - - - Custom - Benutzerdefiniert - - - - Close Media - Medien schließen - - - - Save Frame - Frame speichern - - - - Viewer Zoom - Makes no sense to translate - Viewer Zoom - - - - Set Custom Zoom Value: - Benutzerdefinierten Zoomwert angeben - - - - ViewerWindow - - - Exit Fullscreen - Vollbild verlassen - - - - VoidEffect - - - (unknown) - (unbekannt) - - - - Missing Effect - Effekt fehlt - - - - VolumeEffect - - - - Volume - Lautstärke - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - - transition - - Invalid transition - Ungültiger Übergang - - - No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. - Kein Kandidat für den Übergang '%1'. Der Übergang ist möglicherweise beschädigt. Eine Neuinstallation wird empfohlen. - - - diff --git a/ts/olive_es.ts b/ts/olive_es.ts deleted file mode 100644 index aaf3e1632..000000000 --- a/ts/olive_es.ts +++ /dev/null @@ -1,4209 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - - - - - ActionSearch - - - Search for action... - - - - - AdvancedVideoDialog - - - Advanced Video Settings - - - - - Pixel Format: - - - - - Threads: - - - - - Audio - - - %1 Audio - - - - - Recording %1 - - - - - AudioNoiseEffect - - - Amount - - - - - Mix - - - - - Noise - - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - - - - - Attack Threshold: - - - - - Attack Time: - - - - - Release Threshold: - - - - - Release Time: - - - - - Cacher - - - - Could not open %1 - %2 - - - - - ChannelLayoutName - - - Invalid - - - - - Mono - - - - - Stereo - - - - - ClipPropertiesDialog - - - "%1" Properties - - - - - Multiple Clip Properties - - - - - Name: - - - - - Duration: - - - - - (multiple) - - - - - CollapsibleWidget - - - <untitled> - - - - - ColorButton - - - Set Color - - - - - CornerPinEffect - - - Top Left - - - - - Top Right - - - - - Bottom Left - - - - - Bottom Right - - - - - Perspective - - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - DebugDialog - - - Debug Log - - - - - DemoNotice - - - - Welcome to 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. - - - - - 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 - - - - - Thank you for trying Olive and we hope you enjoy it! - - - - - EffectControls - - - Effects: - - - - - (none) - - - - - Add Video Effect - - - - - VIDEO EFFECTS - - - - - Add Video Transition - - - - - Add Audio Effect - - - - - AUDIO EFFECTS - - - - - Add Audio Transition - - - - - EffectUI - - - %1 (Opening) - - - - - %1 (Closing) - - - - - %1 (multiple) - - - - - Cu&t - - - - - &Copy - - - - - Move &Up - - - - - Move &Down - - - - - D&elete - - - - - Load Settings From File - - - - - Save Settings to File - - - - - EmbeddedFileChooser - - - File: - - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - - - - - Unknown codec name %1 - - - - - Export Failed - - - - - Export failed - %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% (ETA: %1:%2:%3) - - - - - Quality-based (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): - - - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - - - - - Target File Size (MB): - - - - - Format: - - - - - Range: - - - - - Entire Sequence - - - - - In to Out - - - - - Video - - - - - - Codec: - - - - - Width: - - - - - Height: - - - - - Frame Rate: - - - - - Compression Type: - - - - - Advanced - - - - - Audio - - - - - Sampling Rate: - - - - - Bitrate (Kbps/CBR): - - - - - ExportThread - - - failed to send frame to encoder (%1) - - - - - failed to receive packet from encoder (%1) - - - - - could not video encoder for %1 - - - - - could not allocate video stream - - - - - could not allocate video encoding context - - - - - could not open output video encoder (%1) - - - - - could not copy video encoder parameters to output stream (%1) - - - - - could not audio encoder for %1 - - - - - could not allocate audio stream - - - - - could not allocate audio encoding context - - - - - could not open output audio encoder (%1) - - - - - could not copy audio encoder parameters to output stream (%1) - - - - - could not allocate audio buffer (%1) - - - - - could not create output format context - - - - - could not open output file (%1) - - - - - could not write output file header (%1) - - - - - could not write output file trailer (%1) - - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - - - - - Fill Left with Right - - - - - Fill Right with Left - - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - - - - - Error loading Frei0r plugin - - - - - GraphEditor - - - Graph Editor - - - - - Linear - - - - - Bezier - - - - - Hold - - - - - GraphView - - - Zoom to Selection - - - - - Zoom to Show All - - - - - Reset View - - - - - InterlacingName - - - None (Progressive) - - - - - Upper Field First - - - - - Lower Field First - - - - - Invalid - - - - - KeyframeNavigator - - - Enable Keyframes - - - - - KeyframeView - - - Linear - - - - - Bezier - - - - - Hold - - - - - LabelSlider - - - &Edit - - - - - &Reset to Default - - - - - - Set Value - - - - - - New value: - - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - LoadDialog - - - Loading... - - - - - Loading '%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? - - - - - %1 - Line: %2 Col: %3 - - - - - User aborted loading - - - - - XML Parsing Error - - - - - Couldn't load '%1'. %2 - - - - - Project Load Error - - - - - Error loading project: %1 - - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - - Welcome to %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 - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - - - - - Frames - - - - - Drop Frame - - - - - Non-Drop Frame - - - - - Milliseconds - - - - - Title/Action Safe Area - - - - - Off - - - - - Default - - - - - 4:3 - - - - - 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 - - - - - Node 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 - - - - - Auto-Cut Silence - - - - - 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)) - - - - - Interlacing: - - - - - Audio Frequency: - - - - - Audio Channels: - - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - - - - - Name - - - - - Duration - - - - - Rate - - - - - MediaPropertiesDialog - - - "%1" Properties - - - - - Tracks: - - - - - Video %1: %2x%3 %4FPS - - - - - Audio %1: %2Hz %3 - - - - - %n channel(s) - - - - - - - - Conform to Frame Rate: - - - - - Alpha is Premultiplied - - - - - Auto (%1) - - - - - Interlacing: - - - - - Color Space: - - - - - 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. - - - - - Enter custom aspect ratio - - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - - - - - NewSequenceDialog - - - Editing "%1" - - - - - New Sequence - - - - - Preset: - - - - - Film 4K - - - - - TV 4K (Ultra HD/2160p) - - - - - 1080p - - - - - 720p - - - - - 480p - - - - - 360p - - - - - 240p - - - - - 144p - - - - - NTSC (480i) - - - - - PAL (576i) - - - - - Custom - - - - - Video - - - - - Width: - - - - - Height: - - - - - Frame Rate: - - - - - Pixel Aspect Ratio: - - - - - Square Pixels (1.0) - - - - - Interlacing: - - - - - None (Progressive) - - - - - Audio - - - - - Sample Rate: - - - - - Name: - - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - - - - - - Effect XML Settings %1 - - - - - Save Settings Failed - - - - - Failed to open "%1" for writing. - - - - - Load Effect Settings - - - - - - Load Settings Failed - - - - - Failed to open "%1" for reading. - - - - - This settings file doesn't match this effect. - - - - - OliveGlobal - - - Olive Project %1 - - - - - Auto-recovery - - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - - - - - 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? - - - - - Add - - - - - Replace - - - - - Skip - - - - - Do this for all conflicts found - - - - - Open Project... - - - - - Missing recent project - - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - - - - - Save Project As... - - - - - Unsaved Project - - - - - This project has changed since it was last saved. Would you like to save it before closing? - - - - - Import media... - - - - - All Files - - - - - No active sequence - - - - - Please open the sequence to perform this action. - - - - - No clips selected - - - - - Select the clips you wish to auto-cut - - - - - Missing Project File - - - - - Specified project '%1' does not exist. - - - - - PanEffect - - - - Pan - - - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - - Preferences - - - - - Default Sequence - - - - - Invalid CSS File - - - - - CSS file '%1' does not exist. - - - - - 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 - - - - - Delete All Previews - - - - - Are you sure you want to delete all previews? - - - - - Previews Deleted - - - - - Language: - - - - - Default Sequence Settings - - - - - Add Default Effects to New Clips - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - 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 - - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - - - - - Auto-Scale By Default - - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - - - - - Ask For Name When Setting Marker - - - - - Appearance - - - - - Theme - - - - - Olive Dark (Default) - - - - - Olive Light - - - - - Native - - - - - Native (Light Icons) - - - - - Use Native Menu Styling - - - - - Custom CSS: - - - - - - Browse - - - - - Image sequence formats: - - - - - Audio Recording: - - - - - Mono - - - - - Stereo - - - - - Effect Textbox Lines: - - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - - - - - Waveform Resolution: - - - - - Delete Previews - - - - - Use Software Fallbacks When Possible - - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - General - - - - - Behavior - - - - - Memory Usage - - - - - Upcoming Frame Queue: - - - - - - frames - - - - - - seconds - - - - - Previous Frame Queue: - - - - - Playback - - - - - Output Device: - - - - - - Default - - - - - Input Device: - - - - - Sample Rate: - - - - - Audio - - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - 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 - - - - - Could not find stream information - %1 - - - - - Project - - - New - - - - - Open Project - - - - - Save Project - - - - - Undo - - - - - Redo - - - - - Tree View - - - - - Icon View - - - - - List View - - - - - Search media, markers, etc. - - - - - Project - - - - - - 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' - - - - - 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? - - - - - Skip - - - - - No sequence is active, please open the sequence you want to delete clips from. - - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - - - - - Image sequence detected - - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - - - - - ProxyDialog - - - Create Proxy - - - - - Proxy - - - - - Dimensions: - - - - - Same Size as Source - - - - - Half Resolution (1/2) - - - - - Quarter Resolution (1/4) - - - - - Eighth Resolution (1/8) - - - - - Sixteenth Resolution (1/16) - - - - - Format: - - - - - ProRes HQ - - - - - Location: - - - - - Same as Source (in "%1" folder) - - - - - Proxy file exists - - - - - The file "%1" already exists. Do you wish to replace it? - - - - - Custom Location - - - - - ProxyGenerator - - - Finished generating proxy for "%1" - - - - - ReplaceClipMediaDialog - - - Replace clips using "%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 - - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - - - - - ShakeEffect - - - Intensity - - - - - Rotation - - - - - Frequency - - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - - - - - Solid Color - - - - - SMPTE Bars - - - - - Checkerboard - - - - - Opacity - - - - - Color - - - - - Checkerboard Size - - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - - - - - New - - - - - View - - - - - Tree View - - - - - Icon View - - - - - Show Toolbar - - - - - Show Sequences - - - - - Replace/Relink Media - - - - - Reveal in Explorer - - - - - Reveal in 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 - - - - - Create/Modify Proxy - - - - - Create Proxy - - - - - Modify Proxy - - - - - Restore Original - - - - - Delete - - - - - Preview in Media Viewer - - - - - Properties... - - - - - Replace '%1' - - - - - All Files - - - - - Replace Media - - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - - - - - Delete proxy - - - - - Would you like to delete the proxy file "%1" as well? - - - - - SpeedDialog - - - Speed/Duration - - - - - Speed: - - - - - Frame Rate: - - - - - Duration: - - - - - Reverse - - - - - Maintain Audio Pitch - - - - - Ripple Changes - - - - - TextEditDialog - - - Edit Text - - - - - Thin - - - - - Extra Light - - - - - Light - - - - - Normal - - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - - - - - &Edit Text - - - - - TextEffect - - - - Text - - - - - Font - - - - - Size - - - - - Color - - - - - Horizontal Alignment - - - - - Left - - - - - - Center - - - - - Right - - - - - Justify - - - - - Vertical Alignment - - - - - Top - - - - - Bottom - - - - - Word Wrap - - - - - Padding - - - - - Position - - - - - Outline - - - - - Outline Color - - - - - Outline Width - - - - - Shadow - - - - - Shadow Color - - - - - Shadow Angle - - - - - Shadow Distance - - - - - Shadow Softness - - - - - Shadow Opacity - - - - - Sample Text - - - - - Render - - - - - Generate simple text over this clip - - - - - TimecodeEffect - - - - Timecode - - - - - Sequence - - - - - Media - - - - - Scale - - - - - Color - - - - - Background Color - - - - - Background Opacity - - - - - Offset - - - - - Prepend - - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - - Nested Sequence - - - - - 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) - - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - - - - - 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. - - - - - TimelineHeader - - - Center Timecodes - - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - - - - - &Redo - - - - - R&ipple Delete Empty Space - - - - - Sequence Settings - - - - - &Speed/Duration - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - &Reveal in Project - - - - - Properties - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - - - - - Error - - - - - Couldn't locate media wrapper for sequence. - - - - - Title - - - - - Solid Color - - - - - Bars - - - - - Tone - - - - - Noise - - - - - Duration: - - - - - TimelineWidget - - - &Undo - - - - - &Redo - - - - - Sequence Settings - - - - - &Speed/Duration - - - - - &Reveal in Project - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - - - - - R&ipple Delete Empty Space - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - Properties - - - - - Error - - - - - Couldn't locate media wrapper for sequence. - - - - - Title - - - - - Solid Color - - - - - Bars - - - - - Tone - - - - - Noise - - - - - Duration: - - - - - ToneEffect - - - Type - - - - - Sine - - - - - Frequency - - - - - Amount - - - - - Mix - - - - - Tone - - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - - - - - Scale - - - - - Uniform Scale - - - - - Rotation - - - - - Anchor Point - - - - - Opacity - - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - - Transition - - - Length - - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - - - - - VSTHost - - - - Error loading VST plugin - - - - - Failed to load VST plugin "%1": %2 - - - - - Failed to locate entry point for dynamic library. - - - - - VST Error - - - - - Plugin's magic number is invalid - - - - - Plugin - - - - - Interface - - - - - Show - - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - - - - - Viewer - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - - - - - Drag video only - - - - - Drag audio only - - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - - - - - Show Fullscreen - - - - - Disable - - - - - Screen %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 - - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - diff --git a/ts/olive_fr.ts b/ts/olive_fr.ts deleted file mode 100644 index f8475eb4b..000000000 --- a/ts/olive_fr.ts +++ /dev/null @@ -1,4833 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - Olive est un logiciel de montage non-linéaire. Ce logiciel est libre et protégé par la licence GNU GPL. - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - L'équipe d'Olive vous informe que le code source d'Olive est disponible au téléchargement sur son site Web. - - - - ActionSearch - - - Search for action... - Rechercher une action… - - - - AdvancedVideoDialog - - - Advanced Video Settings - Paramètres vidéo avancés - - - - Pixel Format: - Format de pixel : - - - - Threads: - - - - - Audio - - Audio - Audio - - - Recording - Enregistrement audio - - - - %1 Audio - - - - - Recording %1 - - - - - AudioNoiseEffect - - - Amount - Quantité - - - - Mix - Mélanger - - - - Noise - Bruit - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - - - - - Attack Threshold: - - - - - Attack Time: - - - - - Release Threshold: - - - - - Release Time: - - - - - Cacher - - - - Could not open %1 - %2 - - - - - ChannelLayoutName - - - Invalid - Invalide - - - - Mono - Mono - - - - Stereo - Stéréo - - - - ClipPropertiesDialog - - - "%1" Properties - "%1" Propriétés - - - - Multiple Clip Properties - - - - - Name: - Nom : - - - - Duration: - Durée : - - - - (multiple) - - - - - CollapsibleWidget - - - <untitled> - &lt;Sans titre&gt; - - - - ColorButton - - - Set Color - Définir la couleur - - - - CornerPinEffect - - - Top Left - En haut à gauche - - - - Top Right - En haut à droite - - - - Bottom Left - En bas à gauche - - - - Bottom Right - En bas à droite - - - - Perspective - Perspective - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - DebugDialog - - - Debug Log - Journal de débogage - - - - DemoNotice - - - - Welcome to Olive! - Bienvenue dans 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 est un logiciel libre et open-source distribué sous la licence GNU GPL. Si vous avez payé pour ce logiciel, vous avez été victime d'un scam. - - - - 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 - Ce logiciel est actuellement en ALPHA, ce qui signifie qu'il a de grandes chances de planter, d'avoir des bugs ou de manquer de certaines fonctions. Nous n'offrons aucune garantie, utilisez-le à vos propres risques. Merci de nous rapporter tout bug ou demande d'ajout d'une fonctionnalité à %1 - - - - Thank you for trying Olive and we hope you enjoy it! - Merci d'utiliser Olive, nous espérons que vous l'apprécierez ! - - - - Effect - - Invalid effect - Effet invalide - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - Aucun candidat pour l'effet '%1'. C'est effet est peut-être corrompu. Essayez de le réinstaller, ou de réinstaller Olive. - - - Cu&t - &Couper - - - &Copy - Cop&ier - - - Move &Up - Déplacer vers le &haut - - - Move &Down - Déplacer vers le &bas - - - D&elete - &Supprimer - - - Load Settings From File - Charger les paramètres - - - Save Settings to File - Enregistrer les paramètres - - - Save Effect Settings - Enregistrer les paramètres d'effet - - - Effect XML Settings %1 - Paramètres d'effet XML %1 - - - Save Settings Failed - L'enregistrement des paramètres a échoué - - - Failed to open "%1" for writing. - Impossible d'écrire dans "%1". - - - Load Effect Settings - Charger les paramètres d'effet - - - Load Settings Failed - Le chargement des paramètres a échoué - - - Failed to open "%1" for reading. - Impossible de lire "%1". - - - This settings file doesn't match this effect. - Ce fichier de paramètre ne correspond pas à cet effet. - - - - EffectControls - - - Effects: - Effets : - - - &Paste - C&oller - - - - (none) - (aucun) - - - - Add Video Effect - Ajouter un effet vidéo - - - - VIDEO EFFECTS - EFFETS VIDÉO - - - - Add Video Transition - Ajouter une transition vidéo - - - - Add Audio Effect - Ajouter un effet audio - - - - AUDIO EFFECTS - EFFETS AUDIO - - - - Add Audio Transition - Ajouter une transition audio - - - (Multiple clips selected) - (Clips multiples sélectionnés) - - - - EffectRow - - Disable Keyframes - Désactiver les images-clés - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Désactiver les images-clés supprimera toutes les images-clés courantes. Êtes-vous sûr⋅e de vouloir cela ? - - - - EffectUI - - - %1 (Opening) - - - - - %1 (Closing) - - - - - %1 (multiple) - - - - - Cu&t - &Couper - - - - &Copy - Cop&ier - - - - Move &Up - Déplacer vers le &haut - - - - Move &Down - Déplacer vers le &bas - - - - D&elete - &Supprimer - - - - Load Settings From File - Charger les paramètres - - - - Save Settings to File - Enregistrer les paramètres - - - - EmbeddedFileChooser - - - File: - Fichier : - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - Exporter "%1" - - - - Unknown codec name %1 - Nom de codec inconnu %1 - - - - Export Failed - L'export a échoué - - - - Export failed - %1 - Export échoué - %1 - - - - Invalid dimensions - Dimensions invalides - - - - Export width and height must both be even numbers/divisible by 2. - La largeur et la hauteur d'export doivent être des nombres pairs/divisibles par 2. - - - - Invalid codec - Codec invalide - - - - Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. - Impossible de déterminer les paramètres de sortie pour le codec sélectionné. Ceci est un bug, merci de contacter les développeurs. - - - - Invalid format - Format invalide - - - - Couldn't determine output format. This is a bug, please contact the developers. - Impossible de déterminer le format de sortie. Ceci est un bug, merci de contacter les développeurs. - - - - Export Media - Exporter le média - - - - %p% (Total: %1:%2:%3) - - - - - %p% (ETA: %1:%2:%3) - - - - - Quality-based (Constant Rate Factor) - Qualitatif (Constant Rate Factor) - - - - Constant Bitrate - Débit binaire constant - - - - - Invalid Codec - Codec invalide - - - - Failed to find a suitable encoder for this codec. Export will likely fail. - Impossible de trouver un encodeur approprié pour ce codec. L'export risque de planter. - - - - Failed to find pixel format for this encoder. Export will likely fail. - Impossible de trouver un format de pixel pour cet encodeur. L'export risque de planter. - - - - Bitrate (Mbps): - Débit binaire (Mbps) : - - - - Quality (CRF): - Qualité (CRF) : - - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - Facteur de qualité : - -0 = sans perte -17-18 = visuellement sans perte (compressé, mais imperceptible) -23 = haute qualité -51 = qualité la plus basse - - - - Target File Size (MB): - Taille du fichier cible (Mo) : - - - - Format: - Format : - - - - Range: - Plage : - - - - Entire Sequence - Séquence entière - - - - In to Out - Du point d'entrée au point de sortie - - - - Video - Vidéo - - - - - Codec: - Codec : - - - - Width: - Largeur : - - - - Height: - Hauteur : - - - - Frame Rate: - Images par seconde : - - - - Compression Type: - Type de compression : - - - - Advanced - Avancé - - - - Audio - Audio - - - - Sampling Rate: - Taux d'échantillonnage : - - - - Bitrate (Kbps/CBR): - Débit binaire (Kbps/CBR) : - - - - ExportThread - - - failed to send frame to encoder (%1) - Échec de l'envoi d'une image vers l'encodeur (%1) - - - - failed to receive packet from encoder (%1) - Échec de la réception d'un paquet depuis l'encodeur (%1) - - - - could not video encoder for %1 - Impossible d'encoder la vidéo pour %1 - - - - could not allocate video stream - impossible d'allouer le flux vidéo - - - - could not allocate video encoding context - impossible d'allouer le contexte d'encodage vidéo - - - - could not open output video encoder (%1) - impossible d'ouvrir l'encodeur vidéo de sortie (%1) - - - - could not copy video encoder parameters to output stream (%1) - impossible de copier les paramètres d'encodage vidéo vers le flux de sortie (%1) - - - - could not audio encoder for %1 - impossible d'encoder l'audio pour %1 - - - - could not allocate audio stream - impossible d'allouer le flux audio - - - - could not allocate audio encoding context - impossible d'allouer le contexte d'encodage audio - - - - could not open output audio encoder (%1) - impossible d'ouvrir l'encodeur audio de sortie (%1) - - - - could not copy audio encoder parameters to output stream (%1) - impossible de copier les paramètres d'encodage audio vers le flux de sortie (%1) - - - - could not allocate audio buffer (%1) - impossible d'allouer le buffer audio (%1) - - - - could not create output format context - impossible de créer le contexte du format de sortie - - - - could not open output file (%1) - impossible d'ouvrir le fichier de sortie (%1) - - - - could not write output file header (%1) - impossible d'écrire l'en-tête du fichier de sortie (%1) - - - - could not write output file trailer (%1) - impossible d'écrire le trailer du fichier (%1) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Type - - - - Fill Left with Right - Remplir la gauche avec la droite - - - - Fill Right with Left - Remplir la droite avec la gauche - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - Impossible de charger le 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. - NOTE : Vous ne pouvez pas charger de plugin Frei0r 32-bit dans la version 64-bit d'Olive. Essayez de trouver une version 64-bit de ce plugin ou basculez vers Olive 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. - NOTE : Vous ne pouvez pas charger de plugin Frei0r 64-bit dans la version 32-bit d'Olive. Essayez de trouver une version 32-bit de ce plugin ou basculez vers Olive 64-bit. - - - - Error loading Frei0r plugin - Erreur durant le chargement du plugin Frei0r - - - - GraphEditor - - - Graph Editor - Éditeur de graphes - - - - Linear - Linéaire - - - - Bezier - Bézier - - - - Hold - Maintenir - - - - GraphView - - - Zoom to Selection - Zoomer sur la sélection - - - - Zoom to Show All - Zoomer pour tout montrer - - - - Reset View - Réinitialiser la vue - - - - InterlacingName - - - None (Progressive) - Aucun (Progressif) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - Trame supérieure en premier - - - Bottom Field First - Trame inférieure en premier - - - - Invalid - Invalide - - - - KeyframeNavigator - - - Enable Keyframes - Activer les images-clés - - - - KeyframeView - - - Linear - Linéaire - - - - Bezier - Bézier - - - - Hold - Maintenir - - - - LabelSlider - - - &Edit - &Édition - - - - &Reset to Default - - - - - - Set Value - Définir la valeur - - - - - New value: - Nouvelle valeur : - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - LoadDialog - - - Loading... - Cargement… - - - - Loading '%1'... - Chargement '%1'… - - - - Cancel - Annuler - - - - LoadThread - - - Version Mismatch - Incompatibilité de version - - - - 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? - Ce projet a été enregistré avec une version différente d'Olive et peut ne pas être totalement compatible avec celle-ci. Voulez-vous essayer de l'ouvrir malgré tout ? - - - Invalid Clip Link - Lien du clip invalide - - - This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? - Ce projet contient un lien de clip invalide. Il peut être corrompu. Voulez-vous l'ouvrir malgré tout ? - - - - %1 - Line: %2 Col: %3 - %1 - Ligne : %2 Col. : %3 - - - - User aborted loading - L'utilisateur a abandonné le chargement - - - - XML Parsing Error - Erreur de parsage XML - - - - Couldn't load '%1'. %2 - Impossible de charger '%1'. %2 - - - - Project Load Error - Erreur dans le chargement du projet - - - - Error loading project: %1 - Erreur lors du chargement du projet : %1 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - Auto-recovery - Récupération automatique - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive ne s'est pas fermé convenablement et un fichier de récupépration a été détecté. Souhaitez-vous l'ouvrir ? - - - &Project - &Projet - - - &Sequence - &Séquence - - - &Folder - &Dossier - - - Set In Point - Définir le point d'entrée - - - Set Out Point - Définir le point de sortie - - - - Welcome to %1 - Bienvenue à %1 - - - Reset In Point - Réinitialiser le point d'entrée - - - Reset Out Point - Réinitialiser le point de sortie - - - Clear In/Out Point - Effacer le point d'entrée/de sortie - - - No active sequence - Pas de séquence active - - - Please open the sequence you wish to export. - Veuillez ouvrir la séquence que vous souhaitez exporter. - - - Save Project As... - Enregistrer sous… - - - Unsaved Project - Projet non-sauvegardé - - - This project has changed since it was last saved. Would you like to save it before closing? - Ce projet a été modifié depuis la dernière sauvegarde. Souhaitez-vous l'enregistrer avant de fermer ? - - - - &File - &Fichier - - - - &New - &Nouveau - - - - &Open Project - &Ouvrir un projet - - - - Clear Recent List - Nettoyer la liste des projets récents - - - - Open Recent - Ouvrir un projet récent - - - - &Save Project - &Enregistrer le projet - - - - Save Project &As - Enregistrer le projet &sous - - - - &Import... - &Importer… - - - - &Export... - &Exporter… - - - - E&xit - &Quitter - - - - &Edit - &Édition - - - - &Undo - &Annuler - - - - Redo - Rétablir - - - Cu&t - &Couper - - - Cop&y - Cop&ier - - - &Paste - C&oller - - - Paste Insert - Coller et Insérer - - - Duplicate - Dupliquer - - - Delete - Supprimer - - - Ripple Delete - Supprimer et raccorder - - - Split - Séparer - - - - Select &All - Sélectionner &tout - - - - Deselect All - Tout désélectionner - - - Add Default Transition - Ajouter la transition par défaut - - - Link/Unlink - Lier/Délier - - - Enable/Disable - Activer/Désactiver - - - Nest - Imbriquer - - - - Ripple to In Point - Not literal, but it says what it is - Propager au point d'entrée - - - - Ripple to Out Point - Not literal, but it says what it is - Propager au point de sortie - - - - Edit to In Point - Éditer comme point d'entrée - - - - Edit to Out Point - Éditer comme point de sortie - - - - Delete In/Out Point - Supprimer les points d'entrée/de sortie - - - - Ripple Delete In/Out Point - Supprimer et raccorder au point d'entrée/de sortie - - - - Set/Edit Marker - Définir/Éditer un marqueur - - - - &View - &Affichage - - - - Zoom In - Zommer - - - - Zoom Out - Dézoomer - - - - Increase Track Height - Augmenter la hauteur de piste - - - - Decrease Track Height - Diminuer la hauteur de piste - - - - Toggle Show All - Vue d'ensemble - - - Track Lines - Contours des pistes - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - Formes d'onde ajustées - - - - Frames - Images - - - - Drop Frame - Drop Frame - - - - Non-Drop Frame - Non-Drop Frame - - - - Milliseconds - Millisecondes - - - - Title/Action Safe Area - Zone sûre de titre/d'action - - - - Off - Désactivée - - - - Default - Par défaut - - - - 4:3 - 4:3 - - - - 16:9 - 16:9 - - - - Custom - Personnalisée - - - - Full Screen - Plein-écran - - - - Full Screen Viewer - Lecteur en plein écran - - - - &Playback - &Lecture - - - - Go to Start - Aller au début - - - - Previous Frame - Image précédente - - - - Play/Pause - Lire/Pause - - - - Play In to Out - Lire entre les points d'entrée et de sortie - - - - Next Frame - Image suivante - - - - Go to End - Aller à la fin - - - - Go to Previous Cut - Aller au point d'édition précédent - - - - Go to Next Cut - Aller au point d'édition suivant - - - - Go to In Point - Aller au point d'entrée - - - - Go to Out Point - Aller au point de sortie - - - - Shuttle Left - Jouer vers la gauche - - - - Shuttle Stop - Arrêter - - - - Shuttle Right - Jouer vers la droite - - - - Loop - Boucle - - - - &Window - &Fenêtre - - - - Project - Projet - - - - Effect Controls - Propriétés des effets - - - - Timeline - Ligne du temps - - - - Graph Editor - Éditeur de graphes - - - - Node Editor - - - - - Media Viewer - Lecteur de média - - - - Sequence Viewer - Lecteur de séquence - - - - Maximize Panel - Agrandir le panneau - - - - Lock Panels - - - - - Reset to Default Layout - Restaurer la disposition par défaut - - - - &Tools - &Outils - - - - Pointer Tool - Curseur - - - - Edit Tool - Éditer - - - - Ripple Tool - Propagation - - - - Razor Tool - Cutter - - - - Slip Tool - Déplacer dessous - - - - Slide Tool - Déplacer dessus - - - - Hand Tool - Main - - - - Transition Tool - Transition - - - - Enable Snapping - Autoriser le magnétisme - - - - Auto-Cut Silence - - - - Selecting Also Seeks - Sélectionner déplace la tête de lecture - - - Edit Tool Also Seeks - Éditer déplace la tête de lecture - - - Edit Tool Selects Links - Éditer sélectionne les liens - - - Seek Also Selects - Sélectionner avec la tête de lecture - - - Seek to the End of Pastes - Placer la tête de lecture après le collage - - - Scroll Wheel Zooms - Zoomer avec la molette - - - Enable Drag Files to Timeline - Autoriser le dépôt de fichier sur la ligne de temps - - - Auto-Scale By Default - Échelle automatique par défaut - - - Enable Seek to Import - Déplacer la tête de lecture à l'import - - - Audio Scrubbing - Lire l'audio au déplacement de la tête de lecture - - - Enable Drop on Media to Replace - Déposer sur un média pour le remplacer - - - Enable Hover Focus - Activer le focus au survol - - - Ask For Name When Setting Marker - Demander un nom à la création d'un marqueur - - - - No Auto-Scroll - Pas de défilement automatique - - - - Page Auto-Scroll - Défilement paginé - - - - Smooth Auto-Scroll - Défilement doux - - - - Preferences - Préférences - - - - Clear Undo - Nettoyer la pile d'annulation - - - - &Help - &Aide - - - - A&ction Search - Chercher une a&ction - - - - Debug Log - Journal de débogage - - - - &About... - &À propos… - - - - <untitled> - &lt;Sans titre&gt; - - - Open Project... - Ouvrir un projet… - - - Missing recent project - Projet récent manquant - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Le projet '%1' n'existe plus. Voulez-vous le retirer de la liste des projets récents ? - - - Invalid aspect ratio - Ratio d'image invalide - - - The aspect ratio '%1' is invalid. Please try again. - Le ratio d'image '%1' est invalide. Merci de réessayer à nouveau. - - - Enter custom aspect ratio - Entrez un ratio d'image personnalisé - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Entrez le ratio de la zone sûre de titre/d'action (ex: 16:9) : - - - Nested Sequence - Séquence imbriquée - - - - Marker - - - - Set Marker - Définir un marqueur - - - - Set clip marker name: - Définir le nom du marqueur de clip : - - - - Set sequence marker name: - Définir le nom du marqueur de séquence : - - - - Media - - - New Folder - Nouveau dossier - - - - Name: - Nom : - - - - Filename: - Nom de fichier : - - - - Video Dimensions: - Dimensions de la vidéo : - - - - Frame Rate: - Images par seconde : - - - - %1 field(s) (%2 frame(s)) - %1 trame(s) (%2 image(s)) - - - - Interlacing: - Entrelacement : - - - - Audio Frequency: - Fréquence audio : - - - - Audio Channels: - Canaux audio : - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - Nom : %1 -Dimensions vidéo : %2x%3 -Images par seconde : %4 -Fréquence audio: %5 -Canaux audio : %6 - - - - Name - Nom - - - - Duration - Durée - - - - Rate - Images par seconde - - - - MediaPropertiesDialog - - - "%1" Properties - "%1" Propriétés - - - - Tracks: - Pistes : - - - - Video %1: %2x%3 %4FPS - Vidéo %1 : %2×%3 %4 i/s - - - - Audio %1: %2Hz %3 - Audio %1 : %2 Hz %3 - - - - %n channel(s) - - %n canal - %n canaux - - - - - Conform to Frame Rate: - Conformer aux images par seconde : - - - - Alpha is Premultiplied - Le canal alpha est prémultiplié - - - - Auto (%1) - Auto (%1) - - - - Interlacing: - Entrelacement : - - - - Color Space: - - - - - Name: - Nom : - - - - MenuHelper - - - &Project - &Projet - - - - &Sequence - &Séquence - - - - &Folder - &Dossier - - - - Set In Point - Définir le point d'entrée - - - - Set Out Point - Définir le point de sortie - - - - Reset In Point - Réinitialiser le point d'entrée - - - - Reset Out Point - Réinitialiser le point de sortie - - - - Clear In/Out Point - Effacer le point d'entrée/de sortie - - - - Add Default Transition - Ajouter la transition par défaut - - - - Link/Unlink - Lier/Délier - - - - Enable/Disable - Activer/Désactiver - - - - Nest - Imbriquer - - - - Cu&t - &Couper - - - - Cop&y - Cop&ier - - - - - &Paste - C&oller - - - - Paste Insert - Coller et Insérer - - - - Duplicate - Dupliquer - - - - Delete - Supprimer - - - - Ripple Delete - Supprimer et raccorder - - - - Split - Séparer - - - - Invalid aspect ratio - Ratio d'image invalide - - - - The aspect ratio '%1' is invalid. Please try again. - Le ratio d'image '%1' est invalide. Merci de réessayer à nouveau. - - - - Enter custom aspect ratio - Entrez un ratio d'image personnalisé - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Entrez le ratio de la zone sûre de titre/d'action (ex: 16:9) : - - - - NewSequenceDialog - - - Editing "%1" - Édition "%1" - - - - New Sequence - Nouvelle séquence - - - - Preset: - Préréglage : - - - - Film 4K - Film 4K - - - - 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 - Personnalisé - - - - Video - Vidéo - - - - Width: - Largeur : - - - - Height: - Hauteur : - - - - Frame Rate: - Images par seconde : - - - - Pixel Aspect Ratio: - Ratio des pixels : - - - - Square Pixels (1.0) - Pixels carré (1,0) - - - - Interlacing: - Entrelacement : - - - - None (Progressive) - Aucun (Progressif) - - - - Audio - Audio - - - - Sample Rate: - Taux d'échantillonnage : - - - - Name: - Nom : - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - Désactiver les images-clés - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Désactiver les images-clés supprimera toutes les images-clés courantes. Êtes-vous sûr⋅e de vouloir cela ? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - Média - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - Enregistrer les paramètres d'effet - - - - - Effect XML Settings %1 - Paramètres d'effet XML %1 - - - - Save Settings Failed - L'enregistrement des paramètres a échoué - - - - Failed to open "%1" for writing. - Impossible d'écrire dans "%1". - - - - Load Effect Settings - Charger les paramètres d'effet - - - - - Load Settings Failed - Le chargement des paramètres a échoué - - - - Failed to open "%1" for reading. - Impossible de lire "%1". - - - - This settings file doesn't match this effect. - Ce fichier de paramètre ne correspond pas à cet effet. - - - - OliveGlobal - - - Olive Project %1 - - - - - Auto-recovery - Récupération automatique - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive ne s'est pas fermé convenablement et un fichier de récupépration a été détecté. Souhaitez-vous l'ouvrir ? - - - - Effect already exists - L'effet existe déjà - - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Le clip '%1' contient déjà un effet '%2'. SOuhaitez-vous le remplacer par l'effet du presse-papier ou ajouter celui comme un effet distinct ? - - - - Add - Ajouter - - - - Replace - Remplacer - - - - Skip - Passer - - - - Do this for all conflicts found - Faire ceci pour tous les conflits - - - - Open Project... - Ouvrir un projet… - - - - Missing recent project - Projet récent manquant - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Le projet '%1' n'existe plus. Voulez-vous le retirer de la liste des projets récents ? - - - - Save Project As... - Enregistrer sous… - - - - Unsaved Project - Projet non-sauvegardé - - - - This project has changed since it was last saved. Would you like to save it before closing? - Ce projet a été modifié depuis la dernière sauvegarde. Souhaitez-vous l'enregistrer avant de fermer ? - - - - Import media... - Importer un média… - - - - All Files - Tous les fichiers - - - - No active sequence - Pas de séquence active - - - - Please open the sequence to perform this action. - - - - - No clips selected - - - - - Select the clips you wish to auto-cut - - - - Please open the sequence you wish to export. - Veuillez ouvrir la séquence que vous souhaitez exporter. - - - - Missing Project File - - - - - Specified project '%1' does not exist. - - - - - PanEffect - - - - Pan - Panoramique - - - - Modifying the panning on a stereo audio clip. - - - - - Playback - - Generating Proxy: %1% - Génération du proxy : %1% - - - - PreferencesDialog - - - Preferences - Préférences - - - - Invalid CSS File - Fichier CSS invalide - - - - CSS file '%1' does not exist. - Le fichier CSS '%1' n'existe pas. - - - Warning - Avertissement - - - Some changed settings will require restarting Olive to take effect - Certains paramètres modifiés nécessitent le redémarrage d'Olive pour prendre effet - - - - Confirm Reset All Shortcuts - Confirmez la réinitialisation de tous les raccourcis clavier - - - - Are you sure you wish to reset all keyboard shortcuts to their defaults? - Êtes-vous sûr⋅e de vouloir réinitialiser tous les raccourcis clavier à leur valeur par défaut ? - - - - Import Keyboard Shortcuts - Importer les raccourcis clavier - - - - - Error saving shortcuts - Erreur dans l'enregistrement des raccourcis - - - - Failed to open file for reading - Échec de l'ouverture du fichier - - - - Export Keyboard Shortcuts - Exporter les raccourcis clavier - - - - Export Shortcuts - Exporter les raccourcis - - - - Shortcuts exported successfully - Les raccourcis ont été exporté avec succès - - - - Failed to open file for writing - Échec de l'ouverture du fichier - - - - Browse for CSS file - Choisir un fichier CSS - - - - Delete All Previews - Supprimer toutes les prévisualisations - - - - Are you sure you want to delete all previews? - Êtes-vous sûr⋅e de vouloir supprimer toutes les prévisualisations ? - - - - Previews Deleted - Prévisualisations supprimées - - - All previews deleted succesfully. You may have to re-open your current project for changes to take effect. - Toutes les prévisualisations ont été supprimées avec succès. Il est possible que vous deviez ré-ouvrir le projet actuel pour que les changements prennent effet. - - - - Language: - Langue : - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - Default Sequence Settings - - - - - Add Default Effects to New Clips - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - Selecting Also Seeks - Sélectionner déplace la tête de lecture - - - - Edit Tool Also Seeks - Éditer déplace la tête de lecture - - - - Edit Tool Selects Links - Éditer sélectionne les liens - - - - Seek Also Selects - Sélectionner avec la tête de lecture - - - - Seek to the End of Pastes - Placer la tête de lecture après le collage - - - - Scroll Wheel Zooms - Zoomer avec la molette - - - - Hold CTRL to toggle this setting - - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - Autoriser le dépôt de fichier sur la ligne de temps - - - - Auto-Scale By Default - Échelle automatique par défaut - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - Lire l'audio au déplacement de la tête de lecture - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - Activer le focus au survol - - - - Ask For Name When Setting Marker - Demander un nom à la création d'un marqueur - - - - Appearance - - - - - Theme - - - - - Olive Dark (Default) - - - - - Olive Light - - - - - Native - - - - - Native (Light Icons) - - - - - Use Native Menu Styling - - - - - Custom CSS: - CSS personnalisé : - - - - - Browse - Parcourir - - - - Image sequence formats: - Formats de séquence d'image : - - - - Audio Recording: - Enregistrement audio : - - - - Mono - Mono - - - - Stereo - Stéréo - - - - Effect Textbox Lines: - Lignes des boîtes de texte d'effet : - - - - Default Sequence - - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - Résolution des miniatures : - - - - Waveform Resolution: - Résolution des formes d'onde : - - - - Delete Previews - Supprimer les prévisualisations - - - - Use Software Fallbacks When Possible - Utiliser les solutions de repli logicielles quand cela est possible - - - - General - Général - - - - Behavior - Comportement - - - Seeking - Tête de lecture - - - Accurate Seeking -Always show the correct frame (visual may pause briefly as correct frame is retrieved) - Recherche fidèle -Tojours montrer l'image exacte (la prévisualisation peut se mettre en pause brièvement quand la bonne image est en cours de récupération) - - - Fast Seeking -Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) - Recherhe rapide -Montrer rapidement (la prévisualition peut montrer brièvement des images imprécises lors du déplacement de la tête de lecture − cela n'affecte pas la lecture et l'export) - - - - Memory Usage - Utilisation de la mémoire - - - - Upcoming Frame Queue: - File d'image à venir : - - - - - frames - images - - - - - seconds - secondes - - - - Previous Frame Queue: - File d'image précédentes : - - - - Playback - Lecture - - - - Output Device: - Système de sortie : - - - - - Default - Défaut - - - - Input Device: - Système d'entrée : - - - - Sample Rate: - Taux d'échantillonnage : - - - - Audio - Audio - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - Search for action or shortcut - Rechercher une action ou un raccourci - - - - Action - Action - - - - Shortcut - Raccourci - - - - Import - Importer - - - - Export - Exporter - - - - Reset Selected - Réinitialiser la sélection - - - - Reset All - Tout réinitialiser - - - - Keyboard - Clavier - - - - PreviewGenerator - - - Failed to find any valid video/audio streams - - - - - Could not open file - %1 - Impossible d'ouvrir le fichier - %1 - - - - Could not find stream information - %1 - Impossible de trouver les informations de flux - %1 - - - - Project - - - New - Nouveau - - - - Open Project - - - - - Save Project - - - - - Undo - - - - - Redo - Rétablir - - - - Tree View - Vue arborescente - - - - Icon View - Vue par icônes - - - - List View - - - - - Search media, markers, etc. - Rechercher des médias, marqueurs, etc. - - - - Project - Projet - - - Sequence - Séquence - - - Replace '%1' - Remplacer '%1' - - - All Files - Tous les fichiers - - - - - No active sequence - Pas de séquence active - - - - No sequence is active, please open the sequence you want to replace clips from. - Pas de séquence active, veuillez ouvrir la séquence dont vous souhaitez modifier les clips. - - - - Active sequence selected - Séquence active sélectionnée - - - - You cannot insert a sequence into itself, so no clips of this media would be in this sequence. - Vous ne pouvez pas insérer une séquence à l'intérieur d'elle-même, donc aucun clip de ce média ne peut être dans cette séquence. - - - - Rename '%1' - Renommer '%1' - - - - Enter new name: - Entrez le nouveau nom : - - - - Delete media in use? - Supprimer un média en cours d'utilisation ? - - - - 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? - Le média '%1' est actuellement utilisé dans '%2', le supprimer effacera toutes les instances dans la séquence. Êtes-vous sûr⋅e de vouloir cela ? - - - - Skip - Passer - - - Image sequence detected - Séquence d'image détectée - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Le fichier '%1' semble faire partie d'une séquence d'image. Voulez-vous l'importer comme tel ? - - - Import media... - Importer un média… - - - - No sequence is active, please open the sequence you want to delete clips from. - Aucune séquence n'est active, veuillez sélectionner la séquence dont vous souhaitez supprimer les clips. - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - - - - - Image sequence detected - Séquence d'image détectée - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Le fichier '%1' semble faire partie d'une séquence d'image. Voulez-vous l'importer comme tel ? - - - - ProxyDialog - - - Create Proxy - Créer un proxy - - - - Proxy - Proxy - - - - Dimensions: - Dimensions : - - - - Same Size as Source - Même taille que la source - - - - Half Resolution (1/2) - Moitié de la résolution (1/2) - - - - Quarter Resolution (1/4) - Quart de la résolution (1/4) - - - - Eighth Resolution (1/8) - Huitième de la résolution (1/8) - - - - Sixteenth Resolution (1/16) - Seizième de la résolution (1/16) - - - - Format: - Format : - - - - ProRes HQ - ProRes HQ - - - - Location: - Chemin : - - - - Same as Source (in "%1" folder) - Comme la source (dans le dossier "%1") - - - - Proxy file exists - Un fichier de proxy existe - - - - The file "%1" already exists. Do you wish to replace it? - Le fichier "%1" existe déjà. Voulez-vous le remplacer ? - - - - Custom Location - Chemin personnalisé - - - - ProxyGenerator - - - Finished generating proxy for "%1" - Génération du proxy pour "%1" terminée - - - - ReplaceClipMediaDialog - - - Replace clips using "%1" - Remplacer les clips par "%1" - - - - Select which media you want to replace this media's clips with: - Sélectionnez quel média vous souhaitez utiliser pour remplacer les clips de ce média : - - - - Keep the same media in-points - Garder les mêmes points d'entrée du média - - - - Replace - Remplacer - - - - Cancel - Annuler - - - - No media selected - Aucun média sélectionné - - - - Please select a media to replace with or click 'Cancel'. - Veuillez sélectionner un média avec lequel remplacer ou choisir 'Annuler'. - - - - Same media selected - Même média sélectionné - - - - You selected the same media that you're replacing. Please select a different one or click 'Cancel'. - Vous avez sélectionné le même média que celui que vous souhaitez remplacer. Veuillez sélectionner un autre média ou cliquer sur 'Annuler'. - - - - Folder selected - Dossier sélectionné - - - - You cannot replace footage with a folder. - Vous ne pouvez pas remplacer un média par un dossier. - - - - Active sequence selected - Séquence active sélectionnée - - - - You cannot insert a sequence into itself. - Vous ne pouvez pas insérer une séquence dans elle-même. - - - - RichTextEffect - - - Text - Texte - - - - Padding - - - - - Position - Position - - - - Vertical Align: - - - - - Top - En haut - - - - Center - Centrer - - - - Bottom - En bas - - - - Auto-Scroll - - - - - Off - Désactivée - - - - Up - - - - - Down - - - - - Left - À gauche - - - - Right - À droite - - - - Shadow - Ombre - - - - Shadow Color - Couleur de l'ombre - - - - Shadow Angle - - - - - Shadow Distance - Distance de l'ombre - - - - Shadow Softness - Douceur de l'ombre - - - - Shadow Opacity - Opacité de l'ombre - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - %1 (copy) - - - - ShakeEffect - - - Intensity - Intensité - - - - Rotation - Rotation - - - - Frequency - Fréquence - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Type - - - - Solid Color - Couleur unie - - - - SMPTE Bars - Barres SMPTE - - - - Checkerboard - Damier - - - - Opacity - Opacité - - - - Color - Couleur - - - - Checkerboard Size - Taille du damier - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - Importer… - - - - New - Nouveau - - - - View - Affichage - - - - Tree View - Vue arborescente - - - - Icon View - Vue par icônes - - - - Show Toolbar - Afficher la barre d'outils - - - - Show Sequences - Afficher les séquences - - - - Replace/Relink Media - Remplacer/Relier le média - - - - Reveal in Explorer - Montrer dans l'explorateur - - - - Reveal in Finder - Montrer dans le Finder - - - - Reveal in File Manager - Montrer dans le gestionnaire de fichiers - - - - Replace Clips Using This Media - Remplacer les clips utilisant ce média - - - - Create Sequence With This Media - Créer une séquence à partir de ce média - - - - Duplicate - Dupliquer - - - - Delete All Clips Using This Media - Supprimer tous les clips utilisant ce média - - - - Proxy - Proxy - - - - Generating proxy: %1% complete - Génération du proxy: %1% achevée - - - - Create/Modify Proxy - Créer/Modifier le proxy - - - - Create Proxy - Créer le proxy - - - - Modify Proxy - Modifier le proxy - - - - Restore Original - Restaurer l'original - - - - Delete - Supprimer - - - - Preview in Media Viewer - - - - - Properties... - Propriétés… - - - - Replace '%1' - Remplacer '%1' - - - - All Files - Tous les fichiers - - - - Replace Media - Remplacer le média - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - Vous avez déposé un fichier sur '%1'. Souhaitez-vous le remplacer par le fichier déposé ? - - - - Delete proxy - Supprimer le proxy - - - - Would you like to delete the proxy file "%1" as well? - Souhaitez-vous aussi supprimer le fichier de proxy "%1" ? - - - - SpeedDialog - - - Speed/Duration - Vitesse/Durée - - - - Speed: - Vitesse : - - - - Frame Rate: - Images par seconde : - - - - Duration: - Durée : - - - - Reverse - Inverser - - - - Maintain Audio Pitch - Maintenir la hauteur audio - - - - Ripple Changes - Propager les changements - - - - TextEditDialog - - - Edit Text - Éditer le texte - - - - Thin - - - - - Extra Light - - - - - Light - - - - - Normal - Normal - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - Éditer le texte - - - - &Edit Text - &Modifier le texte - - - - TextEffect - - - - Text - Texte - - - - Font - Police - - - - Size - Taille - - - - Color - Couleur - - - Alignment - Allignement - - - - Horizontal Alignment - - - - - Left - À gauche - - - - - Center - Centrer - - - - Right - À droite - - - - Justify - Justifié - - - - Vertical Alignment - - - - - Top - En haut - - - - Bottom - En bas - - - - Word Wrap - Retour automatique - - - - Padding - - - - - Position - Position - - - - Outline - Contour - - - - Outline Color - Couleur du contour - - - - Outline Width - Épaisseur du contour - - - - Shadow - Ombre - - - - Shadow Color - Couleur de l'ombre - - - - Shadow Angle - - - - - Shadow Distance - Distance de l'ombre - - - - Shadow Softness - Douceur de l'ombre - - - - Shadow Opacity - Opacité de l'ombre - - - - Sample Text - Texte d'exemple - - - - Render - - - - - Generate simple text over this clip - - - - &Edit Text - &Modifier le texte - - - - TimecodeEffect - - - - Timecode - Code temporel - - - - Sequence - Séquence - - - - Media - Média - - - - Scale - Échelle - - - - Color - Couleur - - - - Background Color - Couleur d'arrière-plan - - - - Background Opacity - Opacité de l'arrière-plan - - - - Offset - Écart - - - - Prepend - Préfixe - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - Timeline: - Ligne du temps : - - - <none> - <aucun> - - - - Nested Sequence - Séquence imbriquée - - - Effect already exists - L'effet existe déjà - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - Le clip '%1' contient déjà un effet '%2'. SOuhaitez-vous le remplacer par l'effet du presse-papier ou ajouter celui comme un effet distinct ? - - - Add - Ajouter - - - Replace - Remplacer - - - Skip - Passer - - - Do this for all conflicts found - Faire ceci pour tous les conflits - - - - Title... - Titre… - - - - Solid Color... - Couleur unie… - - - - Bars... - Barres… - - - - Tone... - Ton… - - - - Noise... - Bruit… - - - - Unsaved Project - Projet non-sauvegardé - - - - You must save this project before you can record audio in it. - Vous devez sauvegarder ce projet avant d'effectuer un enregistrement audio à l'intérieur. - - - - Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) - Cliquez sur la ligne du temps là où vous souhaitez commencer l'enregistrement (tirez pour limiter l'enregistrement jusqu'à une certaine image) - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (aucun) - - - - Pointer Tool - Curseur - - - - Edit Tool - Éditer - - - - Ripple Tool - Propagation - - - - Razor Tool - Cutter - - - - Slip Tool - Déplacer dessous - - - - Slide Tool - Déplacer dessus - - - - Hand Tool - Main - - - - Transition Tool - Transition - - - - Snapping - Magnétisme - - - - Zoom In - Zoomer - - - - Zoom Out - Dézoomer - - - - Record audio - Enregistrement audio - - - - Add title, solid, bars, etc. - Ajouter un titre, une couleur unie, des barres, etc. - - - - TimelineHeader - - - Center Timecodes - Centrer les codes temporels - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - - - - - &Redo - &Rétablir - - - - R&ipple Delete Empty Space - - - - - Sequence Settings - Paramètres de la séquence - - - - &Speed/Duration - &Vitesse/Durée - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - &Reveal in Project - &Révéler dans le projet - - - - Properties - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Début : %2 -Fin : %3 -Durée : %4 - - - - Error - Erreur - - - - Couldn't locate media wrapper for sequence. - Impossible de localiser le conteneurdu média de cette séquence. - - - - Title - Titre - - - - Solid Color - Couleur unie - - - - Bars - Barres - - - - Tone - Ton - - - - Noise - Bruit - - - - Duration: - Durée : - - - - TimelineWidget - - - &Undo - Ann&uler - - - - &Redo - &Rétablir - - - C&ut - &Couper - - - Cop&y - Cop&ier - - - &Paste - C&oller - - - R&ipple Delete - Supprimer et r&accorder - - - - Sequence Settings - Paramètres de la séquence - - - - &Speed/Duration - &Vitesse/Durée - - - Auto-s&cale - Échelle automati&que - - - Enable/Disable - Activer/Désactiver - - - Link/Unlink - Lier/Délier - - - &Nest - Im&briquer - - - - &Reveal in Project - &Révéler dans le projet - - - R&ename - R&enommer - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Début : %2 -Fin : %3 -Durée : %4 - - - Rename '%1' - Renommer '%1' - - - Rename multiple clips - Renommer plusieurs clips - - - Enter a new name for this clip: - Entrez un nouveau nom pour ce clip : - - - - R&ipple Delete Empty Space - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - Properties - - - - - Error - Erreur - - - - Couldn't locate media wrapper for sequence. - Impossible de localiser le conteneurdu média de cette séquence. - - - - Title - Titre - - - - Solid Color - Couleur unie - - - - Bars - Barres - - - - Tone - Ton - - - - Noise - Bruit - - - - Duration: - Durée : - - - - ToneEffect - - - Type - Type - - - - Sine - - - - - Frequency - Fréquence - - - - Amount - Quantité - - - - Mix - Mélange - - - - Tone - Ton - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - Position - - - - Scale - Échelle - - - - Uniform Scale - Échelle uniforme - - - - Rotation - Rotation - - - - Anchor Point - Point d'ancrage - - - - Opacity - Opacité - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - Blend Mode - Mode de fusion - - - Normal - Normal - - - Darken - Assombrir - - - Multiply - Multiplier - - - Color Burn - Not literal but same translation as Adobe - Densité couleur + - - - Linear Burn - Not literal but same translation as Adobe - Densité linéaire + - - - Lighten - Éclaircir - - - Screen - Not literal but same translation as Adobe - Superposition - - - Color Dodge - Not literal but same translation as Adobe - Densité couleur - - - - Linear Dodge (Add) - Not literal but same translation as Adobe - Densité linéaire - - - - Overlay - Incrustation - - - Soft Light - Not literal but same translation as Adobe - Lumière tamisée - - - Hard Light - Lumière crue - - - Vivid Light - Lumière vive - - - Linear Light - Lumière linéaire - - - Pin Light - Not literal but same translation as Adobe - Lumière ponctuelle - - - Hard Mix - Mélange maximal - - - Difference - Différence - - - Exclusion - Exclusion - - - Reflect - Réflexion - - - Substract - Soustraction - - - Average - Moyenne - - - Glow - Lueur - - - Negation - Négation - - - Phoenix - Phénix - - - - Transition - - - Length - Longueur - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - - - - - VSTHost - - - - Error loading VST plugin - Erreur lors du chargement du plugin VST - - - Failed to create VST reference - Impossible de créer la référence VST - - - - Failed to load VST plugin "%1": %2 - Impossible de charger le plugin 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. - NOTE : Vous ne pouvez pas charger de plugin VST 32-bit avec la version 64-bit d'Olive. Essayez de trouver une version 64-bit de ce plugin ou basculez sur la version 32-bit d'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. - NOTE : Vous ne pouvez pas charger de plugin VST 64-bit avec la version 32-bit d'Olive. Essayez de trouver une version 32-bit de ce plugin ou basculez sur la version 64-bit d'Olive. - - - - Failed to locate entry point for dynamic library. - Impossible de localiser le point d'entrée de la bibliothèque dynamique. - - - - VST Error - Erreur VST - - - - Plugin's magic number is invalid - Le nombre magique du plugin est invalide - - - - Plugin - Plugin - - - - Interface - Interface - - - - Show - Montrer - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - Plugin VST - - - - Viewer - - Sequence Viewer - Lecteur de séquence - - - Media Viewer - Lecteur de média - - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (aucun) - - - - Drag video only - - - - - Drag audio only - - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - Enregistrer l'image… - - - - Show Fullscreen - Montrer en plein écran - - - - Disable - Désactiver - - - - Screen %1: %2x%3 - Écran %1: %2x%3 - - - - Zoom - Zoom - - - - Fit - Ajuster - - - - Custom - Personnalisé - - - - Close Media - Fermer le média - - - - Save Frame - Enregistrer l'image - - - - Viewer Zoom - Zoom du lecteur - - - - Set Custom Zoom Value: - Définir une valeur de zoom personnalisée : - - - - ViewerWindow - - - Exit Fullscreen - Quitter le mode plein-écran - - - - VoidEffect - - - (unknown) - (inconnu) - - - - Missing Effect - Effet manquant - - - - VolumeEffect - - - - Volume - Volume - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - - transition - - Invalid transition - Transition invalide - - - No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. - Aucun candidat pour la transition '%1'. Cette transition est peut-être corrompue. Essayez de la réinstaller, ou de réinstaller Olive. - - - diff --git a/ts/olive_id.ts b/ts/olive_id.ts deleted file mode 100644 index 1a462f959..000000000 --- a/ts/olive_id.ts +++ /dev/null @@ -1,4532 +0,0 @@ - - - - - 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 - - - - - Noise - Noise - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - Potong Senyap - - - - Attack Threshold: - Ambang Mula: - - - - Attack Time: - Waktu Mula: - - - - Release Threshold: - Ambang Akhir: - - - - Release Time: - Waktu Akhir: - - - - 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 - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - 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 atau 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: - - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - 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) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Tipe - - - - Fill Left with Right - Penuhi Suara Kiri dengan Kanan - - - - Fill Right with Left - Penuhi Suara Kanan dengan Kiri - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - 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 - Kurva 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) - - - - Upper Field First - - - - - Lower Field First - - - - 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: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - 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 mungkin 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 dibuka? - - - - %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 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - - Welcome to %1 - Selamat datang di %1 - - - - &File - - - - - &New - &Buat - - - - &Open Project - Buka &Proyek - - - - Clear Recent List - Hapus Daftar "Terakhir Dibuka" - - - - Open Recent - Terakhir Dibuka - - - - &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 Seleksi - - - - 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 - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - "flatten" or "center at bottom" - Visualisasi Audio Rata Bawah - - - - Frames - Frame - - - - Drop Frame - - - - - Non-Drop Frame - - - - - Milliseconds - Milisekon - - - - Title/Action Safe Area - Area Aman Judul/Aksi - - - - 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 - - - - Node Editor - - - - - 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 - - - - Auto-Cut Silence - Potong Audio Senyap - - - 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 sebagai 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: - Daftar trek: - - - - Video %1: %2x%3 %4FPS - - - - - Audio %1: %2Hz %3 - - - - - %n channel(s) - - %n kanal - - - - - Conform to Frame Rate: - Ubah laju frame menjadi: - - - - Alpha is Premultiplied - Idk how to translate this either - Alpha dipremultiplikasi - - - - Auto (%1) - - - - - Interlacing: - Mode interlace: - - - - Color Space: - - - - - Name: - Nama: - - - - MenuHelper - - - &Project - &Proyek Baru - - - - &Sequence - &Rangkaian Baru - - - - &Folder - &Folder Baru - - - - 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 area aman 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: - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - 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? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - 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. - Gagal membaca file "%1". - - - - This settings file doesn't match this effect. - File pengaturan ini tidak cocok dengan efek yang dipilih. - - - - 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? - - - - 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 - - - - 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? - - - - Import media... - Impor media... - - - - All Files - Semua file - - - - No active sequence - Tidak ada rangkaian aktif - - - - Please open the sequence to perform this action. - Buka dahulu rangkaian untuk melakukan aksi ini. - - - - No clips selected - Tidak ada klip yang diseleksi - - - - Select the clips you wish to auto-cut - Silahkan seleksi terlebih dahulu klip-klip yang Anda ingin potong secara otomatis - - - 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 - - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - - Preferences - Preferensi - - - - Default Sequence - Rangkaian Default - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid CSS File - File CSS Salah - - - - CSS file '%1' does not exist. - Tidak ditemukan file CSS '%1'. - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Confirm Reset All Shortcuts - Konfirmasi - - - - Are you sure you wish to reset all keyboard shortcuts to their defaults? - Anda akan mengembalikan semua pintasan keyboard seperti semula. Lanjut? - - - - 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 - Buka file CSS - - - - Browse for OpenColorIO configuration - - - - - 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: - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - Pindahkan kursor secara otomatis ke awal ketika mencapai akhir rangkaian - - - - Selecting Also Seeks - 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 Garis Waktu - - - - Auto-Scale By Default - Atur ukuran video secara default - - - - Auto-Seek to Imported Clips - Geser hingga awal klip yang diimpor - - - - Audio Scrubbing - Nyalakan Audio Scrubbing - - - - Drop Files on Media to Replace - Lepas file pada media untuk menggantikan - - - - Enable Hover Focus - Nyalakan fokus melayang - - - - Ask For Name When Setting Marker - Tanyakan nama ketika menaruh penanda - - - - Custom CSS: - CSS Kustom: - - - - - Browse - Telusur - - - - Image sequence formats: - Format rangkaian gambar: - - - - Audio Recording: - Rekaman audio: - - - - Mono - - - - - Stereo - Stereo - - - - Effect Textbox Lines: - Baris Teks Efek: - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - 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: - Antrian frame ke depan: - - - - - frames - frame - - - - - seconds - detik - - - - Previous Frame Queue: - Antrian frame ke belakang: - - - - Playback - Pemutaran - - - - Output Device: - Peranti output: - - - - - Default - - - - - Input Device: - Peranti masukan: - - - - Sample Rate: - Laju sampel: - - - - Audio - - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - Search for action or shortcut - Cari aksi atau pintasan - - - - Action - Aksi - - - - Shortcut - Pintasan - - - - Import - Impor - - - - Export - Ekspor - - - - Reset Selected - Kembalikan Terseleksi - - - - 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 - - - New - "make" instead of "new", for readability - Buat - - - - Open Project - Buka Proyek - - - - Save Project - Simpan Proyek - - - - Undo - Urung - - - - Redo - Ulangi - - - - Tree View - Tampilan Pohon - - - - Icon View - Tampilan Ikon - - - - List View - Tampilan Daftar - - - - 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 kemunculan 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 tergabung 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. Impor sebagai 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. - - - - ProjectModel - - - Sequence %1 - - - - - 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 tergabung 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. Impor sebagai rangkaian gambar? - - - - 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 yang menggunakan "%1" - - - - Select which media you want to replace this media's clips with: - Pilih media pengganti: - - - - Keep the same media in-points - Samakan titik masuk media - - - - Replace - Ganti - - - - Cancel - Batalkan - - - - No media selected - Tidak ada media yang diseleksi - - - - Please select a media to replace with or click 'Cancel'. - Pilih media pengganti atau klik "Batalkan". - - - - Same media selected - Terseleksi media yang sama - - - - You selected the same media that you're replacing. Please select a different one or click 'Cancel'. - Anda menyeleksi media yang sama dengan yang akan diganti. Silahkan pilih yang lain atau klik "Batalkan". - - - - Folder selected - Folder terseleksi - - - - 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 - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - %1 (salinan) - - - - ShakeEffect - - - Intensity - Intensitas - - - - Rotation - Rotasi - - - - Frequency - Frekuensi - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Tipe - - - - Solid Color - Warna - - - - SMPTE Bars - - - - - Checkerboard - Kotak-Kotak - - - - Opacity - - - - - Color - Warna - - - - Checkerboard Size - Ukuran Kotak-Kotak - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - Impor... - - - - New - thought it'd made more sense to have the user read it as "buat -> rangkaian baru" ("create new sequence"), instead of "baru -> rangkaian" - Buat - - - - 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 Semua Klip yang Menggunakan 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 '%1' - Ganti '%1' - - - - All Files - Semua file - - - - 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 - - - - Horizontal Alignment - - - - - Left - Kiri - - - - - Center - Tengah - - - - Right - Kanan - - - - Justify - Kanan-Kiri - - - - Vertical Alignment - - - - - 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 - - - - Render - - - - - Generate simple text over this clip - - - - - TimecodeEffect - - - - Timecode - Kode Waktu - - - - Sequence - Rangkaian - - - - Media - - - - - Scale - Ukuran - - - - Color - Warna - - - - Background Color - Warna Latar - - - - Background Opacity - Transparansi Latar - - - - Offset - Penggeseran - - - - Prepend - Teks Sebelum - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - 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 - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - 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 - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - &Urung - - - - &Redo - &Ulangi - - - - R&ipple Delete Empty Space - Hapus dan Sesuaikan Ruang &Kosong - - - - Sequence Settings - Pengaturan Rangkaian - - - - &Speed/Duration - &Kecepatan/Durasi - - - - Auto-Cut Silence - Potong Audio Senyap - - - - 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. - Tidak dapat mencari bungkus media untuk rangkaian. - - - - Title - Judul - - - - Solid Color - Warna - - - - Bars - - - - - Tone - Nada - - - - Noise - Noise - - - - Duration: - Durasi: - - - - 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 - - - - Auto-Cut Silence - Potong Audio Senyap - - - - 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. - Tidak dapat mencari bungkus media untuk rangkaian. - - - - Title - Judul - - - - Solid Color - Warna - - - - Bars - - - - - Tone - Nada - - - - Noise - Noise - - - - Duration: - Durasi: - - - - ToneEffect - - - Type - Tipe - - - - Sine - Sinus - - - - Frequency - Frekuensi - - - - Amount - Kenyaringan - - - - Mix - Campur - - - - Tone - Nada - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - Posisi - - - - Scale - Ukuran - - - - Uniform Scale - Ukuran Merata - - - - Rotation - Rotasi - - - - Anchor Point - Titik Poros - - - - Opacity - - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - Blend Mode - Mode Penggabungan - - - - 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 (magic number) plugin salah - - - - Plugin - - - - - Interface - Antarmuka - - - - Show - Tampilkan - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - Plugin VST - - - - Viewer - - Sequence Viewer - Tampilan Rangkaian - - - Media Viewer - Tampilan Media - - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (tidak ada) - - - - Drag video only - Tarik video saja - - - - Drag audio only - Tarik audio saja - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - 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 - - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - - 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. - - - diff --git a/ts/olive_it.ts b/ts/olive_it.ts deleted file mode 100644 index 4ed36bd50..000000000 --- a/ts/olive_it.ts +++ /dev/null @@ -1,4612 +0,0 @@ - - - - - AboutDialog - - - Olive is a non-linear video editor. This software is free and protected by the GNU GPL. - Olive è un editor video non lineare. Questo è software libero ed è protetto dalla licenza GNU GPL. - - - - Olive Team is obliged to inform users that Olive source code is available for download from its website. - Gli sviluppatori di Olive sono grati di informare che il codice sorgente del programma è scaricabile dal sito. - - - - ActionSearch - - - Search for action... - Cerca un'azione... - - - - AdvancedVideoDialog - - - Advanced Video Settings - Impostazioni video avanzate - - - - Pixel Format: - Formato pixel: - - - - Threads: - Thread: - - - - Audio - - - %1 Audio - Audio %1 - - - - Recording %1 - Registrazione di %1 - - - - AudioNoiseEffect - - - Amount - Ammontare - - - - Mix - Miscela - - - - Noise - Rumore - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - Taglia silenzio - - - - Attack Threshold: - Soglia d'attacco: - - - - Attack Time: - Tempo d'attacco: - - - - Release Threshold: - Soglia di rilascio: - - - - Release Time: - Tempo di rilascio: - - - - Cacher - - - - Could not open %1 - %2 - Impossibile aprire %1 - %2 - - - - ChannelLayoutName - - - Invalid - Non valido - - - - Mono - Mono - - - - Stereo - Stereo - - - - ClipPropertiesDialog - - - "%1" Properties - Proprietà di "%1" - - - - Multiple Clip Properties - Proprietà di clip multiple - - - - Name: - Nome: - - - - Duration: - Durata: - - - - (multiple) - (multiple) - - - - CollapsibleWidget - - - <untitled> - <senza titolo> - - - - ColorButton - - - Set Color - Imposta colore - - - - CornerPinEffect - - - Top Left - In alto a sinistra - - - - Top Right - In alto a destra - - - - Bottom Left - In basso a sinistra - - - - Bottom Right - In basso a destra - - - - Perspective - Prospettico - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - DebugDialog - - - Debug Log - Log di debug - - - - DemoNotice - - - - Welcome to Olive! - Maschile riferito all'utente - Benvenuto in 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 è un editor video libero non lineare rilasciato sotto licenza GNU GPL. Se hai pagato per questo programma, sei stato truffato. - - - - 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 - Il software è attualmente in ALFA; ciò significa che non è stabile ed è probabile che vada in crash, abbia errori o manchino alcune funzioni. Non offriamo alcuna garanzia, quindi usalo a tuo rischio. Puoi segnalare errori o richiedere funzionalità su %1 - - - - Thank you for trying Olive and we hope you enjoy it! - Grazie per aver provato Olive, speriamo che ti piaccia! - - - - Effect - - Invalid effect - Effetto non valido - - - No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive. - Nessun candidato per l'effetto "%1". Questo effetto potrebbe essere corrotto. Prova a reinstallare l'effetto o Olive. - - - Cu&t - &Taglia - - - &Copy - &Copia - - - Move &Up - Sposta in s&u - - - Move &Down - Sposta in &giù - - - D&elete - &Elimina - - - Load Settings From File - Carica le impostazioni da file - - - Save Settings to File - Salva le impostazioni su file - - - Save Effect Settings - Salva impostazioni degli effetti - - - Effect XML Settings %1 - XML impostazioni effetti %1 - - - Save Settings Failed - Salvataggio impostazioni fallito - - - Failed to open "%1" for writing. - Impossibile aprire il file "%1" in scrittura. - - - Load Effect Settings - Carica impostazioni effetto - - - Load Settings Failed - Caricamento impostazioni fallito - - - Failed to open "%1" for reading. - Impossibile aprire "%1" in lettura. - - - This settings file doesn't match this effect. - Questo file di impostazioni non corrisponde con questo effetto. - - - - EffectControls - - - Effects: - Effetti: - - - &Paste - &Incolla - - - - (none) - (nessuno) - - - - Add Video Effect - Aggiungi effetto video - - - - VIDEO EFFECTS - EFFETTI VIDEO - - - - Add Video Transition - Aggiungi transizione video - - - - Add Audio Effect - Aggiungi effetto video - - - - AUDIO EFFECTS - EFFETTI AUDIO - - - - Add Audio Transition - Aggiungi transizione audio - - - (Multiple clips selected) - (Più clip selezionate) - - - - EffectRow - - Disable Keyframes - Disabilita fotogrammi chiave - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Disabilitare i fotogrammi chiave eliminerà tutti quelli attualmente esistenti. Sei sicuro di volerlo fare? - - - - EffectUI - - - %1 (Opening) - %1 (in apertura) - - - - %1 (Closing) - %1 (in chiusura) - - - - %1 (multiple) - %1 (multiple) - - - - Cu&t - &Taglia - - - - &Copy - &Copia - - - - Move &Up - Sposta in s&u - - - - Move &Down - Sposta in &giù - - - - D&elete - &Elimina - - - - Load Settings From File - Carica le impostazioni da file - - - - Save Settings to File - Salva le impostazioni su file - - - - EmbeddedFileChooser - - - File: - File: - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - Esporta "%1" - Esporta "%1" - - - - Unknown codec name %1 - Nome del codec %1 sconosciuto - - - - Export Failed - Esportazione non riuscita - - - - Export failed - %1 - Esportazione non riuscita - %1 - - - - Invalid dimensions - Dimensioni non valide - - - - Export width and height must both be even numbers/divisible by 2. - La larghezza e l'altezza dell'esportazione devono essere pari/divisibili per due. - - - - Invalid codec - Codec non valido - - - - Couldn't determine output parameters for the selected codec. This is a bug, please contact the developers. - Impossibile determinare i parametri d'output per il codec selezionato. Questo è un errore, si prega di contattare gli sviluppatori. - - - - Invalid format - Formato non valido - - - - Couldn't determine output format. This is a bug, please contact the developers. - Impossibile determinare il formato di output. Questo è un errore, si prega di contattare gli sviluppatori. - - - - Export Media - Esporta media - - - - %p% (Total: %1:%2:%3) - %p% (totale: %1:%2:%3) - - - - %p% (ETA: %1:%2:%3) - %p% (tempo residuo %1:%2:%3) - - - - Quality-based (Constant Rate Factor) - Basata sulla qualità (CFR bitrate variabile) - - - - Constant Bitrate - Bitrate costante - - - - - Invalid Codec - Codec non valido - - - - Failed to find a suitable encoder for this codec. Export will likely fail. - Impossibile trovare un codificatore compatibile per questo codec. È facile che l'esportazione fallisca. - - - - Failed to find pixel format for this encoder. Export will likely fail. - Impossibile trovare il formato dei pixel di questo codificatore. È facile che l'esportazione fallisca. - - - - Bitrate (Mbps): - Bitrate (Mbps): - - - - Quality (CRF): - Qualità (CRF): - - - - Quality Factor: - -0 = lossless -17-18 = visually lossless (compressed, but unnoticeable) -23 = high quality -51 = lowest quality possible - Fattore di qualità: - -0 = senza perdita -17-18 = visivamente senza perdita (compresso, ma non si nota) -23 = alta qualità -51 = peggiore qualità possibile - - - - Target File Size (MB): - Grandezza file desiderata (MB): - - - - Format: - Formato: - - - - Range: - Intervallo: - - - - Entire Sequence - Sequenza completa - - - - In to Out - Zona selezionata - - - - Video - Video - - - - - Codec: - Codec: - - - - Width: - Larghezza: - - - - Height: - Altezza: - - - - Frame Rate: - Fotogrammi al secondo: - - - - Compression Type: - Tipo di compressione: - - - - Advanced - Avanzate - - - - Audio - Audio - - - - Sampling Rate: - Frequenza di campionamento: - - - - Bitrate (Kbps/CBR): - Bitrate (Kbps/CBR): - - - - ExportThread - - - failed to send frame to encoder (%1) - errore nell'invio del fotogramma al codificatore (%1) - - - - failed to receive packet from encoder (%1) - errore nella ricezione di un pacchetto dal codificatore (%1) - - - - could not video encoder for %1 - impossibile trovare un codificatore video per %1 - - - - could not allocate video stream - impossibile allocare stream video - - - - could not allocate video encoding context - impossibile allocale contesto di codifica del video - - - - could not open output video encoder (%1) - impossibile aprire il codificatore video d'output (%1) - - - - could not copy video encoder parameters to output stream (%1) - impossibile copiare i parametri del codificatore video allo stream di output (%1) - - - - could not audio encoder for %1 - impossibile trovare un codificatore audio per %1 - - - - could not allocate audio stream - impossibile allocare lo stream audio - - - - could not allocate audio encoding context - impossibile allocale contesto di codifica dell'audio - - - - could not open output audio encoder (%1) - impossibile aprire il codificatore dell'output audio (%1) - - - - could not copy audio encoder parameters to output stream (%1) - impossibile copiare i parametri del codificatore audio allo stream di output (%1) - - - - could not allocate audio buffer (%1) - impossibile allocare il buffer audio (%1) - - - - could not create output format context - impossibile creare il contesto del formato d'output - - - - could not open output file (%1) - impossibile aprire il file di output (%1) - - - - could not write output file header (%1) - impossibile scrivere l'intestazione del file di output (%1) - - - - could not write output file trailer (%1) - impossibile scrivere la fine del file d'output (%1) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Tipo - - - - Fill Left with Right - Riempi il sinistro con il destro - - - - Fill Right with Left - Riempi il destro con il sinistro - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - Impossibile caricare il 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. - NOTA: Non si possono caricare plugin Frei0r a 32 bit in una versione a 64 bit di Olive. Si prega di trovare la versione a 64 bit di questo plugin oppure di passare alla versione 32 bit di 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. - NOTA: Non si possono caricare plugin Frei0r a 64 bit in una versione a 32 bit di Olive. Si prega di trovare la versione a 32 bit di questo plugin oppure di passare alla versione 64 bit di Olive. - - - - Error loading Frei0r plugin - Errore nel caricamento plugin Frei0r - - - - GraphEditor - - - Graph Editor - Editor del grafico - - - - Linear - Lineare - - - - Bezier - Bézier - - - - Hold - Costante - - - - GraphView - - - Zoom to Selection - Ingrandisci la selezione - - - - Zoom to Show All - Ingrandisci per mostrare tutto - - - - Reset View - Reimposta ingrandimento - - - - InterlacingName - - - None (Progressive) - Nessuno (progressivo) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - Prima la linea in alto - - - Bottom Field First - Prima la linea in basso - - - - Invalid - Non valido - - - - KeyframeNavigator - - - Enable Keyframes - Abilita fotogrammi chiave - - - - KeyframeView - - - Linear - Lineare - - - - Bezier - Bézier - - - - Hold - Costante - - - - LabelSlider - - - &Edit - &Modifica - - - - &Reset to Default - &Ripristina predefinito - - - - - Set Value - Imposta valore - - - - - New value: - Nuovo valore: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - LoadDialog - - - Loading... - Caricamento... - - - - Loading '%1'... - Caricamento di "%1"... - - - - Cancel - Annulla - - - - LoadThread - - - Version Mismatch - Mancata corrispondenza della versione - - - - 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? - Questo progetto è stato salvato con una versione diversa di Olive e potrebbe non essere compatibile con questa. Vuoi provare a caricarlo ugualmente? - - - Invalid Clip Link - Link della clip non valido - - - This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it? - Questo progetto contiene un collegamento non valido a una clip. Potrebbe essere danneggiato. Vuoi continuare a caricarlo? - - - - %1 - Line: %2 Col: %3 - %1 - Linea: %2 Colonna: %3 - - - - User aborted loading - L'utente ha interrotto il caricamento - - - - XML Parsing Error - Errore nell'analisi XML - - - - Couldn't load '%1'. %2 - Impossibile caricare "%1". %2 - - - - Project Load Error - Errore nel caricamento del progetto - - - - Error loading project: %1 - Impossibile caricare il progetto: %1 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - - Welcome to %1 - Benvenuti in %1 - - - - &File - &File - - - - &New - &Nuovo - - - - &Open Project - Apri pr&ogetto - - - - Clear Recent List - Svuota lista recenti - - - - Open Recent - Apri recenti - - - - &Save Project - &Salva progetto - - - - Save Project &As - S&alva progetto con nome - - - - &Import... - &Importa... - - - - &Export... - &Esporta... - - - - E&xit - Es&ci - - - - &Edit - &Modifica - - - - &Undo - &Annulla - - - - Redo - Rifai - - - - Select &All - Seleziona t&utto - - - - Deselect All - Deseleziona tutto - - - - Ripple to In Point - Taglia a catena fino al punto iniziale - - - - Ripple to Out Point - Intende il punto fine selezione o il cursore? - Taglia a catena dal punto finale - - - - Edit to In Point - Taglia fino al punto iniziale - - - - Edit to Out Point - Taglia dal punto finale - - - - Delete In/Out Point - Elimina tra l'inizio e fine selezione - - - - Ripple Delete In/Out Point - Elimina a catena tra l'inizio e fine selezione - - - - Set/Edit Marker - Imposta/modifica marcatore - - - - &View - &Visualizza - - - - Zoom In - Ingrandisci - - - - Zoom Out - Rimpicciolisci - - - - Increase Track Height - Aumenta l'altezza delle tracce - - - - Decrease Track Height - Diminuisci altezza delle tracce - - - - Toggle Show All - Commuta mostra tutti - - - Track Lines - Linee tra le tracce - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - Forme d'onda rettificate - - - - Frames - Fotogrammi - - - - Drop Frame - Salta fotogrammi - - - - Non-Drop Frame - Non saltare fotogrammi - - - - Milliseconds - Millisecondi - - - - Title/Action Safe Area - Area di sicurezza del titolo/azione - - - - Off - Disattivato - - - - Default - Predefinito - - - - 4:3 - 4:3 - - - - 16:9 - 16:9 - - - - Custom - Personalizzato - - - - Full Screen - Schermo intero - - - - Full Screen Viewer - Visualizzatore a schermo intero - - - - &Playback - &Riproduzione - - - - Go to Start - Vai all'inizio - - - - Previous Frame - Fotogramma precedente - - - - Play/Pause - Riproduci/pausa - - - - Play In to Out - Riproduci tra inizio e fine selezione - - - - Next Frame - Fotogramma successivo - - - - Go to End - Vai alla fine - - - - Go to Previous Cut - Vai al taglio precedente - - - - Go to Next Cut - Vai al taglio successivo - - - - Go to In Point - Vai al punto di inizio selezione - - - - Go to Out Point - Vai al punto di fine selezione - - - - Shuttle Left - Scorri riproducendo verso sinistra - - - - Shuttle Stop - Ferma scorrimento riproduzione - - - - Shuttle Right - Scorri riproducendo verso destra - - - - Loop - Ciclico - - - - &Window - &Finestra - - - - Project - Progetto - - - - Effect Controls - Controllo effetti - - - - Timeline - Linea temporale - - - - Graph Editor - Editor del grafico - - - - Node Editor - - - - - Media Viewer - Visualizzatore media - - - - Sequence Viewer - Visualizzatore sequenza - - - - Maximize Panel - Massimizza pannello - - - - Lock Panels - Blocca pannelli - - - - Reset to Default Layout - Torna alla disposizione predefinita - - - - &Tools - S&trumenti - - - - Pointer Tool - Strumento puntatore - - - - Edit Tool - Strumento di modifica - - - - Ripple Tool - Strumento ridimensiona a catena - - - - Razor Tool - Strumento di taglio - - - - Slip Tool - Strumento di scivolamento - - - - Slide Tool - Strumento di scorrimento - - - - Hand Tool - Strumento mano - - - - Transition Tool - Strumento transizione - - - - Enable Snapping - Attiva bordi magnetici - - - - Auto-Cut Silence - Taglio automatico del silenzio - - - Selecting Also Seeks - Selezionando si sposta anche il cursore - - - Edit Tool Also Seeks - Lo strumento di modifica sposta anche il cursore - - - Edit Tool Selects Links - Lo strumento di modifica seleziona anche i collegamenti - - - Seek Also Selects - Spostare il cursore seleziona anche - - - Seek to the End of Pastes - Sposta cursore alla fine di ciò che viene incollato - - - Scroll Wheel Zooms - Ingrandisci con la rotellina del mouse - - - Enable Drag Files to Timeline - Permetti il trascinamento dei file alla linea temporale - - - Auto-Scale By Default - Scala automaticamente in maniera predefinita - - - Enable Seek to Import - Sposta cursore all'importazione - - - Audio Scrubbing - Da rivedere in base alla traduzione della linea verticale di riproduzione - Audio attivo durante il trascinamento - - - Enable Drop on Media to Replace - Permetti di rilasciare su un media per rimpiazzarlo - - - Enable Hover Focus - Abilita focus al passaggio - - - Ask For Name When Setting Marker - Chiedi un nome nell'impostazione del marcatore - - - - No Auto-Scroll - Disattiva scorrimento automatico - - - - Page Auto-Scroll - Scorrimento pagina automatico - - - - Smooth Auto-Scroll - Scorrimento automatico fluido - - - - Preferences - Impostazioni - - - - Clear Undo - Dimentica cronologia azioni - - - - &Help - &Aiuto - - - - A&ction Search - Ri&cerca azione - - - - Debug Log - Log di debug - - - - &About... - Inform&azioni... - - - - <untitled> - <senza titolo> - - - - Marker - - - - Set Marker - Imposta marcatore - - - - Set clip marker name: - Imposta nome del marcatore della clip: - - - - Set sequence marker name: - Imposta nome del marcatore della sequenza: - - - - Media - - - New Folder - Nuova cartella - - - - Name: - Nome: - - - - Filename: - Nome file: - - - - Video Dimensions: - Dimensioni video: - - - - Frame Rate: - Velocità fotogrammi: - - - - %1 field(s) (%2 frame(s)) - %1 campo(i) (%2 fotogramma(i)) - - - - Interlacing: - Interlacciamento: - - - - Audio Frequency: - Frequenza audio: - - - - Audio Channels: - Canali audio: - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - Nome: %1 -Dimensioni video: %2x%3 -Velocità fotogrammi: %4 -Frequenza audio: %5 -Disposizione audio: %6 - - - - Name - Nome - - - - Duration - Durata - - - - Rate - Frequenza - - - - MediaPropertiesDialog - - - "%1" Properties - Proprietà di "%1" - - - - Tracks: - Tracce: - - - - Video %1: %2x%3 %4FPS - Video %1: %2x%3 %4FPS - - - - Audio %1: %2Hz %3 - Audio %1: %2Hz %3 - - - - %n channel(s) - - %n canale - %n canali - - - - - Conform to Frame Rate: - Conforme alla velocità dei fotogrammi: - - - - Alpha is Premultiplied - Canale alfa premoltiplicato - - - - Auto (%1) - Automatico (%1) - - - - Interlacing: - Interlacciamento: - - - - Color Space: - - - - - Name: - Nome: - - - - MenuHelper - - - &Project - &Progetto - - - - &Sequence - &Sequenza - - - - &Folder - C&artella - - - - Set In Point - Imposta punto di inizio selezione - - - - Set Out Point - Imposta punto di fine selezione - - - - Reset In Point - Azzera punto inizio selezione - - - - Reset Out Point - Azzera punto fine selezione - - - - Clear In/Out Point - Pulisci punti di inizio/fine selezione - - - - Add Default Transition - Aggiungi transizione predefinita - - - - Link/Unlink - Collega/scollega - - - - Enable/Disable - Attiva/disattiva - - - - Nest - Annida - - - - Cu&t - &Taglia - - - - Cop&y - &Copia - - - - - &Paste - &Incolla - - - - Paste Insert - Incolla e inserisci - - - - Duplicate - Duplica - - - - Delete - Elimina - - - - Ripple Delete - Elimina a catena - - - - Split - Dividi - - - - Invalid aspect ratio - Rapporto d'aspetto non valido - - - - The aspect ratio '%1' is invalid. Please try again. - Il rapporto d'aspetto "%1" non è valido. Riprovare. - - - - Enter custom aspect ratio - Inserisci rapporto d'aspetto personalizzato - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - Inserisci il rapporto d'aspetto da usare per l'area di sicurezza (es. 16:9): - - - - NewSequenceDialog - - - Editing "%1" - Modifica di "%1" - - - - New Sequence - Nuova sequenza - - - - Preset: - Preimpostazioni: - - - - Film 4K - Film 4K - - - - 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 - Personalizzato - - - - Video - Video - - - - Width: - Larghezza: - - - - Height: - Altezza: - - - - Frame Rate: - Velocità fotogrammi: - - - - Pixel Aspect Ratio: - Proporzioni dei pixel: - - - - Square Pixels (1.0) - Pixel quadrati (1.0) - - - - Interlacing: - Interlacciamento: - - - - None (Progressive) - Nessuno (progressivo) - - - - Audio - Audio - - - - Sample Rate: - Frequenza di campionamento: - - - - Name: - Nome: - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - Disabilita fotogrammi chiave - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Disabilitare i fotogrammi chiave eliminerà tutti quelli attualmente esistenti. Sei sicuro di volerlo fare? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - Media - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - Salva impostazioni degli effetti - - - - - Effect XML Settings %1 - XML impostazioni effetti %1 - - - - Save Settings Failed - Salvataggio impostazioni fallito - - - - Failed to open "%1" for writing. - Impossibile aprire il file "%1" in scrittura. - - - - Load Effect Settings - Carica impostazioni effetto - - - - - Load Settings Failed - Caricamento impostazioni fallito - - - - Failed to open "%1" for reading. - Impossibile aprire "%1" in lettura. - - - - This settings file doesn't match this effect. - Questo file di impostazioni non corrisponde con questo effetto. - - - - OliveGlobal - - - Olive Project %1 - Progetto di Olive %1 - - - - Auto-recovery - Ripristino automatico - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - Olive non è stato chiuso correttamente ed è stato trovato un file di ripristino. Desideri aprirlo? - - - - Effect already exists - L'effetto esiste già - - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - La clip "%1" contiene già un effetto "%2". Vuoi rimpiazzarlo con quello incollato oppure aggiungerlo come effetto separato? - - - - Add - Aggiungi - - - - Replace - Rimpiazza - - - - Skip - Salta - - - - Do this for all conflicts found - Ripeti per ogni conflitto trovato - - - - Open Project... - Apri progetto... - - - - Missing recent project - Progetto recente mancante - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - Il progetto "%1" non esiste più. Vuoi rimuoverlo dalla lista dei progetti recenti? - - - - Save Project As... - Salva progetto con nome... - - - - Unsaved Project - Progetto non salvato - - - - This project has changed since it was last saved. Would you like to save it before closing? - Il progetto è stato modificato rispetto all'ultimo salvataggio. Vuoi salvarlo prima di chiuderlo? - - - - Import media... - Importa media... - - - - All Files - Tutti i file - - - - No active sequence - Nessuna sequenza attiva - - - - Please open the sequence to perform this action. - Si prega di aprire una sequenza per poter eseguire questa azione. - - - - No clips selected - Nessuna clip selezionata - - - - Select the clips you wish to auto-cut - Seleziona le clip che vuoi tagliare automaticamente - - - Please open the sequence you wish to export. - Si prega di aprire la sequenza che si desidera esportare. - - - - Missing Project File - File del progetto mancante - - - - Specified project '%1' does not exist. - Il progetto specificato "%1" non esiste. - - - - PanEffect - - - - Pan - Trasla - - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - - Preferences - Impostazioni - - - - Default Sequence - Sequenza predefinita - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid CSS File - File CSS non valido - - - - CSS file '%1' does not exist. - Il file CSS "%1" non esiste. - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Confirm Reset All Shortcuts - Conferma l'azzeramento di tutte le scorciatoie da tastiera - - - - Are you sure you wish to reset all keyboard shortcuts to their defaults? - Sei sicuro di voler riportare tutte le scorciatoie da tastiera ai valori iniziali? - - - - Import Keyboard Shortcuts - Importa scorciatoie da tastiera - - - - - Error saving shortcuts - Errore nel salvataggio delle scorciatoie - - - - Failed to open file for reading - Errore nell'apertura del file in lettura - - - - Export Keyboard Shortcuts - Esporta scorciatoie da tastiera - - - - Export Shortcuts - Esporta scorciatoie - - - - Shortcuts exported successfully - Scorciatoie esportate con successo - - - - Failed to open file for writing - Errore nell'apertura del file in scrittura - - - - Browse for CSS file - Sfoglia file CSS - - - - Browse for OpenColorIO configuration - - - - - Delete All Previews - Elimina tutte le anteprime - - - - Are you sure you want to delete all previews? - Sei sicuro di voler eliminare tutte le anteprime? - - - - Previews Deleted - Anteprime eliminate - - - All previews deleted succesfully. You may have to re-open your current project for changes to take effect. - Tutte le anteprime sono state eliminate con successo. Potresti dover riaprire il progetto attuale affinché i cambiamenti abbiano effetto. - - - - Language: - Lingua: - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - Default Sequence Settings - Impostazioni predefinite della sequenza - - - - Add Default Effects to New Clips - Aggiungi gli effetti predefiniti alle nuove clip - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - Riporta il cursore all'inizio quando si riproduce alla fine di una sequenza - - - - Selecting Also Seeks - Selezionando si sposta anche il cursore - - - - Edit Tool Also Seeks - Lo strumento di modifica sposta anche il cursore - - - - Edit Tool Selects Links - collegamenti o collegàti? - Lo strumento di modifica seleziona anche i collegamenti - - - - Seek Also Selects - Spostare il cursore seleziona anche - - - - Seek to the End of Pastes - Sposta cursore alla fine di ciò che viene incollato - - - - Scroll Wheel Zooms - Ingrandisci con la rotellina del mouse - - - - Hold CTRL to toggle this setting - Tieni premuto CTRL per commutare questa impostazione - - - - Invert Timeline Scroll Axes - Inverti assi di scorrimento della linea temporale - - - - Enable Drag Files to Timeline - Permetti il trascinamento dei file alla linea temporale - - - - Auto-Scale By Default - Scala automaticamente in maniera predefinita - - - - Auto-Seek to Imported Clips - Sposta il cursore alle clip importate - - - - Audio Scrubbing - Audio attivo durante il trascinamento cursore - - - - Drop Files on Media to Replace - Rilascia i file sui media per rimpiazzarli - - - - Enable Hover Focus - Abilita focus al passaggio - - - - Ask For Name When Setting Marker - Chiedi un nome nell'impostazione del marcatore - - - - Appearance - Aspetto - - - - Theme - Tema - - - - Olive Dark (Default) - Olive scuro (predefinito) - - - - Olive Light - Olive chiaro - - - - Native - Nativo - - - - Native (Light Icons) - Nativo (icone chiare) - - - - Use Native Menu Styling - Usa lo stile nativo per i menu - - - - Custom CSS: - CSS personalizzato: - - - - - Browse - Sfoglia - - - - Image sequence formats: - Formati delle sequenze immagini: - - - - Audio Recording: - Registrazione audio: - - - - Mono - Mono - - - - Stereo - Stereo - - - - Effect Textbox Lines: - N° linee nelle caselle di testo degli effetti: - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - Risoluzione anteprime: - - - - Waveform Resolution: - Risoluzione forma d'onda: - - - - Delete Previews - Elimina anteprime - - - - Use Software Fallbacks When Possible - tradurre o no software fallback? è linguaggio parecchio tecnico - Usa i software fallback quando possibile - - - - General - Generale - - - - Behavior - Comportamento - - - Seeking - Spostamento cursore - - - Accurate Seeking -Always show the correct frame (visual may pause briefly as correct frame is retrieved) - Spostamento cursore accurato -Mostra sempre il fotogramma corretto (il video potrebbe bloccarsi brevemente per caricare il fotogramma) - - - Fast Seeking -Seek quickly (may briefly show inaccurate frames when seeking - doesn't affect playback/export) - Spostamento veloce del cursore -Sposta velocemente il cursore (potrebbe mostrare fotogrammi non perfettamente accurati durante lo spostamento - non interessa la riproduzione/esportazione) - - - - Memory Usage - Uso della memoria - - - - Upcoming Frame Queue: - Fotogrammi seguenti in coda: - - - - - frames - fotogrammi - - - - - seconds - secondi - - - - Previous Frame Queue: - Fotogrammi precedenti in coda: - - - - Playback - Riproduzione - - - - Output Device: - Dispositivo d'uscita: - - - - - Default - Predefinito - - - - Input Device: - Dispositivo d'ingresso: - - - - Sample Rate: - Frequenza di campionamento: - - - - Audio - Audio - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - Search for action or shortcut - Cerca un'azione o una scorciatoia - - - - Action - Azione - - - - Shortcut - Scorciatoia - - - - Import - Importa - - - - Export - Esporta - - - - Reset Selected - Reimposta quelle selezionate - - - - Reset All - Reimposta tutto - - - - Keyboard - Tastiera - - - - PreviewGenerator - - - Failed to find any valid video/audio streams - Impossibile trovare stream audio/video validi - - - - Could not open file - %1 - Impossibile aprire il file - %1 - - - - Could not find stream information - %1 - Impossibile trovare le informazioni sullo stream - %1 - - - - Project - - - New - Nuovo - - - - Open Project - Apri progetto - - - - Save Project - Salva progetto - - - - Undo - Annulla - - - - Redo - Rifai - - - - Tree View - Vista ad albero - - - - Icon View - Vista ad icone - - - - List View - Vista a lista - - - - Search media, markers, etc. - Cerca media, marcatori, ecc. - - - - Project - Progetto - - - Sequence - Sequenza - - - Replace '%1' - Rimpiazza "%1" - - - All Files - Tutti i file - - - - - No active sequence - Nessuna sequenza attiva - - - - No sequence is active, please open the sequence you want to replace clips from. - Nessuna sequenza attiva, si prega di aprire quella da cui vuoi rimpiazzare le clip. - - - - Active sequence selected - Sequenza attiva selezionata - - - - You cannot insert a sequence into itself, so no clips of this media would be in this sequence. - Non puoi inserire una sequenza dentro sé stessa, in questa sequenza non ci sarebbero clip di questo media. - - - - Rename '%1' - Rinomina "%1" - - - - Enter new name: - Inserisci un nuovo nome: - - - - Delete media in use? - Eliminare il media in uso? - - - - 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? - Il media "%1" è attualmente usato in "%2". Eliminandolo, toglierai tutte le sue istanze dalla sequenza. Sei sicuro di volerlo fare? - - - - Skip - Salta - - - Import a Project - Importa un progetto - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - "%1" è un file di un progetto Olive. Verrà unito a questo progetto. Desideri continuare? - - - Image sequence detected - Sequenza di immagini rilevata - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Il file "%1" sembra far parte di una sequenza di immagini. Desideri importarla come tale? - - - Import media... - Importa media... - - - - No sequence is active, please open the sequence you want to delete clips from. - Nessuna sequenza attiva, si prega di aprire la sequenza da cui vuoi eliminare le clip. - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - Importa un progetto - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - "%1" è un file di un progetto Olive. Verrà unito a questo progetto. Desideri continuare? - - - - Image sequence detected - Sequenza di immagini rilevata - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - Il file "%1" sembra far parte di una sequenza di immagini. Desideri importarla come tale? - - - - ProxyDialog - - - Create Proxy - Crea clip rappresentativa - - - - Proxy - Clip rappresentativa - - - - Dimensions: - Dimensioni: - - - - Same Size as Source - Stessa dimensione del file originale - - - - Half Resolution (1/2) - Metà della risoluzione (1/2) - - - - Quarter Resolution (1/4) - Un quarto della risoluzione (1/4) - - - - Eighth Resolution (1/8) - Un ottavo della risoluzione (1/8) - - - - Sixteenth Resolution (1/16) - Un sedicesimo della risoluzione (1/16) - - - - Format: - Formato: - - - - ProRes HQ - ProRes HQ - - - - Location: - Posizione: - - - - Same as Source (in "%1" folder) - Stessa del file originale (nella cartella "%1") - - - - Proxy file exists - La clip rappresentativa esiste - - - - The file "%1" already exists. Do you wish to replace it? - Il file "%1" esiste già. Desideri sovrascriverlo? - - - - Custom Location - Posizione personalizzata - - - - ProxyGenerator - - - Finished generating proxy for "%1" - Generazione clip rappresentative di "%1" terminata - - - - ReplaceClipMediaDialog - - - Replace clips using "%1" - Rimpiazza clip usando "%1" - - - - Select which media you want to replace this media's clips with: - Seleziona quale media vuoi usare per rimpiazzare le clip di questo media: - - - - Keep the same media in-points - Mantieni lo stesso media nei punti - - - - Replace - Rimpiazza - - - - Cancel - Annulla - - - - No media selected - Nessun media selezionato - - - - Please select a media to replace with or click 'Cancel'. - Si prega di selezionare una media per la sostituzione o di cliccare "Annulla". - - - - Same media selected - Stesso media selezionato - - - - You selected the same media that you're replacing. Please select a different one or click 'Cancel'. - Hai selezionato lo stesso media che stai cercando di rimpiazzare. Si prega di selezionarne un altro o di cliccare "Annulla". - - - - Folder selected - Cartella selezionata - - - - You cannot replace footage with a folder. - Non puoi rimpiazzare un filmato con una cartella. - - - - Active sequence selected - Sequenza attiva selezionata - - - - You cannot insert a sequence into itself. - Non puoi inserire una sequenza dentro sé stessa. - - - - RichTextEffect - - - Text - Testo - - - - Padding - Spaziatura - - - - Position - Posizione - - - - Vertical Align: - Allineamento verticale: - - - - Top - In alto - - - - Center - Al centro - - - - Bottom - In basso - - - - Auto-Scroll - Scorri automaticamente - - - - Off - Disattivato - - - - Up - Verso su - - - - Down - Verso giù - - - - Left - Verso sinistra - - - - Right - Verso destra - - - - Shadow - Ombra - - - - Shadow Color - Colore dell'ombra - - - - Shadow Angle - Angolo dell'ombra - - - - Shadow Distance - Distanza dell'ombra - - - - Shadow Softness - Morbidezza dell'ombra - - - - Shadow Opacity - Opacità dell'ombra - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - %1 (copia) - - - - ShakeEffect - - - Intensity - Intensità - - - - Rotation - Rotazione - - - - Frequency - Frequenza - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Tipo - - - - Solid Color - Colore a tinta unita - - - - SMPTE Bars - Barre SMPTE - - - - Checkerboard - A scacchi - - - - Opacity - Opacità - - - - Color - Colore - - - - Checkerboard Size - Dimensione scacchiera - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - Importa... - - - - New - Nuovo - - - - View - Visualizza - - - - Tree View - Vista ad albero - - - - Icon View - Vista ad icone - - - - Show Toolbar - Mostra barra degli strumenti - - - - Show Sequences - Mostra sequenza - - - - Replace/Relink Media - Rimpiazza/ricollega media - - - - Reveal in Explorer - Mostra in Esplora risorse - - - - Reveal in Finder - Mostra in Finder - - - - Reveal in File Manager - Mostra nel gestore file - - - - Replace Clips Using This Media - Rimpiazza clip usando questo media - - - - Create Sequence With This Media - Crea sequenza con questo media - - - - Duplicate - Duplica - - - - Delete All Clips Using This Media - Elimina tutte le clip che usano questo media - - - - Proxy - Clip rappresentativa - - - - Generating proxy: %1% complete - Generazione clip rappresentative: %1% completo - - - - Create/Modify Proxy - Crea/modifica clip rappresentativa - - - - Create Proxy - Crea clip rappresentativa - - - - Modify Proxy - Modifica clip rappresentativa - - - - Restore Original - Ripristina l'originale - - - - Delete - Elimina - - - - Preview in Media Viewer - Anteprima nel Visualizzatore media - - - - Properties... - Proprietà... - - - - Replace '%1' - Rimpiazza "%1" - - - - All Files - Tutti i file - - - - Replace Media - Rimpiazza media - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - Hai rilasciato un file dentro "%1". Desideri rimpiazzarlo con quello rilasciato? - - - - Delete proxy - Elimina clip rappresentativa - - - - Would you like to delete the proxy file "%1" as well? - Desideri eliminare anche il file della clip rappresentativa "%1"? - - - - SpeedDialog - - - Speed/Duration - Velocità/durata - - - - Speed: - Velocità: - - - - Frame Rate: - Velocità fotogrammi: - - - - Duration: - Durata: - - - - Reverse - In senso inverso - - - - Maintain Audio Pitch - Mantieni la tonalità dell'audio - - - - Ripple Changes - Sposta clip successive a catena - - - - TextEditDialog - - - Edit Text - Modifica testo - - - - Thin - Sottile - - - - Extra Light - Molto leggero - - - - Light - Leggero - - - - Normal - Normale - - - - Medium - Medio - - - - Demi Bold - Grassetto corsivo - - - - Bold - Grassetto - - - - Extra Bold - Grassetto più spesso - - - - Black - Nero - - - - TextEditEx - - - Edit Text - Modifica testo - - - - &Edit Text - Modifica t&esto - - - - TextEffect - - - - Text - Testo - - - - Font - Carattere - - - - Size - Dimensione - - - - Color - Colore - - - Alignment - Allineamento - - - - Horizontal Alignment - - - - - Left - A sinistra - - - - - Center - Al centro - - - - Right - A destra - - - - Justify - Giustifica - - - - Vertical Alignment - - - - - Top - In alto - - - - Bottom - In basso - - - - Word Wrap - A capo automatico - - - - Padding - Spaziatura - - - - Position - Posizione - - - - Outline - Bordo - - - - Outline Color - Colore bordo - - - - Outline Width - Larghezza bordo - - - - Shadow - Ombra - - - - Shadow Color - Colore dell'ombra - - - - Shadow Angle - Angolo dell'ombra - - - - Shadow Distance - Distanza dell'ombra - - - - Shadow Softness - Morbidezza dell'ombra - - - - Shadow Opacity - Opacità dell'ombra - - - - Sample Text - Testo di esempio - - - - Render - - - - - Generate simple text over this clip - - - - &Edit Text - Modifica t&esto - - - - TimecodeEffect - - - - Timecode - Codice temporale - - - - Sequence - Sequenza - - - - Media - Media - - - - Scale - Scala - - - - Color - Colore - - - - Background Color - Colore di sfondo - - - - Background Opacity - Opacità dello sfondo - - - - Offset - Traslazione - - - - Prepend - Aggiungi all'inizio - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - Timeline: - Linea temporale: - - - - Nested Sequence - Sequenza annidata - - - Effect already exists - L'effetto esiste già - - - Clip '%1' already contains a '%2' effect. Would you like to replace it with the pasted one or add it as a separate effect? - La clip "%1" contiene già un effetto "%2". Vuoi rimpiazzarlo con quello incollato oppure aggiungerlo come effetto separato? - - - Add - Aggiungi - - - Replace - Rimpiazza - - - Skip - Salta - - - Do this for all conflicts found - Ripeti per ogni conflitto trovato - - - - Title... - Titolo... - - - - Solid Color... - Colore a tinta unita... - - - - Bars... - Barre... - - - - Tone... - Suono... - - - - Noise... - Rumore... - - - - Unsaved Project - Progetto non salvato - - - - You must save this project before you can record audio in it. - Devi salvare il progetto prima di poterci registrare dell'audio. - - - - Click on the timeline where you want to start recording (drag to limit the recording to a certain timeframe) - Fa' clic sulla linea temporale nel punto in cui vuoi iniziare la registrazione (trascina per limitare la registrazione in una certa finestra) - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (nessuno) - - - - Pointer Tool - Strumento puntatore - - - - Edit Tool - Strumento di modifica - - - - Ripple Tool - Su premier è tradotto come -strumento montaggio con scarto-. Valutare quale usare - Strumento ridimensiona a catena - - - - Razor Tool - Strumento di taglio - - - - Slip Tool - Strumento di scivolamento - - - - Slide Tool - Strumento di scorrimento - - - - Hand Tool - Strumento mano - - - - Transition Tool - Strumento transizione - - - - Snapping - Bordi magnetici - - - - Zoom In - Ingrandisci - - - - Zoom Out - Rimpicciolisci - - - - Record audio - Registra audio - - - - Add title, solid, bars, etc. - Aggiungi titolo, colori, barre ecc. - - - - TimelineHeader - - - Center Timecodes - Centra codici temporali - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - - - - - &Redo - &Rifai - - - - R&ipple Delete Empty Space - El&imina spazio vuoto a catena - - - - Sequence Settings - Impostazioni sequenza - - - - &Speed/Duration - &Velocità/durata - - - - Auto-Cut Silence - Taglio automatico del silenzio - - - - Auto-S&cale - S&cala automaticamente - - - - &Reveal in Project - Most&ra nel progetto - - - - Properties - Proprietà - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Inizio: %2 -Fine: %3 -Durata: %4 - - - - Error - Errore - - - - Couldn't locate media wrapper for sequence. - Impossibile trovare contenitore media per la sequenza. - - - - Title - Titolo - - - - Solid Color - Colore a tinta unita - - - - Bars - Barre - - - - Tone - Suono - - - - Noise - Rumore - - - - Duration: - Durata: - - - - TimelineWidget - - - &Undo - Ann&ulla - - - - &Redo - &Rifai - - - C&ut - &Taglia - - - Cop&y - &Copia - - - &Paste - &Incolla - - - R&ipple Delete - El&imina a catena - - - - Sequence Settings - Impostazioni sequenza - - - - &Speed/Duration - &Velocità/durata - - - Auto-s&cale - S&cala automaticamente - - - - &Reveal in Project - Most&ra nel progetto - - - R&ename - &Rinomina - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Inizio: %2 -Fine: %3 -Durata: %4 - - - Rename '%1' - Rinomina '%1' - - - Rename multiple clips - Rinomina più clip - - - Enter a new name for this clip: - Inserisci un nuovo nome per questa clip: - - - - R&ipple Delete Empty Space - El&imina spazio vuoto a catena - - - - Auto-Cut Silence - Taglio automatico del silenzio - - - - Auto-S&cale - S&cala automaticamente - - - - Properties - Proprietà - - - - Error - Errore - - - - Couldn't locate media wrapper for sequence. - Impossibile trovare contenitore media per la sequenza. - - - - Title - Titolo - - - - Solid Color - Colore a tinta unita - - - - Bars - Barre - - - - Tone - Suono - - - - Noise - Rumore - - - - Duration: - Durata: - - - - ToneEffect - - - Type - Tipo - - - - Sine - Seno - - - - Frequency - Frequenza - - - - Amount - Ammontare - - - - Mix - Miscela - - - - Tone - Suono - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - Posizione - - - - Scale - Scalatura - - - - Uniform Scale - Mantieni proporzioni - - - - Rotation - Rotazione - - - - Anchor Point - Punto di ancoraggio - - - - Opacity - Opacità - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - Blend Mode - Modalità miscela - - - Normal - Normale - - - Darken - Scurisci - - - Multiply - Moltiplica - - - Color Burn - Brucia colore - - - Lighten - Illumina - - - Screen - Scherma - - - Color Dodge - Scherma colore - - - Overlay - Sovrapponi - - - Soft Light - Luce leggera - - - Hard Light - Luce forte - - - Difference - Differenza - - - Exclusion - Esclusione - - - - Transition - - - Length - Lunghezza - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - È disponibile un aggiornamento sul sito di Olive. Visita www.olivevideoeditor.org per scaricarlo. - - - - VSTHost - - - - Error loading VST plugin - Errore nel caricamento del plugin VST - - - Failed to create VST reference - Errore nella creazione del riferimento VST - - - - Failed to load VST plugin "%1": %2 - Impossibile caricare il plugin 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. - NOTA: Non si possono caricare plugin VST a 32 bit in una versione a 64 bit di Olive. Si prega di trovare la versione a 64 bit di questo plugin oppure di passare alla versione 32 bit di 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. - NOTA: Non si possono caricare plugin VST a 64 bit in una versione a 32 bit di Olive. Si prega di trovare la versione a 32 bit di questo plugin oppure di passare alla versione 64 bit di Olive. - - - - Failed to locate entry point for dynamic library. - Impossibile trovare punto d'ingresso per la libreria dinamica. - - - - VST Error - Errore VST - - - - Plugin's magic number is invalid - Il magic number del plugin non è valido - - - - Plugin - Plugin - - - - Interface - Interfaccia - - - - Show - Mostra - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - Plugin VST - - - - Viewer - - Sequence Viewer - Visualizzatore sequenza - - - Media Viewer - Visualizzatore media - - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (nessuno) - - - - Drag video only - Sposta solamente il video - - - - Drag audio only - Sposta solamente l'audio - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - Salva fotogramma come immagine... - - - - Show Fullscreen - Mostra a schermo intero - - - - Disable - Disattiva - - - - Screen %1: %2x%3 - Schermo %1: %2x%3 - - - - Zoom - Ingrandimento - - - - Fit - Adatta - - - - Custom - Personalizzato - - - - Close Media - Chiudi media - - - - Save Frame - Salva fotogramma - - - - Viewer Zoom - Ingrandimento visualizzatore - - - - Set Custom Zoom Value: - Imposta un valore di ingrandimento personalizzato: - - - - ViewerWindow - - - Exit Fullscreen - Esci dalla modalità a schermo intero - - - - VoidEffect - - - (unknown) - (sconosciuto) - - - - Missing Effect - Effetto mancante - - - - VolumeEffect - - - - Volume - Volume - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - - transition - - Invalid transition - Transizione non valida - - - No candidate for transition '%1'. This transition may be corrupt. Try reinstalling it or Olive. - Nessun candidato per la transizione "%1". Questa transizione potrebbe essere danneggiata. Prova a reinstallare la transizione o Olive. - - - diff --git a/ts/olive_ru.ts b/ts/olive_ru.ts deleted file mode 100644 index d3d635b89..000000000 --- a/ts/olive_ru.ts +++ /dev/null @@ -1,4386 +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 доступен для скачивания на сайте программы. - - - - ActionSearch - - - Search for action... - Найти действие… - - - - AdvancedVideoDialog - - - Advanced Video Settings - Дополнительные параметры видео - - - - Pixel Format: - Формат пикселей: - - - - Threads: - Потоков: - - - - Audio - - - %1 Audio - - - - - Recording %1 - Запись %1 - - - - AudioNoiseEffect - - - Amount - Количество - - - - Mix - Смешивание - - - - Noise - Шум - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - Вырезать тишину - - - - Attack Threshold: - Порог атаки: - - - - Attack Time: - Время атаки: - - - - Release Threshold: - Порог восстановления: - - - - Release Time: - Время восстановления: - - - - Cacher - - - - Could not open %1 - %2 - Не удалось открыть %1 - %2 - - - - 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 - Перспектива - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - 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. - Это свободный нелинейный видеоредактор с открытым исходным кодом под лицензией 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 - Некорректный эффект - - - 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 - - - Effects: - Эффекты: - - - - (none) - (нет) - - - - 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: - Файл: - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - ExportDialog - - - Export "%1" - Экспортировать "%1" - - - - Unknown codec name %1 - - - - - Export Failed - Не удалось экспортировать - - - - Export failed - %1 - Не удалось экспортировать — %1 - - - - Invalid dimensions - Некорректный размер кадра - - - - Export width and height must both be even numbers/divisible by 2. - Ширина и высота кадра при экспорте должны делиться на 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: - Тип сжатия: - - - - Advanced - Дополнительно - - - - Audio - Звук - - - - Sampling Rate: - Частота дискретизации: - - - - Bitrate (Kbps/CBR): - Скорость потока (Кбит/с / CBR): - - - - ExportThread - - - failed to send frame to encoder (%1) - - - - - failed to receive packet from encoder (%1) - - - - - could not video encoder for %1 - - - - - could not allocate video stream - - - - - could not allocate video encoding context - - - - - could not open output video encoder (%1) - - - - - could not copy video encoder parameters to output stream (%1) - - - - - could not audio encoder for %1 - - - - - could not allocate audio stream - - - - - could not allocate audio encoding context - - - - - could not open output audio encoder (%1) - - - - - could not copy audio encoder parameters to output stream (%1) - - - - - could not allocate audio buffer (%1) - - - - - could not create output format context - - - - - could not open output file (%1) - - - - - could not write output file header (%1) - - - - - could not write output file trailer (%1) - - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Тип - - - - Fill Left with Right - Заполнить левый канал правым - - - - Fill Right with Left - Заполнить правый канал левым - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - Frei0rEffect - - - Failed to load Frei0r plugin "%1": %2 - Не удалось загрузить плагшин Frei0r "%1": %2 - - - - Error loading Frei0r plugin - Ошибка при загрузке плагина Frei0r - - - - GraphEditor - - - Graph Editor - Редактор графов - - - - Linear - Линейный - - - - Bezier - Безье - - - - Hold - Константа - - - - GraphView - - - Zoom to Selection - Масштабировать в выделение - - - - Zoom to Show All - Масштабировать и показать всё - - - - Reset View - Сбросить масштаб - - - - InterlacingName - - - None (Progressive) - Нет (прогрессивно) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - Сначала верхнее поле - - - Bottom Field First - Сначала нижнее поле - - - - Invalid - Некорректно - - - - KeyframeNavigator - - - Enable Keyframes - Включить ключевые кадры - - - - KeyframeView - - - Linear - Линейный - - - - Bezier - Безье - - - - Hold - Константа - - - - LabelSlider - - - &Edit - &Изменить - - - - &Reset to Default - С&бросить до исходного - - - - - Set Value - Установить значение - - - - - New value: - Новое значение: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - 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 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - 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 - Линии дорожек - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - 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 - Редактор графов - - - - Node 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 - Включить прилипание - - - - Auto-Cut Silence - Вырезать тишину - - - - 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к/с - - - - Audio %1: %2Hz %3 - Звук %1: %2Гц %3 - - - - %n channel(s) - - %n канал - %n канала - %n каналов - - - - - Conform to Frame Rate: - - - - - Alpha is Premultiplied - Предумноженный альфа-канал - - - - Auto (%1) - Авто (%1) - - - - Interlacing: - Чересстрочность: - - - - Color Space: - - - - - 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. - - - - - 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: - Название: - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - Отключить ключевые кадры - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Отключение приведёт к удалению всех текущих ключевых кадров. Вы уверены? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - Файл - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - 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. - Это файлс параметрами совсем другого эффекта. - - - - 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 аварийно завершил работу, обнаружен файл автовосстановления. Открыть его? - - - - 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 - Применить для всех конфликтов - - - - 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? - Проект был изменён с момента последнего сохранения. Хотите сохранить его перед закрытием? - - - - Import media... - Импортировать медиафайлы… - - - - All Files - Все файлы - - - - No active sequence - Нет активных последовательностей - - - - Please open the sequence to perform this action. - Откройте последовательность для выполнения этого действия. - - - - No clips selected - Клипы не выделены - - - - Select the clips you wish to auto-cut - Выделите клипы, в которых надо вырезать тишину - - - - Missing Project File - Отсутствует проектный файл - - - - Specified project '%1' does not exist. - Указанный проект '%1' не существует. - - - - PanEffect - - - - Pan - Панорама - - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - - Preferences - Параметры - - - - Default Sequence - Последовательности по умолчанию - - - - 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: - Язык: - - - - Default Sequence Settings - - - - - Add Default Effects to New Clips - Добавлять эффекты по умолчанию в новые клипы - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - 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 - - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - Разрешить перетаскивание на монтажный стол извне - - - - Auto-Scale By Default - Автоматически масштабировать по умолчанию - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - Воспроизводить звук при прокрутке - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - Включить фокус наводкой - - - - Ask For Name When Setting Marker - Спрашивать имя маркера при добавлении - - - - Appearance - Внешний вид - - - - Theme - Тема - - - - Olive Dark (Default) - Olive Dark (по умолчанию) - - - - Olive Light - Olive Light - - - - Native - Системная - - - - Native (Light Icons) - Системная со светлыми значками - - - - Use Native Menu Styling - - - - - Custom CSS: - Свой CSS: - - - - - Browse - Просмотр - - - - Image sequence formats: - Форматы изображений: - - - - Audio Recording: - Запись звука: - - - - Mono - Моно - - - - Stereo - Стерео - - - - Effect Textbox Lines: - Строк в редакторе титров: - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - Разрешение миниатюр: - - - - Waveform Resolution: - Разрешение волновой формы: - - - - Delete Previews - Удалить миниатюры - - - - Use Software Fallbacks When Possible - По возможности использовать программную реализацию вместо аппаратной - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - General - Общие - - - - Behavior - Поведение - - - - Memory Usage - Использование памяти - - - - Upcoming Frame Queue: - Очередь последующих кадров: - - - - - frames - кадров - - - - - seconds - секунд - - - - Previous Frame Queue: - Очередь предыдущих кадров: - - - - Playback - Воспроизведение - - - - Output Device: - Устройство выхода: - - - - - Default - По умолчанию - - - - Input Device: - Устройство входа: - - - - Sample Rate: - Частота дискретизации: - - - - Audio - Звук - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - 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 - - - New - Создать - - - - Open Project - Открыть проект - - - - Save Project - Сохранить проект - - - - Undo - Отменить - - - - Redo - Вернуть - - - - Tree View - В виде дерева - - - - Icon View - В виде миниатюр - - - - List View - В виде списка - - - - 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. - Нет активных последовательностей. Откройте последовательность, из которой хотите удалить клипы. - - - - ProjectModel - - - Sequence %1 - - - - - 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' яавляется частью последовательности изображений. Загрузить его как таковой? - - - - 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 - Непрозрачность тени - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - %1 (копия) - - - - ShakeEffect - - - Intensity - Интенсивность - - - - Rotation - Вращение - - - - Frequency - Частота - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Тип - - - - Solid Color - Сплошная заливка - - - - SMPTE Bars - Таблица SMPTE - - - - Checkerboard - Шахматная доска - - - - Opacity - Непрозрачность - - - - Color - Цвет - - - - Checkerboard Size - Размер клеток - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - Импортировать… - - - - New - Создать - - - - View - Вид - - - - Tree View - В виде таблицы - - - - Icon View - В виде миниатюр - - - - Show Toolbar - Показывать панель - - - - Show Sequences - Показывать последовательности - - - - Replace/Relink Media - Заменить/пересвязать файлы - - - - Reveal in 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 '%1' - Заменить '%1' - - - - All Files - Все файлы - - - - 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 - - - - - Extra Light - - - - - Light - - - - - Normal - Обычный - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - Изменить текст - - - - &Edit Text - &Изменить текст - - - - TextEffect - - - - Text - Текст - - - - Font - Шрифт - - - - Size - Кегль - - - - Color - Цвет - - - Alignment - Выравнивание - - - - Horizontal Alignment - - - - - Left - Слева - - - - - Center - По центру - - - - Right - Справа - - - - Justify - По ширине - - - - Vertical Alignment - - - - - Top - Сверху - - - - Bottom - Снизу - - - - Word Wrap - Перенос строки - - - - Padding - Отступ - - - - Position - Позиция - - - - Outline - Обводка - - - - Outline Color - Цвет обводки - - - - Outline Width - Толщина обводки - - - - Shadow - Тень - - - - Shadow Color - Цвет тени - - - - Shadow Angle - Угол тени - - - - Shadow Distance - Длина тени - - - - Shadow Softness - Мягкость тени - - - - Shadow Opacity - Непрозрачность тени - - - - Sample Text - Образец текста - - - - Render - - - - - Generate simple text over this clip - - - - - TimecodeEffect - - - - Timecode - Тайм-код - - - - Sequence - Последовательность - - - - Media - Файл - - - - Scale - Масштаб - - - - Color - Цвет - - - - Background Color - Цвет фона - - - - Background Opacity - Непрозрачность фона - - - - Offset - Смещение - - - - Prepend - Префикс - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - Timeline: - Монтажный стол: - - - 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 - Применить для всех конфликтов - - - - Nested Sequence - Вложенная последовательность - - - - 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) - Щелкните на монтажном столе в точке, от которой хотите начать запись звука. Перетащите курсор после щелчка, чтобы сразу задать длительность записи. - - - - 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. - Добавить титры, заливку цветом, испытательную таблицу и т.д. - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (нет) - - - - TimelineHeader - - - Center Timecodes - Центрировать тайм-код - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - &Отменить - - - - &Redo - В&ернуть - - - - R&ipple Delete Empty Space - &Удалить со сдвигом пустое пространство - - - - Sequence Settings - Параметры последовательности - - - - &Speed/Duration - С&корость/Длительность - - - - Auto-Cut Silence - Вырезать тишину - - - - 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: - Длительность: - - - - TimelineWidget - - - &Undo - &Отменить - - - - &Redo - В&ернуть - - - - Sequence Settings - Параметры последовательности - - - - &Speed/Duration - С&корость/Длительность - - - - &Reveal in Project - &Показать в проекте - - - - Properties - Свойства - - - - %1 -Start: %2 -End: %3 -Duration: %4 - %1 -Начало: %2 -Конец: %3 -Длительность: %4 - - - - R&ipple Delete Empty Space - &Удалить со сдвигом пустое пространство - - - - Auto-Cut Silence - Вырезать тишину - - - - Auto-S&cale - Авто&масштабирование - - - - Error - Ошибка - - - - Couldn't locate media wrapper for sequence. - - - - - Title - Титры - - - - Solid Color - Цветная заливка - - - - Bars - Испытательная таблица - - - - Tone - Звуковой сигнал - - - - Noise - Шум - - - - Duration: - Длительность: - - - - ToneEffect - - - Type - Тип - - - - Sine - Синусоида - - - - Frequency - Частота - - - - Amount - Количество - - - - Mix - Смешать - - - - Tone - Звуковой сигнал - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - Позиция - - - - Scale - Масштаб - - - - Uniform Scale - Сохранять пропорции - - - - Rotation - Вращение - - - - Anchor Point - Точка привязки - - - - Opacity - Непрозрачность - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - 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 load VST plugin "%1": %2 - - - - - Failed to locate entry point for dynamic library. - - - - - VST Error - Ошибка VST - - - - Plugin's magic number is invalid - - - - - Plugin - Плагин - - - - Interface - Интерфейс - - - - Show - Показать - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - Плагин VST - - - - Viewer - - Sequence Viewer - Просмотр последовательностей - - - Media Viewer - Просмотр проекта - - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (нет) - - - - Drag video only - Перетаскивать только видео - - - - Drag audio only - Перетаскивать только звук - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - Сохранить кадр как изображение… - - - - Show Fullscreen - Полноэкранный режим - - - - Disable - Отключить - - - - Screen %1: %2x%3 - Экран %1: %2×%3 - - - - Zoom - Масштаб - - - - Fit - Уместить - - - - Custom - Другой - - - - Close Media - Закрыть файл - - - - Save Frame - Сохранить кадр - - - - Viewer Zoom - Масштаб просмотра - - - - Set Custom Zoom Value: - Другое значение масштаба: - - - - ViewerWindow - - - Exit Fullscreen - Выйти из полноэкранного режима - - - - VoidEffect - - - (unknown) - (неизвестно) - - - - Missing Effect - Отсутствующий эффект - - - - VolumeEffect - - - - Volume - Громкость - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - - transition - - Invalid transition - Некорректный переход - - - diff --git a/ts/olive_sr.ts b/ts/olive_sr.ts deleted file mode 100644 index 2ccaf0e78..000000000 --- a/ts/olive_sr.ts +++ /dev/null @@ -1,4349 +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 тим је под обавезом да обавести своје кориснике да је Olive-ов изворни код доступан за преузимање са његове веб странице. - - - - ActionSearch - - - Search for action... - Потражите радњу... - - - - AdvancedVideoDialog - - - Advanced Video Settings - Напредне видео поставке - - - - Pixel Format: - Формат пиксела: - - - - Threads: - - - - - Audio - - Audio - Аудио - - - Recording - Снимање - - - - %1 Audio - %1 Аудио - - - - Recording %1 - Снимање %1 - - - - AudioNoiseEffect - - - Amount - Количина - - - - Mix - Микс - - - - Noise - - - - - Generate audio noise that can be mixed with this clip. - - - - - AutoCutSilenceDialog - - - Cut Silence - - - - - Attack Threshold: - - - - - Attack Time: - - - - - Release Threshold: - - - - - Release Time: - - - - - Cacher - - - - Could not open %1 - %2 - - - - - ChannelLayoutName - - - Invalid - Неважеће - - - - Mono - Моно - - - - Stereo - Стерео - - - - ClipPropertiesDialog - - - "%1" Properties - - - - - Multiple Clip Properties - - - - - Name: - - - - - Duration: - - - - - (multiple) - - - - - CollapsibleWidget - - - <untitled> - <неименовано> - - - - ColorButton - - - Set Color - Постави боју - - - - CornerPinEffect - - - Top Left - Горње лево - - - - Top Right - Горње десно - - - - Bottom Left - Доње лево - - - - Bottom Right - Доње десно - - - - Perspective - Перспектива - - - - Corner Pin - - - - - Distort - - - - - Distort/warp this clip by pinning each of its four corners. - - - - - CrashDialog - - - We're very sorry, Olive has crashed. Please send the following data to developers: - - - - - CrossDissolveTransition - - - Cross Dissolve - - - - - Dissolves - - - - - Dissolve clips evenly. - - - - - 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 - XML поставке ефекта %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 - - - Effects: - Ефекти: - - - &Paste - &Залепи - - - - (none) - (нема) - - - - 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? - Онемогућавање кључних кадрова ће обрисати све тренутне кључне кадрове. Да ли сте сигурни да желите ово урадити? - - - - EffectUI - - - %1 (Opening) - - - - - %1 (Closing) - - - - - %1 (multiple) - - - - - Cu&t - &Режи - - - - &Copy - &Копирај - - - - Move &Up - Помери &горе - - - - Move &Down - Помери &доле - - - - D&elete - &Обриши - - - - Load Settings From File - Учитај поставке из датотеке - - - - Save Settings to File - Спаси поставке у датотеку - - - - EmbeddedFileChooser - - - File: - Датотека: - - - - ExponentialFadeTransition - - - Exponential Fade - - - - - An exponential audio fade that starts slow and ends fast. - - - - - 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% (ETA: %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): - Стопа битова (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): - Жељена величина датотеке (MB): - - - - Format: - Формат: - - - - Range: - Распон: - - - - Entire Sequence - Читава секвенца - - - - In to Out - Од почетка до краја - - - - Video - Видео - - - - - Codec: - Кодек: - - - - Width: - Ширина: - - - - Height: - Висина: - - - - Frame Rate: - Оквирна стопа: - - - - Compression Type: - Тип компримације: - - - - Advanced - Напредно - - - - Audio - Аудио - - - - Sampling Rate: - Стопа узорака: - - - - Bitrate (Kbps/CBR): - Стопа битова (Kbps/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) - - - - FFmpegDecoder - - - Failed to find appropriate decoder for this codec (%1 :: %2) - - - - - Failed to allocate codec context (%1 :: %2) - - - - - Error decoding %1 - %2 %3 - - - - - FillLeftRightEffect - - - Type - Тип - - - - Fill Left with Right - Попуни лево са десним - - - - Fill Right with Left - Попуни десно са левим - - - - Fill Left/Right - - - - - Replaces either the left or right channel with the other - - - - - 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-a. Молимо нађите 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-a. Молимо нађите 32-битно издање ових додатака, или пређите на 64-битно издање Olive-а. - - - - Error loading Frei0r plugin - Грешка при учитавању Frei0r додатака - - - - GraphEditor - - - Graph Editor - Уређивач графикона - - - - Linear - Линеарно - - - - Bezier - Bezier - - - - Hold - Држи - - - - GraphView - - - Zoom to Selection - Повећај ка одабиру - - - - Zoom to Show All - Повећај ка свему - - - - Reset View - Врати првобитни приказ - - - - InterlacingName - - - None (Progressive) - Нема (прогресивно) - - - - Upper Field First - - - - - Lower Field First - - - - Top Field First - Горње поље прво - - - Bottom Field First - Доње поље прво - - - - Invalid - Неважеће - - - - KeyframeNavigator - - - Enable Keyframes - Омогући кључне кадрове - - - - KeyframeView - - - Linear - Линеарно - - - - Bezier - Bezier - - - - Hold - Држи - - - - LabelSlider - - - &Edit - - - - - &Reset to Default - - - - - - Set Value - Одреди вредност - - - - - New value: - Нова вредност: - - - - LinearFadeTransition - - - Linear Fade - - - - - An linear audio fade that fades evenly at a constant rate. - - - - - 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 - - - - LogarithmicFadeTransition - - - Logarithmic Fade - - - - - An logarithmic audio fade that starts fast and ends slow. - - - - - MainWindow - - - Welcome to %1 - - - - - &File - - - - - &New - - - - - &Open Project - - - - - Clear Recent List - - - - - Open Recent - - - - - &Save Project - - - - - Save Project &As - - - - - &Import... - - - - - &Export... - - - - - E&xit - - - - - &Edit - - - - - &Undo - - - - - Redo - - - - Cu&t - &Режи - - - &Paste - &Залепи - - - - 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 - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Rectified Waveforms - - - - - Frames - - - - - Drop Frame - - - - - Non-Drop Frame - - - - - Milliseconds - - - - - Title/Action Safe Area - - - - - Off - - - - - Default - - - - - 4:3 - - - - - 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 - Уређивач графикона - - - - Node 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 - - - - - Auto-Cut Silence - - - - - 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)) - - - - - Interlacing: - - - - - Audio Frequency: - - - - - Audio Channels: - - - - - Name: %1 -Video Dimensions: %2x%3 -Frame Rate: %4 -Audio Frequency: %5 -Audio Layout: %6 - - - - - Name - - - - - Duration - - - - - Rate - - - - - MediaPropertiesDialog - - - "%1" Properties - - - - - Tracks: - - - - - Video %1: %2x%3 %4FPS - - - - - Audio %1: %2Hz %3 - - - - - %n channel(s) - - - - - - - - - Conform to Frame Rate: - - - - - Alpha is Premultiplied - - - - - Auto (%1) - - - - - Interlacing: - - - - - Color Space: - - - - - 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. - - - - - Enter custom aspect ratio - - - - - Enter the aspect ratio to use for the title/action safe area (e.g. 16:9): - - - - - NewSequenceDialog - - - Editing "%1" - - - - - New Sequence - - - - - Preset: - - - - - Film 4K - - - - - TV 4K (Ultra HD/2160p) - - - - - 1080p - - - - - 720p - - - - - 480p - - - - - 360p - - - - - 240p - - - - - 144p - - - - - NTSC (480i) - - - - - PAL (576i) - - - - - Custom - - - - - Video - Видео - - - - Width: - Ширина: - - - - Height: - Висина: - - - - Frame Rate: - Оквирна стопа: - - - - Pixel Aspect Ratio: - - - - - Square Pixels (1.0) - - - - - Interlacing: - - - - - None (Progressive) - Нема (прогресивно) - - - - Audio - Аудио - - - - Sample Rate: - - - - - Name: - - - - - Node - - - Node - - - - - NodeBlock - - - Previous - - - - - Next - - - - - Block - - - - - NodeEditor - - - Node Editor - - - - - NodeIO - - - Disable Keyframes - Онемогући кључне кадрове - - - - Disabling keyframes will delete all current keyframes. Are you sure you want to do this? - Онемогућавање кључних кадрова ће обрисати све тренутне кључне кадрове. Да ли сте сигурни да желите ово урадити? - - - - NodeMedia - - - Matrix - - - - - Texture - - - - - Media - - - - - NodeTexturePassthru - - - - Texture - - - - - Image Output - - - - - NodeVideoClip - - - - Texture - - - - - NodeView - - - Node Editor - - - - - OldEffectNode - - - Save Effect Settings - Спаси пиставке ефекта - - - - - Effect XML Settings %1 - XML поставке ефекта %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. - Ова датотека поставки није прикладна за овај ефекат. - - - - OliveGlobal - - - Olive Project %1 - - - - - Auto-recovery - - - - - Olive didn't close properly and an autorecovery file was detected. Would you like to open it? - - - - - 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? - - - - - Add - - - - - Replace - - - - - Skip - - - - - Do this for all conflicts found - - - - - Open Project... - - - - - Missing recent project - - - - - The project '%1' no longer exists. Would you like to remove it from the recent projects list? - - - - - Save Project As... - - - - - Unsaved Project - - - - - This project has changed since it was last saved. Would you like to save it before closing? - - - - - Import media... - - - - - All Files - - - - - No active sequence - - - - - Please open the sequence to perform this action. - - - - - No clips selected - - - - - Select the clips you wish to auto-cut - - - - - Missing Project File - - - - - Specified project '%1' does not exist. - - - - - PanEffect - - - - Pan - - - - - Modifying the panning on a stereo audio clip. - - - - - PreferencesDialog - - - Preferences - - - - - Default Sequence - - - - - Invalid CSS File - - - - - CSS file '%1' does not exist. - - - - - 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 - - - - - Delete All Previews - - - - - Are you sure you want to delete all previews? - - - - - Previews Deleted - - - - - Language: - - - - - Default Sequence Settings - - - - - Add Default Effects to New Clips - - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - - - - - 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 - - - - - Invert Timeline Scroll Axes - - - - - Enable Drag Files to Timeline - - - - - Auto-Scale By Default - - - - - Auto-Seek to Imported Clips - - - - - Audio Scrubbing - - - - - Drop Files on Media to Replace - - - - - Enable Hover Focus - - - - - Ask For Name When Setting Marker - - - - - Appearance - - - - - Theme - - - - - Olive Dark (Default) - - - - - Olive Light - - - - - Native - - - - - Native (Light Icons) - - - - - Use Native Menu Styling - - - - - Custom CSS: - - - - - - Browse - - - - - Image sequence formats: - - - - - Audio Recording: - - - - - Mono - Моно - - - - Stereo - Стерео - - - - Effect Textbox Lines: - - - - - (None) - - - - - OpenColorIO Config Error - - - - - Failed to set OpenColorIO configuration: %1 - - - - - Invalid OpenColorIO Configuration File - - - - - You must specify an OpenColorIO configuration file if color management is enabled. - - - - - OpenColorIO configuration file '%1' does not exist. - - - - - Browse for OpenColorIO configuration - - - - - All previews deleted successfully. You may have to re-open your current project for changes to take effect. - - - - - Thumbnail Resolution: - - - - - Waveform Resolution: - - - - - Delete Previews - - - - - Use Software Fallbacks When Possible - - - - - Don't Use Proxies When Exporting - - - - - Use originals instead of proxies when exporting - - - - - General - - - - - Behavior - - - - - Memory Usage - - - - - Upcoming Frame Queue: - - - - - - frames - - - - - - seconds - - - - - Previous Frame Queue: - - - - - Playback - - - - - Output Device: - - - - - - Default - - - - - Input Device: - - - - - Sample Rate: - - - - - Audio - Аудио - - - - Enable Color Management - - - - - OpenColorIO Config File: - - - - - Default Input Color Space: - - - - - Display: - - - - - View: - - - - - Look: - - - - - Bit Depth - - - - - Playback (Offline): - - - - - Export (Online): - - - - - Color Management - - - - - 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 - - - - - Could not find stream information - %1 - - - - - Project - - - New - - - - - Open Project - - - - - Save Project - - - - - Undo - - - - - Redo - - - - - Tree View - - - - - Icon View - - - - - List View - - - - - Search media, markers, etc. - - - - - Project - - - - - - 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' - - - - - 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? - - - - - Skip - - - - - No sequence is active, please open the sequence you want to delete clips from. - - - - - ProjectModel - - - Sequence %1 - - - - - Import a Project - - - - - "%1" is an Olive project file. It will merge with this project. Do you wish to continue? - - - - - Image sequence detected - - - - - The file '%1' appears to be part of an image sequence. Would you like to import it as such? - - - - - ProxyDialog - - - Create Proxy - - - - - Proxy - - - - - Dimensions: - - - - - Same Size as Source - - - - - Half Resolution (1/2) - - - - - Quarter Resolution (1/4) - - - - - Eighth Resolution (1/8) - - - - - Sixteenth Resolution (1/16) - - - - - Format: - Формат: - - - - ProRes HQ - - - - - Location: - - - - - Same as Source (in "%1" folder) - - - - - Proxy file exists - - - - - The file "%1" already exists. Do you wish to replace it? - - - - - Custom Location - - - - - ProxyGenerator - - - Finished generating proxy for "%1" - - - - - ReplaceClipMediaDialog - - - Replace clips using "%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 - - - - - Rich Text - - - - - Render - - - - - Render formatted rich text over a clip. - - - - - Sequence - - - %1 (copy) - - - - - ShakeEffect - - - Intensity - - - - - Rotation - - - - - Frequency - - - - - Shake - - - - - Distort - - - - - Simulate a camera shake movement. - - - - - SolidEffect - - - Type - Тип - - - - Solid Color - - - - - SMPTE Bars - - - - - Checkerboard - - - - - Opacity - - - - - Color - - - - - Checkerboard Size - - - - - Solid - - - - - Render - - - - - Render a solid color over this clip. - - - - - SourcesCommon - - - Import... - - - - - New - - - - - View - - - - - Tree View - - - - - Icon View - - - - - Show Toolbar - - - - - Show Sequences - - - - - Replace/Relink Media - - - - - Reveal in Explorer - - - - - Reveal in 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 - - - - - Create/Modify Proxy - - - - - Create Proxy - - - - - Modify Proxy - - - - - Restore Original - - - - - Delete - - - - - Preview in Media Viewer - - - - - Properties... - - - - - Replace '%1' - - - - - All Files - - - - - Replace Media - - - - - You dropped a file onto '%1'. Would you like to replace it with the dropped file? - - - - - Delete proxy - - - - - Would you like to delete the proxy file "%1" as well? - - - - - SpeedDialog - - - Speed/Duration - - - - - Speed: - - - - - Frame Rate: - Оквирна стопа: - - - - Duration: - - - - - Reverse - - - - - Maintain Audio Pitch - - - - - Ripple Changes - - - - - TextEditDialog - - - Edit Text - - - - - Thin - - - - - Extra Light - - - - - Light - - - - - Normal - - - - - Medium - - - - - Demi Bold - - - - - Bold - - - - - Extra Bold - - - - - Black - - - - - TextEditEx - - - Edit Text - - - - - &Edit Text - - - - - TextEffect - - - - Text - - - - - Font - - - - - Size - - - - - Color - - - - - Horizontal Alignment - - - - - Left - - - - - - Center - - - - - Right - - - - - Justify - - - - - Vertical Alignment - - - - - Top - - - - - Bottom - - - - - Word Wrap - - - - - Padding - - - - - Position - - - - - Outline - - - - - Outline Color - - - - - Outline Width - - - - - Shadow - - - - - Shadow Color - - - - - Shadow Angle - - - - - Shadow Distance - - - - - Shadow Softness - - - - - Shadow Opacity - - - - - Sample Text - - - - - Render - - - - - Generate simple text over this clip - - - - - TimecodeEffect - - - - Timecode - - - - - Sequence - - - - - Media - - - - - Scale - - - - - Color - - - - - Background Color - - - - - Background Opacity - - - - - Offset - - - - - Prepend - - - - - Render - - - - - Render the media or sequence timecode on this clip. - - - - - Timeline - - - Nested Sequence - - - - - 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) - - - - - Video Transitions - - - - - Audio Transitions - - - - - Timeline: %1 - - - - - (none) - (нема) - - - - 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. - - - - - TimelineHeader - - - Center Timecodes - - - - - TimelineLabel - - - Rename Track - - - - - Enter the new name for this track - - - - - TimelineView - - - &Undo - - - - - &Redo - - - - - R&ipple Delete Empty Space - - - - - Sequence Settings - - - - - &Speed/Duration - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - &Reveal in Project - - - - - Properties - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - - - - - Error - - - - - Couldn't locate media wrapper for sequence. - - - - - Title - - - - - Solid Color - - - - - Bars - - - - - Tone - - - - - Noise - - - - - Duration: - - - - - TimelineWidget - - - &Undo - - - - - &Redo - - - - &Paste - &Залепи - - - - Sequence Settings - - - - - &Speed/Duration - - - - - &Reveal in Project - - - - - %1 -Start: %2 -End: %3 -Duration: %4 - - - - - R&ipple Delete Empty Space - - - - - Auto-Cut Silence - - - - - Auto-S&cale - - - - - Properties - - - - - Error - - - - - Couldn't locate media wrapper for sequence. - - - - - Title - - - - - Solid Color - - - - - Bars - - - - - Tone - - - - - Noise - - - - - Duration: - - - - - ToneEffect - - - Type - Тип - - - - Sine - - - - - Frequency - - - - - Amount - Количина - - - - Mix - Микс - - - - Tone - - - - - Generate a sine wave tone to mix into this clip's audio. - - - - - Track - - - Video %1 - - - - - Audio %1 - - - - - Subtitle %1 - - - - - Unknown %1 - - - - - TransformEffect - - - Position - - - - - Scale - - - - - Uniform Scale - - - - - Rotation - - - - - Anchor Point - - - - - Opacity - - - - - Transform - - - - - Distort - - - - - Transform the position, scale, and rotation of this clip. - - - - - Transition - - - Length - - - - - UpdateNotification - - - An update is available from the Olive website. Visit www.olivevideoeditor.org to download it. - - - - - VSTHost - - - - Error loading VST plugin - - - - - Failed to load VST plugin "%1": %2 - - - - - Failed to locate entry point for dynamic library. - - - - - VST Error - - - - - Plugin's magic number is invalid - - - - - Plugin - - - - - Interface - - - - - Show - - - - - VST Plugin 2.x - - - - - Use a VST 2.x plugin on this clip's audio. - - - - - VST Plugin - - - - - Viewer - - - Viewer: %1 - - - - - Failed to import recorded file - - - - - An error occurred trying to import the recorded audio - - - - - (none) - (нема) - - - - Drag video only - - - - - Drag audio only - - - - - Sequence Viewer: %1 - - - - - Media Viewer: %1 - - - - - ViewerWidget - - - Save Frame as Image... - - - - - Show Fullscreen - - - - - Disable - - - - - Screen %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 - - - - - Adjust the volume of this clip's audio - - - - - bitdepths - - - 8-bit - - - - - 16-bit Integer - - - - - Half-Float (16-bit) - - - - - Full-Float (32-bit) - - - - diff --git a/ts/olive_uk.ts b/ts/olive_uk.ts deleted file mode 100644 index 1a0c8e664..000000000 --- a/ts/olive_uk.ts +++ /dev/null @@ -1,3813 +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 - Змішування - - - - AutoCutSilenceDialog - - - Cut Silence - Вирізати тишу - - - - Attack Threshold: - Поріг атаки: - - - - Attack Time: - Час атаки: - - - - Release Threshold: - Поріг відновлення: - - - - Release Time: - Час відновлення: - - - - Cacher - - - - Could not open %1 - %2 - Не вдалося відкрити %1 - %2 - - - - 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 - Увімкнути прилипання - - - - Auto-Cut Silence - Автовирізання тиші - - - 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 to perform this action. - Відкрийте послідовність для застосування цієї дії. - - - - No clips selected - Не обрано кліпи - - - - Select the clips you wish to auto-cut - Уточнити - Оберіть кліпи для автовирізання - - - Please open the sequence you wish to export. - Будь-ласка, відкрийте послідовність котру хочете експортувати. - - - - Missing Project File - Відсутній файл проекта - - - - Specified project '%1' does not exist. - Вказаний проект '%1' не існує. - - - - PanEffect - - - Pan - Уточнити - Панорама - - - - PreferencesDialog - - - Preferences - Параметри - - - - Default Sequence - Типова послідовність - - - - 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 - Поведінка - - - - Add Default Effects to New Clips - Додавати типові ефекти для нових кліпів - - - - Automatically Seek to the Beginning When Playing at the End of a Sequence - Автопрокручувати на початок при відворенні з кінця послідовності - - - - 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 - Автомасштабування за умовчанням - - - - Auto-Seek to Imported Clips - Уточнити - Автопрокручувати до імпортованих кліпів - - - - Audio Scrubbing - Відтворювати звук під час прокручування - - - - Drop Files on Media to Replace - Уточнити - Перетягування файлів на медіа для заміни - - - - Enable Hover Focus - Увімкнути фокус наведенням - - - - Ask For Name When Setting Marker - Запитувати назву маркера при додаванні - - - - 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 - - - New - Створити - - - - Open Project - Відкрити проект - - - - Save Project - Зберегти проект - - - - Undo - Відмінити - - - - Redo - Повернути - - - - Tree View - У вигляді таблиці - - - - Icon View - У вигляді мініатюр - - - - List View - У вигляді списку - - - - 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 - Редагувати текст - - - - &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 - Авто&масштабування - - - - Auto-Cut Silence - Автовирізання тиші - - - - 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) - (пусто) - - - - Drag video only - Перетягнути лише відео - - - - Drag audio only - Перетягнути лише аудіо - - - - 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. - - - diff --git a/ui/audiomonitor.cpp b/ui/audiomonitor.cpp deleted file mode 100644 index 61e1f07ee..000000000 --- a/ui/audiomonitor.cpp +++ /dev/null @@ -1,122 +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 "audiomonitor.h" - -#include "timeline/sequence.h" -#include "rendering/audio.h" -#include "panels/panels.h" -#include "panels/timeline.h" - -#include -#include -#include - -#define AUDIO_MONITOR_PEAK_HEIGHT 15 -#define AUDIO_MONITOR_GAP 3 - -extern "C" { -#include "libavformat/avformat.h" -} - -AudioMonitor::AudioMonitor(QWidget *parent) : - QWidget(parent), - peaked_(false) -{ - clear_timer.setInterval(500); - connect(&clear_timer, SIGNAL(timeout()), this, SLOT(clear())); -} - -void AudioMonitor::set_value(const QVector &ivalues) { - if (value_lock.tryLock()) { - values = ivalues; - - if (peaked_.size() != values.size()) { - peaked_.resize(values.size()); - peaked_.fill(false); - } - - value_lock.unlock(); - - QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); - QMetaObject::invokeMethod(&clear_timer, "start", Qt::QueuedConnection); - } -} - -void AudioMonitor::clear() { - clear_timer.stop(); - peaked_.fill(false); - values.fill(0.0); - update(); -} - -void AudioMonitor::resizeEvent(QResizeEvent *e) { - gradient = QLinearGradient(QPoint(0, rect().top()), QPoint(0, rect().bottom())); - gradient.setColorAt(0, Qt::red); - gradient.setColorAt(0.25, Qt::yellow); - gradient.setColorAt(1, Qt::green); - QWidget::resizeEvent(e); -} - -void AudioMonitor::mousePressEvent(QMouseEvent *) -{ - peaked_.fill(false); - update(); -} - -void AudioMonitor::paintEvent(QPaintEvent *) { - value_lock.lock(); - if (values.size() > 0) { - QPainter p(this); - int channel_x = AUDIO_MONITOR_GAP; - int channel_count = values.size(); - int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP; - - for (int i=0;i 1.0f) { - peaked_[i] = true; - } - - // We draw an inverted dark shadow over the gradient to represent to are not lit up - // TODO change to decibel representation - float val = 1.0f - qMin(1.0f, values.at(i)); - r.setHeight(qRound(r.height()*val)); - - QRect peak_rect(channel_x, 0, channel_width, AUDIO_MONITOR_PEAK_HEIGHT); - if (peaked_[i]) { - // We're peaked on this channel, so we light up the peak light - p.fillRect(peak_rect, QColor(255, 0, 0)); - } else { - p.fillRect(peak_rect, QColor(64, 0, 0)); - } - - p.fillRect(r, QColor(0, 0, 0, 160)); - - channel_x += channel_width + AUDIO_MONITOR_GAP; - } - } - value_lock.unlock(); -} diff --git a/ui/audiomonitor.h b/ui/audiomonitor.h deleted file mode 100644 index f6a4505c2..000000000 --- a/ui/audiomonitor.h +++ /dev/null @@ -1,122 +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 AUDIOMONITOR_H -#define AUDIOMONITOR_H - -#include -#include -#include - -/** - * @brief The AudioMonitor class - * - * Used to show a visual representation of audio currently playing - */ -class AudioMonitor : public QWidget -{ - Q_OBJECT -public: - /** - * @brief AudioMonitor Constructor - * @param parent - * - * QWidget parent object. - */ - explicit AudioMonitor(QWidget *parent = nullptr); - - /** - * @brief Set the current audio value - * - * The main interface for updating the audio monitor. Using this function will redraw the monitor with the values - * specified. - * - * @param values - * - * An array of doubles between 0.0 and 1.0 to display the amplitude. 0.0 is no audio, 1.0 is full volume. Each array - * entry is a channel and the audio monitor will automatically adjust to the channel count in the array. - */ - void set_value(const QVector &values); - -protected: - /** - * @brief Internal paint event - * - * Paints the audio monitor - */ - virtual void paintEvent(QPaintEvent *) override; - - /** - * @brief Internal resize event handler - * - * Triggers a repaint when the widget is resized. - */ - virtual void resizeEvent(QResizeEvent *) override; - - /** - * @brief Internal mouse press handler - * - * @param event - */ - virtual void mousePressEvent(QMouseEvent *event) override; - -signals: - -public slots: - -private: - /** - * @brief Internal gradient object from red to yellow to green - */ - QLinearGradient gradient; - - /** - * @brief Internal value storage - */ - QVector values; - - /** - * @brief Value mutex - * - * Audio is often processed and sent to this object from other threads. To keep them synchronized, we lock them here. - */ - QMutex value_lock; - - /** - * @brief Internal timer to clear the audio monitor after a certain amount of time - * - * If it doesn't receive any values within a certain amount of time, it's assumed audio is no longer playing and the - * monitor is cleared. - */ - QTimer clear_timer; - - /** - * @brief Internal variable for whether audio played as peaked or not - */ - QVector peaked_; - -private slots: - /** - * @brief Slot to clear the audio monitor - */ - void clear(); -}; - -#endif // AUDIOMONITOR_H diff --git a/ui/blur.cpp b/ui/blur.cpp deleted file mode 100644 index 29052b585..000000000 --- a/ui/blur.cpp +++ /dev/null @@ -1,85 +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 "blur.h" - -void olive::ui::blur(QImage& result, const QRect& rect, int radius, bool alphaOnly) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; - - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); - - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; - - int i1 = 0; - int i2 = 3; - - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } -} diff --git a/ui/blur.h b/ui/blur.h deleted file mode 100644 index 461f67525..000000000 --- a/ui/blur.h +++ /dev/null @@ -1,52 +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 BLUR_H -#define BLUR_H - -#include -#include - -namespace olive { - namespace ui { - /** - * @brief Convenience function for blurring a QImage - * - * @param result - * - * QImage to blur - * - * @param rect - * - * The rectangle of the QImage to blur. Use QImage::rect() to blur the entire image. - * - * @param radius - * - * The blur radius - how much to blur the image. - * - * @param alphaOnly - * - * True if only the alpha channel should be blurred rather than the entire RGBA space. - */ - void blur(QImage& result, const QRect& rect, int radius, bool alphaOnly); - } -} - -#endif // BLUR_H diff --git a/ui/checkboxex.cpp b/ui/checkboxex.cpp deleted file mode 100644 index fefb88668..000000000 --- a/ui/checkboxex.cpp +++ /dev/null @@ -1,33 +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 "checkboxex.h" - -#include "undo/undostack.h" -#include "undo/undo.h" - -CheckboxEx::CheckboxEx(QWidget* parent) : QCheckBox(parent) { -// connect(this, SIGNAL(clicked(bool)), this, SLOT(checkbox_command())); -} - -void CheckboxEx::checkbox_command() { - CheckboxCommand* c = new CheckboxCommand(this); - olive::UndoStack.push(c); -} diff --git a/ui/checkboxex.h b/ui/checkboxex.h deleted file mode 100644 index a7ebb054f..000000000 --- a/ui/checkboxex.h +++ /dev/null @@ -1,35 +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 CHECKBOXEX_H -#define CHECKBOXEX_H - -#include - -class CheckboxEx : public QCheckBox -{ - Q_OBJECT -public: - CheckboxEx(QWidget* parent = 0); -private slots: - void checkbox_command(); -}; - -#endif // CHECKBOXEX_H diff --git a/ui/clickablelabel.cpp b/ui/clickablelabel.cpp deleted file mode 100644 index fd888d46b..000000000 --- a/ui/clickablelabel.cpp +++ /dev/null @@ -1,38 +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 "clickablelabel.h" - -ClickableLabel::ClickableLabel(QWidget *parent, Qt::WindowFlags f) : - QLabel(parent, f) -{} - -ClickableLabel::ClickableLabel(const QString &text, QWidget *parent, Qt::WindowFlags f) : - QLabel(text, parent, f) -{} - -void ClickableLabel::mousePressEvent(QMouseEvent *) { - emit clicked(); -} - -void ClickableLabel::mouseDoubleClickEvent(QMouseEvent *ev) -{ - emit double_clicked(); -} diff --git a/ui/clickablelabel.h b/ui/clickablelabel.h deleted file mode 100644 index dc2c8bb3f..000000000 --- a/ui/clickablelabel.h +++ /dev/null @@ -1,43 +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 CLICKABLELABEL_H -#define CLICKABLELABEL_H - -#include - -/** - * @brief The ClickableLabel class - * - * Simple QLabel-derived class that emits a clicked() signal when the widget receives a mouse press event. - */ -class ClickableLabel : public QLabel { - Q_OBJECT -public: - ClickableLabel(QWidget * parent = nullptr, Qt::WindowFlags f = nullptr); - ClickableLabel(const QString & text, QWidget * parent = nullptr, Qt::WindowFlags f = nullptr); - virtual void mousePressEvent(QMouseEvent *ev) override; - virtual void mouseDoubleClickEvent(QMouseEvent *ev) override; -signals: - void clicked(); - void double_clicked(); -}; - -#endif // CLICKABLELABEL_H diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp deleted file mode 100644 index 0d32b4835..000000000 --- a/ui/collapsiblewidget.cpp +++ /dev/null @@ -1,198 +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 "collapsiblewidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ui/icons.h" -#include "global/debug.h" - -CollapsibleWidget::CollapsibleWidget(QWidget* parent) : - QWidget(parent), - contents(nullptr) -{ - layout = new QVBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(0); - - title_bar = new CollapsibleWidgetHeader(this); - title_bar->setFocusPolicy(Qt::ClickFocus); - title_bar->setAutoFillBackground(true); - title_bar_layout = new QHBoxLayout(title_bar); - title_bar_layout->setMargin(5); - enabled_check = new QCheckBox(title_bar); - enabled_check->setChecked(true); - header = new QLabel(title_bar); - collapse_button = new QPushButton(title_bar); - collapse_button->setIconSize(collapse_button->iconSize()*0.5); - collapse_button->setFlat(true); - SetTitle(tr("")); - title_bar_layout->addWidget(collapse_button); - title_bar_layout->addWidget(enabled_check); - title_bar_layout->addWidget(header); - title_bar_layout->addStretch(); - layout->addWidget(title_bar); - - connect(title_bar, SIGNAL(select()), this, SLOT(Selected())); - - set_button_icon(true); -} - -void CollapsibleWidget::Selected() { - emit deselect_others(this); -} - -bool CollapsibleWidget::IsFocused() { - if (hasFocus()) return true; - return title_bar->hasFocus(); -} - -bool CollapsibleWidget::IsExpanded() { - return contents->isVisible(); -} - -void CollapsibleWidget::SetExpanded(bool s) -{ - contents->setVisible(s); - set_button_icon(s); - emit visibleChanged(s); -} - -bool CollapsibleWidget::IsSelected() -{ - return title_bar->IsSelected(); -} - -void CollapsibleWidget::Deselect() -{ - title_bar->SetSelected(false); -} - -void CollapsibleWidget::SetSelectable(bool s) -{ - title_bar->SetSelectable(s); -} - -void CollapsibleWidget::set_button_icon(bool open) { - collapse_button->setIcon(open ? olive::icon::DownArrow : olive::icon::RightArrow); -} - -void CollapsibleWidget::SetContents(QWidget* c) { - bool existing = (contents != nullptr); - contents = c; - if (!existing) { - layout->addWidget(contents); - connect(collapse_button, SIGNAL(clicked()), this, SLOT(on_visible_change())); - } -} - -QString CollapsibleWidget::Title() -{ - return header->text(); -} - -void CollapsibleWidget::SetTitle(const QString &s) { - header->setText(s); -} - -void CollapsibleWidget::on_visible_change() { - SetExpanded(!IsExpanded()); -} - -CollapsibleWidgetHeader::CollapsibleWidgetHeader(QWidget* parent) : - QWidget(parent), - selected_(false), - selectable_(true) -{ - setContextMenuPolicy(Qt::CustomContextMenu); -} - -bool CollapsibleWidgetHeader::IsSelected() -{ - return selected_; -} - -void CollapsibleWidgetHeader::SetSelected(bool s, bool deselect_others) -{ - selected_ = s; - - if (s) { - QPalette p = palette(); - p.setColor(QPalette::Background, QColor(255, 255, 255, 64)); - setPalette(p); - } else { - setPalette(qApp->palette()); - } - - if (deselect_others) { - emit select(); - } -} - -void CollapsibleWidgetHeader::SetSelectable(bool s) -{ - selectable_ = s; - - if (!selectable_ && selected_) { - SetSelected(false); - } -} - -bool CollapsibleWidgetHeader::event(QEvent *event) -{ - if (!selectable_ - && (event->type() == QEvent::MouseButtonPress - || event->type() == QEvent::MouseButtonRelease - || event->type() == QEvent::MouseMove - || event->type() == QEvent::MouseButtonDblClick) - && QApplication::sendEvent(parent(), event)) { - return true; - } - return QWidget::event(event); -} - -void CollapsibleWidgetHeader::mousePressEvent(QMouseEvent* event) { - if (selected_) { - if (event->modifiers() & Qt::ShiftModifier) { - SetSelected(false); - } - } else { - SetSelected(true, !(event->modifiers() & Qt::ShiftModifier)); - } -} - -void CollapsibleWidgetHeader::paintEvent(QPaintEvent *event) { - QWidget::paintEvent(event); - QPainter p(this); - p.setPen(Qt::white); - int line_y = height() - 1; - p.drawLine(0, line_y, width(), line_y); -} diff --git a/ui/collapsiblewidget.h b/ui/collapsiblewidget.h deleted file mode 100644 index 514c3c63e..000000000 --- a/ui/collapsiblewidget.h +++ /dev/null @@ -1,91 +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 COLLAPSIBLEWIDGET_H -#define COLLAPSIBLEWIDGET_H - -#include -#include -#include -#include -#include -#include -#include -#include - -class CollapsibleWidgetHeader : public QWidget { - Q_OBJECT -public: - CollapsibleWidgetHeader(QWidget* parent = nullptr); - - bool IsSelected(); - void SetSelected(bool s, bool deselect_others = false); - - void SetSelectable(bool s); -protected: - virtual bool event(QEvent *event) override; - virtual void mousePressEvent(QMouseEvent* event) override; - virtual void paintEvent(QPaintEvent *event) override; -signals: - void select(); -private: - bool selected_; - bool selectable_; -}; - -class CollapsibleWidget : public QWidget -{ - Q_OBJECT -public: - CollapsibleWidget(QWidget* parent = nullptr); - void SetContents(QWidget* c); - QString Title(); - void SetTitle(const QString &); - bool IsFocused(); - bool IsExpanded(); - void SetExpanded(bool s); - - bool IsSelected(); - void Deselect(); - void SetSelectable(bool s); -protected: - QCheckBox* enabled_check; - CollapsibleWidgetHeader* title_bar; - QWidget* contents; -private: - QLabel* header; - QVBoxLayout* layout; - QPushButton* collapse_button; - QFrame* line; - QHBoxLayout* title_bar_layout; - void set_button_icon(bool open); - -signals: - void deselect_others(QWidget*); - void visibleChanged(bool); - -private slots: - void on_visible_change(); - -public slots: - void Selected(); -}; - -#endif // COLLAPSIBLEWIDGET_H diff --git a/ui/colorbutton.cpp b/ui/colorbutton.cpp deleted file mode 100644 index 39eba687c..000000000 --- a/ui/colorbutton.cpp +++ /dev/null @@ -1,53 +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 "colorbutton.h" - -#include - -ColorButton::ColorButton(QWidget *parent) - : QPushButton(parent), color(Qt::white) { - set_button_color(); - connect(this, SIGNAL(clicked(bool)), this, SLOT(open_dialog())); -} - -QColor ColorButton::get_color() { - return color; -} - -void ColorButton::set_color(QColor c) { - color = c; - set_button_color(); -} - -void ColorButton::set_button_color() { - QPalette pal = palette(); - pal.setColor(QPalette::Button, color); - setPalette(pal); -} - -void ColorButton::open_dialog() { - QColor new_color = QColorDialog::getColor(color, nullptr, tr("Set Color")); - if (new_color.isValid() && color != new_color) { - set_color(new_color); - set_button_color(); - emit color_changed(color); - } -} diff --git a/ui/colorbutton.h b/ui/colorbutton.h deleted file mode 100644 index 2359cbf9f..000000000 --- a/ui/colorbutton.h +++ /dev/null @@ -1,43 +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 COLORBUTTON_H -#define COLORBUTTON_H - -#include -#include -#include - -class ColorButton : public QPushButton { - Q_OBJECT -public: - ColorButton(QWidget* parent = nullptr); - QColor get_color(); - void set_color(QColor c); -private: - QColor color; - void set_button_color(); -signals: - void color_changed(const QColor& c); -private slots: - void open_dialog(); -}; - -#endif // COLORBUTTON_H diff --git a/ui/columnedgridlayout.cpp b/ui/columnedgridlayout.cpp deleted file mode 100644 index 6404e6c96..000000000 --- a/ui/columnedgridlayout.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "columnedgridlayout.h" - -ColumnedGridLayout::ColumnedGridLayout(QWidget* parent, - int maximum_columns) : - QGridLayout (parent), - maximum_columns_(maximum_columns) -{ -} - -void ColumnedGridLayout::Add(QWidget *widget) -{ - if (maximum_columns_ > 0) { - - int row = count() / maximum_columns_; - int column = count() % maximum_columns_; - - addWidget(widget, row, column); - - } else { - - addWidget(widget); - - } -} - -int ColumnedGridLayout::MaximumColumns() const -{ - return maximum_columns_; -} - -void ColumnedGridLayout::SetMaximumColumns(int maximum_columns) -{ - maximum_columns_ = maximum_columns; -} diff --git a/ui/columnedgridlayout.h b/ui/columnedgridlayout.h deleted file mode 100644 index d62eaa6d7..000000000 --- a/ui/columnedgridlayout.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef COLUMNEDGRIDLAYOUT_H -#define COLUMNEDGRIDLAYOUT_H - -#include - -/** - * @brief The ColumnedGridLayout class - * - * A simple derivative of QGridLayout that provides a automatic row/column layout based on a specified maximum - * column count. - */ -class ColumnedGridLayout : public QGridLayout -{ - Q_OBJECT -public: - ColumnedGridLayout(QWidget* parent = nullptr, - int maximum_columns = 0); - - void Add(QWidget* widget); - int MaximumColumns() const; - void SetMaximumColumns(int maximum_columns); - -private: - int maximum_columns_; -}; - -#endif // COLUMNEDGRIDLAYOUT_H diff --git a/ui/comboboxex.cpp b/ui/comboboxex.cpp deleted file mode 100644 index 8cb994129..000000000 --- a/ui/comboboxex.cpp +++ /dev/null @@ -1,42 +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 "comboboxex.h" - -#include - -ComboBoxEx::ComboBoxEx(QWidget *parent) : - QComboBox(parent) -{ -} - -void ComboBoxEx::setScrollingEnabled(bool b) -{ - scrolling_enabled_ = b; -} - -void ComboBoxEx::wheelEvent(QWheelEvent *e) -{ - if (scrolling_enabled_) { - QComboBox::wheelEvent(e); - } else { - e->ignore(); - } -} diff --git a/ui/comboboxex.h b/ui/comboboxex.h deleted file mode 100644 index f045f18ef..000000000 --- a/ui/comboboxex.h +++ /dev/null @@ -1,37 +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 COMBOBOXEX_H -#define COMBOBOXEX_H - -#include - -class ComboBoxEx : public QComboBox { - Q_OBJECT -public: - ComboBoxEx(QWidget* parent = nullptr); - void setScrollingEnabled(bool b); -protected: - virtual void wheelEvent(QWheelEvent* e) override; -private: - bool scrolling_enabled_; -}; - -#endif // COMBOBOXEX_H diff --git a/ui/cursors.cpp b/ui/cursors.cpp deleted file mode 100644 index 977c52c63..000000000 --- a/ui/cursors.cpp +++ /dev/null @@ -1,69 +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 "cursors.h" - -#include -#include -#include -#include -#include -#include -#include - -QCursor olive::cursor::LeftTrim; -QCursor olive::cursor::RightTrim; -QCursor olive::cursor::LeftRipple; -QCursor olive::cursor::RightRipple; -QCursor olive::cursor::Slip; -QCursor olive::cursor::Razor; - -const int cursor_size = 24; - -QCursor load_cursor(const QString& file, int hotX = -1, int hotY = -1, bool right_aligned = false){ - // load specified file into a pixmap - QSvgRenderer renderer(file); - - int cursor_size_dpiaware = cursor_size * QApplication::desktop()->devicePixelRatio(); - QPixmap pixmap(cursor_size_dpiaware, cursor_size_dpiaware); - pixmap.fill(Qt::transparent); - - QPainter painter(&pixmap); - renderer.render(&painter, pixmap.rect()); - - // set cursor's horizontal hotspot - if (right_aligned) { - hotX = pixmap.width() - hotX; - } - - // return cursor - return QCursor(pixmap, hotX, hotY); -} - -void olive::cursor::Initialize(){ - qInfo() << "Initializing custom cursors"; - olive::cursor::LeftTrim = load_cursor(":/cursors/1_left.svg"); - olive::cursor::RightTrim = load_cursor(":/cursors/1_right.svg"); - olive::cursor::LeftRipple = load_cursor(":/cursors/3_left.svg"); - olive::cursor::RightRipple = load_cursor(":/cursors/3_right.svg"); - olive::cursor::Slip = load_cursor(":/cursors/4.svg"); - olive::cursor::Razor = load_cursor(":/cursors/5.svg"); - qInfo() << "Finished initializing custom cursors"; -} diff --git a/ui/cursors.h b/ui/cursors.h deleted file mode 100644 index 1c6a3a1cc..000000000 --- a/ui/cursors.h +++ /dev/null @@ -1,39 +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 CURSORS_H -#define CURSORS_H - -#include - -namespace olive{ - namespace cursor { - extern QCursor LeftTrim; - extern QCursor RightTrim; - extern QCursor LeftRipple; - extern QCursor RightRipple; - extern QCursor Slip; - extern QCursor Razor; - - void Initialize(); - } -} - -#endif // CURSORS_H diff --git a/ui/effectui.cpp b/ui/effectui.cpp deleted file mode 100644 index 1f72728ee..000000000 --- a/ui/effectui.cpp +++ /dev/null @@ -1,358 +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 "effectui.h" - -#include - -#include "timeline/clip.h" -#include "ui/menuhelper.h" -#include "ui/keyframenavigator.h" -#include "ui/clickablelabel.h" -#include "ui/menu.h" -#include "panels/panels.h" - -EffectUI::EffectUI(OldEffectNode* e) : - effect_(e) -{ - Q_ASSERT(e != nullptr); - - QString effect_name; - - // If this effect is actually a transition - if (e->type() == EFFECT_TYPE_TRANSITION) { - - Transition* t = static_cast(e); - - // Since effects can have two clip attachments, find out which one is selected - Clip* selected_clip = t->parent_clip; - bool both_selected = false; - - // Check if this is a shared transition - if (t->secondary_clip != nullptr) { - - // Check which clips are selected - if (t->secondary_clip->IsSelected()) { - - selected_clip = t->secondary_clip; - - if (t->parent_clip->IsSelected()) { - // Both clips are selected - both_selected = true; - } - - } else if (!t->parent_clip->IsSelected()) { - - // Neither are selected, but the naming scheme (no "opening" or "closing" modifier) will be the same - both_selected = true; - - } - - } - - // See if the transition is the clip's opening or closing transition and label it accordingly - if (both_selected) { - effect_name = t->name(); - } else if (selected_clip->opening_transition.get() == t) { - effect_name = tr("%1 (Opening)").arg(t->name()); - } else { - effect_name = tr("%1 (Closing)").arg(t->name()); - } - - } else { - - // Otherwise just set the title normally - effect_name = e->name(); - - } - - SetTitle(effect_name); - - QWidget* ui = new QWidget(this); - ui->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - SetContents(ui); - - title_bar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - - SetExpanded(e->IsExpanded()); - connect(this, SIGNAL(visibleChanged(bool)), e, SLOT(SetExpanded(bool))); - - layout_ = new QGridLayout(ui); - layout_->setSpacing(4); - - connect(title_bar, - SIGNAL(customContextMenuRequested(const QPoint&)), - this, - SLOT(show_context_menu(const QPoint&))); - - widgets_.resize(e->ParameterCount()); - keyframe_navigators_.resize(e->ParameterCount()); - - for (int i=0;iParameterCount();i++) { - NodeIO* row = e->Parameter(i); - - ClickableLabel* row_label = new ClickableLabel(row->name()); - connect(row_label, SIGNAL(clicked()), row, SLOT(FocusRow())); - - labels_.append(row_label); - - if (row->IsNodeOutput()) { - - row_label->setAlignment(Qt::AlignRight); - layout_->addWidget(row_label, i, 2); - - } else { - - layout_->addWidget(row_label, i, 0); - - widgets_[i].resize(row->FieldCount()); - - QGridLayout* field_layout = new QGridLayout(); - for (int j=0;jFieldCount();j++) { - EffectField* field = row->Field(j); - - QWidget* widget = field->CreateWidget(); - - widgets_[i][j] = widget; - - field_layout->addWidget(widget, 0, j); - } - layout_->addLayout(field_layout, i, 1); - - KeyframeNavigator* nav; - - if (row->IsKeyframable()) { - - nav = new KeyframeNavigator(); - - nav->enable_keyframes(row->IsKeyframing()); - - AttachKeyframeNavigationToRow(row, nav); - - layout_->addWidget(nav, i, 2); - - } else { - - nav = nullptr; - - } - - keyframe_navigators_[i] = nav; - - } - } - - enabled_check->setChecked(e->IsEnabled()); - connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(SetEnabled(bool))); - connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(FieldChanged())); -} - -void EffectUI::AddAdditionalEffect(OldEffectNode *e) -{ - // Ensure this is the same kind of effect and will be fully compatible - Q_ASSERT(e->id() == effect_->id()); - - // Add 'multiple' modifier to header label (but only once) - if (additional_effects_.isEmpty()) { - QString new_title = tr("%1 (multiple)").arg(Title()); - - SetTitle(new_title); - } - - // Add effect to list - additional_effects_.append(e); - - // Attach this UI's widgets to the additional effect - for (int i=0;iParameterCount();i++) { - - NodeIO* row = effect_->Parameter(i); - - // Attach existing keyframe navigator to this effect's row - AttachKeyframeNavigationToRow(e->Parameter(i), keyframe_navigators_.at(i)); - - for (int j=0;jFieldCount();j++) { - - // Attach existing field widget to this effect's field - e->Parameter(i)->Field(j)->CreateWidget(Widget(i, j)); - - } - - } -} - -OldEffectNode *EffectUI::GetEffect() -{ - return effect_; -} - -int EffectUI::GetRowY(int row, QWidget* mapToWidget) { - - // Currently to get a Y value in the context of `mapToWidget`, we use `panel_effect_controls` as the base. Mapping - // to global doesn't work for some reason, so this is the best reference point we have. - - QLabel* row_label = labels_.at(row); - - int mapped_coord; - if (mapToWidget == nullptr) { - mapped_coord = contents->pos().y(); - } else { - // FIXME Problematic now that EffectUIs are used outside of EffectControls - mapped_coord = mapToWidget->mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y(); - mapped_coord -= title_bar->height(); - } - - // Get center point of label (label->rect()->center()->y() - instead of y()+height/2 - produces an inaccurate result) - return row_label->y() - + row_label->height() / 2 - + mapped_coord; -} - -void EffectUI::UpdateFromEffect() -{ - OldEffectNode* effect = GetEffect(); - - for (int j=0;jParameterCount();j++) { - - NodeIO* row = effect->Parameter(j); - - for (int k=0;kFieldCount();k++) { - EffectField* field = row->Field(k); - - // Check if this UI object is attached to one effect or many - if (additional_effects_.isEmpty()) { - - field->UpdateWidgetValue(Widget(j, k), effect->Now()); - - } else { - - bool same_value = true; - - for (int i=0;i 0 ? additional_effects_.at(i-1)->Parameter(j)->Field(k) : field; - EffectField* additional_field = additional_effects_.at(i)->Parameter(j)->Field(k); - - if (additional_field->GetValueAt(additional_effects_.at(i)->Now()) - != previous_field->GetValueAt(additional_effects_.at(i)->Now())) { - same_value = false; - break; - } - } - - if (same_value) { - field->UpdateWidgetValue(Widget(j, k), effect->Now()); - } else { - field->UpdateWidgetValue(Widget(j, k), qSNaN()); - } - - } - } - } -} - -bool EffectUI::IsAttachedToClip(Clip *c) -{ - if (GetEffect()->parent_clip == c) { - return true; - } - - for (int i=0;iparent_clip == c) { - return true; - } - } - - return false; -} - -QWidget *EffectUI::Widget(int row, int field) -{ - return widgets_.at(row).at(field); -} - -void EffectUI::AttachKeyframeNavigationToRow(NodeIO *row, KeyframeNavigator *nav) -{ - if (nav == nullptr) { - return; - } - - connect(nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); - connect(nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); - connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); - connect(nav, SIGNAL(keyframe_enabled_changed(bool)), row, SLOT(SetKeyframingEnabled(bool))); - connect(nav, SIGNAL(clicked()), row, SLOT(FocusRow())); - connect(row, SIGNAL(KeyframingSetChanged(bool)), nav, SLOT(enable_keyframes(bool))); -} - -void EffectUI::show_context_menu(const QPoint& pos) { - if (effect_->type() == EFFECT_TYPE_EFFECT) { - Menu menu; - - Clip* c = effect_->parent_clip; - - int index = c->IndexOfEffect(effect_); - - QAction* cut_action = menu.addAction(tr("Cu&t")); - connect(cut_action, SIGNAL(triggered(bool)), this, SIGNAL(CutRequested())); - - QAction* copy_action = menu.addAction(tr("&Copy")); - connect(copy_action, SIGNAL(triggered(bool)), this, SIGNAL(CopyRequested())); - - olive::MenuHelper.create_effect_paste_action(&menu); - - menu.addSeparator(); - - QAction* move_up_action = nullptr; - QAction* move_down_action = nullptr; - - if (index > 0) { - move_up_action = menu.addAction(tr("Move &Up"), GetEffect(), SLOT(move_up())); - } - - if (index < c->effects.size() - 1) { - move_down_action = menu.addAction(tr("Move &Down"), GetEffect(), SLOT(move_down())); - } - - menu.addSeparator(); - - QAction* delete_action = menu.addAction(tr("D&elete"), GetEffect(), SLOT(delete_self())); - - // Loop through additional effects and link these too - for (int i=0;imapToGlobal(pos)); - } -} diff --git a/ui/effectui.h b/ui/effectui.h deleted file mode 100644 index 942966de4..000000000 --- a/ui/effectui.h +++ /dev/null @@ -1,223 +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 EFFECTUI_H -#define EFFECTUI_H - -#include "collapsiblewidget.h" -#include "nodes/oldeffectnode.h" -#include "ui/nodeui.h" -#include "ui/keyframenavigator.h" - -/** - * @brief The EffectUI class - * - * EffectUI is a complete QWidget-based representation of an Effect that can be added to any Qt layout. It overrides - * CollapsibleWidget (meaning the Effect can be collapsed to just a titlebar to save space). The titlebar is - * automatically set to the Effect's name and the contents are composed of a grid layout (QGridLayout) corresponding - * to the Effect's EffectRow and EffectField children. - * - * Many EffectUIs can be created from a single Effect, and many Effects can be attached to a single EffectUI (provided - * the Effects are all the same type). Neither gains ownership of each other and deleting an EffectUI without any other - * work is perfectly safe (deleting an Effect with an open EffectUI however, is not). - */ -class EffectUI : public CollapsibleWidget { - Q_OBJECT -public: - /** - * @brief EffectUI Constructor - * - * Creates a QWidget-based UI representation of an Effect. - * - * @param e - * - * The Effect to make a UI of. It must be a valid object. - */ - EffectUI(OldEffectNode* e); - - /** - * @brief Attach additional effects to this UI - * - * Olive allows users to modify several effects (of the same type) with one UI representation. To do this, you can - * add any amount of extra Effect objects using this function and the UI will attach all of its UI functions to that - * Effect as well without creating any new QWidgets. - * - * @param e - * - * The Effect to add to this UI object. - */ - void AddAdditionalEffect(OldEffectNode* e); - - /** - * @brief Get the primary Effect that this UI object was created for - * - * @return - * - * The Effect object passed to the constructor when creating this EffectUI. - */ - OldEffectNode* GetEffect(); - - /** - * @brief Get the Y position of a given row - * - * Retrieve the on-screen Y position of the attached Effect's EffectRow at a given index. This is primarily used for - * displaying UI elements that align with the the row's on-screen widgets (e.g. keyframes in the EffectControls - * panel). - * - * The Y value provided is specifically the center point of the row's name label. It gets mapped to a provided - * QWidget object so it can be used locally by that QWidget without further modification. - * - * @param row - * - * The index of the EffectRow to retrieve the Y position of. - * - * @param mapToWidget - * - * The widget to map the Y value to. - * - * @return - * - * The row's Y position. - */ - int GetRowY(int row, QWidget *mapToWidget = nullptr); - - /** - * @brief Update widgets with the current Effect's values. - * - * When the Timeline playhead moves, the current values in the Effect might change if its fields are keyframed. - * In order to visually update these values on the UI, this function should be called. It will loop through all - * fields of all attached effects and update them to the value at the current Timeline playhead. - * - * Currently this function is called by update_ui() which is also responsible for updating other parts of the UI - * like the Timeline and Viewer so they all get updated together. - */ - void UpdateFromEffect(); - - /** - * @brief Check if a given Clip has an Effect referenced by this EffectUI - * - * Olive allows users to modify several effects (of the same type) with one UI representation. The behavior is if - * multiple clips are selected that have effects of the same type, all those Effects can be modified by the same - * EffectUI object. However this behavior is undesirable if a single Clip has more than one of the same type of Effect - * (e.g. two or more blurs). In this scenario, the user will most likely expect two separate UI objects for each of - * these effects individually, rather than consolidating them into one UI object. - * - * To address this, EffectControls will check this function to determine if this EffectUI already references - * an Effect of this type from this Clip. If it does, it's assumed a new EffectUI should be made rather than - * consolidating that Effect into the same EffectUI. - * - * @param c - * - * The Clip to determine whether an Effect of this type is already referenced by this EffectUI. - * - * @return - * - * True is an Effect from this Clip is already attached to this EffectUI. - */ - bool IsAttachedToClip(Clip* c); - -protected: - -signals: - /** - * @brief Cut signal - * - * Emitted when the user selects Cut from the right-click context menu. - */ - void CutRequested(); - - /** - * @brief Copy signal - * - * Emitted when the user selects Copy from the right-click context menu. - */ - void CopyRequested(); -private: - /** - * @brief Retrieve the QWidget corresponding a specific EffectField - * - * Convenience function equivalent to widgets_.at(row).at(field). - * - * @param row - * - * EffectRow index to retrieve field QWidget from - * - * @param field - * - * EffectField index to retrieve QWidget from - * - * @return - * - * The QWidget at this row and field index. - */ - QWidget* Widget(int row, int field); - - /** - * @brief Internal reference to the Effect this object was constructed around. - */ - OldEffectNode* effect_; - - /** - * @brief Internal array of additional Effect objects attached to this UI. - */ - QVector additional_effects_; - - /** - * @brief Layout for UI widgets - */ - QGridLayout* layout_; - - /** - * @brief Grid array of QWidgets corresponding to the Effect's rows and fields - */ - QVector< QVector > widgets_; - - /** - * @brief Array of QLabel objects corresponding to each row's name(). - */ - QVector labels_; - - /** - * @brief Array of KeyframeNavigator objects corresponding to each row. - */ - QVector keyframe_navigators_; - - /** - * @brief Attach a KeyframeNavigator object to an EffectRow. - * - * Internal function for connecting a KeyframeNavigator UI object to an EffectRow. - * - * @param row - * - * The EffectRow object. - * - * @param nav - * - * The KeyframeNavigator object. - */ - void AttachKeyframeNavigationToRow(NodeIO* row, KeyframeNavigator* nav); -private slots: - /** - * @brief Slot for titlebar's right-click signal to show a context menu for extra Effect functions. - */ - void show_context_menu(const QPoint&); -}; - -#endif // EFFECTUI_H diff --git a/ui/embeddedfilechooser.cpp b/ui/embeddedfilechooser.cpp deleted file mode 100644 index 582f213e0..000000000 --- a/ui/embeddedfilechooser.cpp +++ /dev/null @@ -1,75 +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 "embeddedfilechooser.h" - -#include -#include -#include -#include -#include - -EmbeddedFileChooser::EmbeddedFileChooser(QWidget* parent) : QWidget(parent) { - QHBoxLayout* layout = new QHBoxLayout(this); - layout->setMargin(0); - file_label = new QLabel(this); - update_label(); - layout->addWidget(file_label); - QPushButton* browse_button = new QPushButton("...", this); - browse_button->setFixedWidth(25); - layout->addWidget(browse_button); - connect(browse_button, SIGNAL(clicked(bool)), this, SLOT(browse())); -} - -const QString &EmbeddedFileChooser::getFilename() { - return filename; -} - -void EmbeddedFileChooser::setFilename(const QString &s) { - filename = s; - update_label(); - emit changed(filename); -} - -void EmbeddedFileChooser::update_label() { - QString l = "" + tr("File:") + " "; - if (filename.isEmpty()) { - l += "(none)"; - } else { - bool file_exists = QFileInfo::exists(filename); - if (!file_exists) l += ""; - QString short_fn = filename.mid(filename.lastIndexOf('/')+1); - if (short_fn.size() > 20) { - l += "..." + short_fn.right(20); - } else { - l += short_fn; - } - if (!file_exists) l += ""; - } - l += ""; - file_label->setText(l); -} - -void EmbeddedFileChooser::browse() { - QString fn = QFileDialog::getOpenFileName(this); - if (!fn.isEmpty()) { - setFilename(fn); - } -} diff --git a/ui/embeddedfilechooser.h b/ui/embeddedfilechooser.h deleted file mode 100644 index 28397cc12..000000000 --- a/ui/embeddedfilechooser.h +++ /dev/null @@ -1,45 +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 EMBEDDEDFILECHOOSER_H -#define EMBEDDEDFILECHOOSER_H - -#include - -class QLabel; - -class EmbeddedFileChooser : public QWidget { - Q_OBJECT -public: - EmbeddedFileChooser(QWidget* parent = 0); - - const QString& getFilename(); - void setFilename(const QString& s); -signals: - void changed(const QString& s); -private: - QLabel* file_label; - QString filename; - void update_label(); -private slots: - void browse(); -}; - -#endif // EMBEDDEDFILECHOOSER_H diff --git a/ui/flowlayout.cpp b/ui/flowlayout.cpp deleted file mode 100644 index 0dd3a1f60..000000000 --- a/ui/flowlayout.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include "flowlayout.h" -FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) - : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) -{ - setContentsMargins(margin, margin, margin, margin); -} - -FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) - : m_hSpace(hSpacing), m_vSpace(vSpacing) -{ - setContentsMargins(margin, margin, margin, margin); -} - -FlowLayout::~FlowLayout() -{ - QLayoutItem *item; - while ((item = takeAt(0))) - delete item; -} - -void FlowLayout::addItem(QLayoutItem *item) -{ - itemList.append(item); -} - -int FlowLayout::horizontalSpacing() const -{ - if (m_hSpace >= 0) { - return m_hSpace; - } else { - return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); - } -} - -int FlowLayout::verticalSpacing() const -{ - if (m_vSpace >= 0) { - return m_vSpace; - } else { - return smartSpacing(QStyle::PM_LayoutVerticalSpacing); - } -} - -int FlowLayout::count() const -{ - return itemList.size(); -} - -QLayoutItem *FlowLayout::itemAt(int index) const -{ - return itemList.value(index); -} - -QLayoutItem *FlowLayout::takeAt(int index) -{ - if (index >= 0 && index < itemList.size()) - return itemList.takeAt(index); - else - return 0; -} - -Qt::Orientations FlowLayout::expandingDirections() const -{ - return 0; -} - -bool FlowLayout::hasHeightForWidth() const -{ - return true; -} - -int FlowLayout::heightForWidth(int width) const -{ - int height = doLayout(QRect(0, 0, width, 0), true); - return height; -} - -void FlowLayout::setGeometry(const QRect &rect) -{ - QLayout::setGeometry(rect); - doLayout(rect, false); -} - -QSize FlowLayout::sizeHint() const -{ - return minimumSize(); -} - -QSize FlowLayout::minimumSize() const -{ - QSize size; - QLayoutItem *item; - foreach (item, itemList) - size = size.expandedTo(item->minimumSize()); - - size += QSize(2*margin(), 2*margin()); - return size; -} - -int FlowLayout::doLayout(const QRect &rect, bool testOnly) const -{ - int left, top, right, bottom; - getContentsMargins(&left, &top, &right, &bottom); - QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); - int x = effectiveRect.x(); - int y = effectiveRect.y(); - int lineHeight = 0; - - QLayoutItem *item; - foreach (item, itemList) { - QWidget *wid = item->widget(); - int spaceX = horizontalSpacing(); - if (spaceX == -1) - spaceX = wid->style()->layoutSpacing( - QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); - int spaceY = verticalSpacing(); - if (spaceY == -1) - spaceY = wid->style()->layoutSpacing( - QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); - int nextX = x + item->sizeHint().width() + spaceX; - if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { - x = effectiveRect.x(); - y = y + lineHeight + spaceY; - nextX = x + item->sizeHint().width() + spaceX; - lineHeight = 0; - } - - if (!testOnly) - item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); - - x = nextX; - lineHeight = qMax(lineHeight, item->sizeHint().height()); - } - return y + lineHeight - rect.y() + bottom; -} -int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const -{ - QObject *parent = this->parent(); - if (!parent) { - return -1; - } else if (parent->isWidgetType()) { - QWidget *pw = static_cast(parent); - return pw->style()->pixelMetric(pm, 0, pw); - } else { - return static_cast(parent)->spacing(); - } -} diff --git a/ui/flowlayout.h b/ui/flowlayout.h deleted file mode 100644 index 72f5282aa..000000000 --- a/ui/flowlayout.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#ifndef FLOWLAYOUT_H -#define FLOWLAYOUT_H - -#include -#include -#include -class FlowLayout : public QLayout -{ -public: - explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); - explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); - ~FlowLayout(); - - void addItem(QLayoutItem *item) override; - int horizontalSpacing() const; - int verticalSpacing() const; - Qt::Orientations expandingDirections() const override; - bool hasHeightForWidth() const override; - int heightForWidth(int) const override; - int count() const override; - QLayoutItem *itemAt(int index) const override; - QSize minimumSize() const override; - void setGeometry(const QRect &rect) override; - QSize sizeHint() const override; - QLayoutItem *takeAt(int index) override; - -private: - int doLayout(const QRect &rect, bool testOnly) const; - int smartSpacing(QStyle::PixelMetric pm) const; - - QList itemList; - int m_hSpace; - int m_vSpace; -}; - -#endif // FLOWLAYOUT_H diff --git a/ui/focusfilter.cpp b/ui/focusfilter.cpp deleted file mode 100644 index e890178ce..000000000 --- a/ui/focusfilter.cpp +++ /dev/null @@ -1,279 +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 "focusfilter.h" - -#include "panels/panels.h" -#include "timeline/sequence.h" -#include "ui/timelineheader.h" - -FocusFilter olive::FocusFilter; - -FocusFilter::FocusFilter() {} - -void FocusFilter::go_to_in() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->go_to_in(); - } else { - panel_sequence_viewer->go_to_in(); - } -} - -void FocusFilter::go_to_out() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->go_to_out(); - } else { - panel_sequence_viewer->go_to_out(); - } -} - -void FocusFilter::go_to_start() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->go_to_start(); - } else { - panel_sequence_viewer->go_to_start(); - } -} - -void FocusFilter::prev_frame() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->previous_frame(); - } else { - panel_sequence_viewer->previous_frame(); - } -} - -void FocusFilter::play_in_to_out() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->play(true); - } else { - panel_sequence_viewer->play(true); - } -} - -void FocusFilter::next_frame() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->next_frame(); - } else { - panel_sequence_viewer->next_frame(); - } -} - -void FocusFilter::go_to_end() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->go_to_end(); - } else { - panel_sequence_viewer->go_to_end(); - } -} - -void FocusFilter::set_viewer_fullscreen() { - if (get_focused_panel() == panel_footage_viewer) { - panel_footage_viewer->viewer_widget()->set_fullscreen(); - } else { - panel_sequence_viewer->viewer_widget()->set_fullscreen(); - } -} - -void FocusFilter::set_marker() { - if (Timeline::GetTopSequence() != nullptr) { - QDockWidget* focused_panel = get_focused_panel(); - - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->set_marker(); - } else if (focused_panel == panel_sequence_viewer) { - panel_sequence_viewer->set_marker(); - } else { - panel_timeline.first()->set_marker(); - } - } -} - -void FocusFilter::playpause() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->toggle_play(); - } else { - panel_sequence_viewer->toggle_play(); - } -} - -void FocusFilter::pause() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->pause(); - } else { - panel_sequence_viewer->pause(); - } -} - -void FocusFilter::increase_speed() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->increase_speed(); - } else { - panel_sequence_viewer->increase_speed(); - } -} - -void FocusFilter::decrease_speed() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->decrease_speed(); - } else { - panel_sequence_viewer->decrease_speed(); - } -} - -void FocusFilter::set_in_point() { - if (get_focused_panel() == panel_footage_viewer) { - panel_footage_viewer->set_in_point(); - } else { - panel_sequence_viewer->set_in_point(); - } -} - -void FocusFilter::set_out_point() { - if (get_focused_panel() == panel_footage_viewer) { - panel_footage_viewer->set_out_point(); - } else { - panel_sequence_viewer->set_out_point(); - } -} - -void FocusFilter::clear_in() { - if (get_focused_panel() == panel_footage_viewer) { - panel_footage_viewer->clear_in(); - } else { - panel_sequence_viewer->clear_in(); - } -} - -void FocusFilter::clear_out() { - if (get_focused_panel() == panel_footage_viewer) { - panel_footage_viewer->clear_out(); - } else { - panel_sequence_viewer->clear_out(); - } -} - -void FocusFilter::clear_inout() { - if (get_focused_panel() == panel_footage_viewer) { - panel_footage_viewer->clear_inout_point(); - } else { - panel_sequence_viewer->clear_inout_point(); - } -} - -void FocusFilter::delete_function() { - if (panel_timeline.first()->headers->hasFocus()) { - panel_timeline.first()->headers->delete_markers(); - } else if (panel_footage_viewer->headers->hasFocus()) { - panel_footage_viewer->headers->delete_markers(); - } else if (panel_sequence_viewer->headers->hasFocus()) { - panel_sequence_viewer->headers->delete_markers(); - } else if (panel_effect_controls->focused()) { - panel_effect_controls->DeleteSelectedEffects(); - } else if (panel_project.first()->focused()) { - panel_project.first()->delete_selected_media(); - } else if (panel_effect_controls->focused()) { - panel_effect_controls->delete_selected_keyframes(); - } else if (panel_graph_editor->focused()) { - panel_graph_editor->delete_selected_keys(); - } else { - Sequence* top_sequence = Timeline::GetTopSequence().get(); - if (top_sequence != nullptr) { - ComboAction* ca = new ComboAction(); - top_sequence->DeleteAreas(ca, top_sequence->Selections(), true); - olive::undo_stack.push(ca); - update_ui(false); - } - } -} - -void FocusFilter::duplicate() { - if (panel_project.first()->focused()) { - panel_project.first()->duplicate_selected(); - } -} - -void FocusFilter::select_all() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_graph_editor) { - panel_graph_editor->select_all(); - } else { - panel_timeline.first()->select_all(); - } -} - -void FocusFilter::zoom_in() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_effect_controls) { - panel_effect_controls->set_zoom(true); - } else if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->set_zoom(true); - } else if (focused_panel == panel_sequence_viewer) { - panel_sequence_viewer->set_zoom(true); - } else { - panel_timeline.first()->zoom_in(); - } -} - -void FocusFilter::zoom_out() { - QDockWidget* focused_panel = get_focused_panel(); - if (focused_panel == panel_effect_controls) { - panel_effect_controls->set_zoom(false); - } else if (focused_panel == panel_footage_viewer) { - panel_footage_viewer->set_zoom(false); - } else if (focused_panel == panel_sequence_viewer) { - panel_sequence_viewer->set_zoom(false); - } else { - panel_timeline.first()->zoom_out(); - } -} - -void FocusFilter::cut() { - if (Timeline::GetTopSequence() != nullptr) { - QDockWidget* focused_panel = get_focused_panel(); - if (panel_effect_controls == focused_panel) { - panel_effect_controls->copy(true); - } else { - panel_timeline.first()->copy(true); - } - } -} - -void FocusFilter::copy() { - if (Timeline::GetTopSequence() != nullptr) { - QDockWidget* focused_panel = get_focused_panel(); - if (panel_effect_controls == focused_panel) { - panel_effect_controls->copy(false); - } else { - panel_timeline.first()->copy(false); - } - } -} diff --git a/ui/focusfilter.h b/ui/focusfilter.h deleted file mode 100644 index 841749f4e..000000000 --- a/ui/focusfilter.h +++ /dev/null @@ -1,231 +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 FOCUSFILTER_H -#define FOCUSFILTER_H - -#include - -/** - * @brief The FocusFilter class - * - * Some keyboard shortcuts/menu actions will do different things depending on the panel that's currently focused. - * For example, pressing "Set Marker" will set a marker on the main active sequence if the timeline is focused, - * or on the media in the Media Viewer if the Media Viewer is focused. This class provides slots/functions that - * can be called that will check which panel is focused and call the appropriate function. - * - * Responds to `config.hover_focus`. Default behavior is focus by clicking on the panels, but if `hover_focus` is - * **TRUE**, the focused panel will be whichever panel has the cursor currently hovering over it. - */ -class FocusFilter : public QObject { - Q_OBJECT -public: - /** - * @brief FocusFilter Constructor - * - * Currently empty. - */ - FocusFilter(); - -public slots: - /** - * @brief Cuts selected clips or selected effects (but not both). - * - * If the Effect Controls panel is focused, cuts selected effects. Otherwise cuts selected clips. - */ - void cut(); - - /** - * @brief Copies selected clips or selected effects (but not both). - * - * If the Effect Controls panel is focused, copies selected effects. Otherwise copies selected clips. - */ - void copy(); - - /** - * @brief Duplicates currently selected items - * - * Currently this only duplicates Sequences in the project panel. - */ - void duplicate(); - - /** - * @brief Go to In Point. - * - * Calls go_to_in() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void go_to_in(); - - /** - * @brief Go to Out Point. - * - * Calls go_to_out() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void go_to_out(); - - /** - * @brief Go to Start - * - * Calls go_to_start() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void go_to_start(); - - /** - * @brief Go to Previous Frame - * - * Calls previous_frame() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void prev_frame(); - - /** - * @brief Play In Point to Out Point - * - * Calls play(true) on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void play_in_to_out(); - - /** - * @brief Toggle Play/Pause - * - * Calls toggle_play() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void playpause(); - - /** - * @brief Pause/Shuttle Stop. - * - * Calls pause() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void pause(); - - /** - * @brief Increase Speed/Shuttle Right - * - * Calls increase_speed() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void increase_speed(); - - /** - * @brief Decrease Speed/Shuttle Left - * - * Calls decrease_speed() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void decrease_speed(); - - /** - * @brief Go to Next Frame - * - * Calls next_frame() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void next_frame(); - - /** - * @brief Go to End - * - * Calls go_to_end() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void go_to_end(); - - /** - * @brief Set currently focused viewer to full screen - * - * Calls viewer_widget->set_fullscreen() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void set_viewer_fullscreen(); - - /** - * @brief Set a marker at the current playhead - * - * Calls set_marker() on Media Viewer or Sequence Viewer if it's focused. Otherwise calls it on Timeline. - */ - void set_marker(); - - /** - * @brief Set in point - * - * Calls set_in_point() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void set_in_point(); - - /** - * @brief Set out point - * - * Calls set_out_point() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void set_out_point(); - - /** - * @brief Clear in point - * - * Calls clear_in() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void clear_in(); - - /** - * @brief Clear out point - * - * Calls clear_out() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void clear_out(); - - /** - * @brief Clear in/out point - * - * Calls clear_inout() on Media Viewer it's focused. Otherwise calls it on Sequence Viewer. - */ - void clear_inout(); - - /** - * @brief Delete - * - * Calls various delete functions based on which UI elements are focused. Deletes span anywhere from deleting - * clips (Timeline), to effects (Effect Controls), to markers (TimelineHeader). - */ - void delete_function(); - - /** - * @brief Select All - * - * Calls select_all() on Graph Editor if its focused or Timeline if it's not. - */ - void select_all(); - - /** - * @brief Zoom In - * - * Calls zoom_in() on Effect Controls, Footage Viewer, or Sequence Viewer if one of them is focused. Otherwise - * calls it on Timeline. - */ - void zoom_in(); - - /** - * @brief Zoom Out - * - * Calls zoom_out() on Effect Controls, Footage Viewer, or Sequence Viewer if one of them is focused. Otherwise - * calls it on Timeline. - */ - void zoom_out(); -}; - -namespace olive { -extern FocusFilter FocusFilter; -} - -#endif // FOCUSFILTER_H diff --git a/ui/graphview.cpp b/ui/graphview.cpp deleted file mode 100644 index dfc3044f9..000000000 --- a/ui/graphview.cpp +++ /dev/null @@ -1,950 +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 "graphview.h" - -#include -#include -#include -#include - -#include "global/config.h" -#include "panels/panels.h" -#include "panels/timeline.h" -#include "panels/viewer.h" -#include "timeline/sequence.h" -#include "ui/keyframedrawing.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "nodes/oldeffectnode.h" -#include "timeline/clip.h" -#include "ui/rectangleselect.h" -#include "ui/menu.h" -#include "global/debug.h" - -const double kGraphZoomSpeed = 0.05; -const int kGraphSize = 100; -const int kBezierHandleSize = 3; -const int kBezierLineSize = 2; - -const int kBezierHandleNone = 1; -const int kBezierHandlePre = 2; -const int kBezierHandlePost = 3; - -QColor get_curve_color(int index, int length) { - QColor c; - int hue = qRound((double(index)/double(length))*255); - c.setHsv(hue, 255, 255); - return c; -} - -GraphView::GraphView(QWidget* parent) : QWidget(parent) { - x_scroll = 0; - y_scroll = 0; - mousedown = false; - x_zoom = 1.0; - y_zoom = 1.0; - row = nullptr; - moved_keys = false; - current_handle = kBezierHandleNone; - rect_select = false; - visible_in = 0; - click_add_proc = false; - - setMouseTracking(true); - setFocusPolicy(Qt::ClickFocus); - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); -} - -void GraphView::show_context_menu(const QPoint& pos) { - Menu menu(this); - - QAction* zoom_to_selection = menu.addAction(tr("Zoom to Selection")); - if (selected_keys.size() == 0 || row == nullptr) { - zoom_to_selection->setEnabled(false); - } else { - connect(zoom_to_selection, SIGNAL(triggered(bool)), this, SLOT(set_view_to_selection())); - } - - QAction* zoom_to_all = menu.addAction(tr("Zoom to Show All")); - if (row == nullptr) { - zoom_to_all->setEnabled(false); - } else { - connect(zoom_to_all, SIGNAL(triggered(bool)), this, SLOT(set_view_to_all())); - } - - menu.addSeparator(); - - QAction* reset_action = menu.addAction(tr("Reset View")); - if (row == nullptr) { - reset_action->setEnabled(false); - } else { - connect(reset_action, SIGNAL(triggered(bool)), this, SLOT(reset_view())); - } - - menu.exec(mapToGlobal(pos)); -} - -void GraphView::reset_view() { - x_zoom = 1.0; - y_zoom = 1.0; - set_scroll_x(0); - set_scroll_y(0); - emit zoom_changed(x_zoom, y_zoom); - update(); -} - -void GraphView::set_view_to_selection() { - if (row != nullptr && selected_keys.size() > 0) { - double min_time = DBL_MAX; - double max_time = DBL_MIN; - double min_dbl = DBL_MAX; - double max_dbl = DBL_MIN; - for (int i=0;iField(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i)); - min_time = qMin(key.time, min_time); - max_time = qMax(key.time, max_time); - min_dbl = qMin(key.data.toDouble(), min_dbl); - max_dbl = qMax(key.data.toDouble(), max_dbl); - } - - /* FIXME - min_time -= row->GetParentEffect()->parent_clip->clip_in(); - max_time -= row->GetParentEffect()->parent_clip->clip_in(); - */ - - set_view_to_rect(min_time, min_dbl, max_time, max_dbl); - } -} - -void GraphView::set_view_to_all() { - if (row != nullptr) { - bool can_set = false; - - double min_time = DBL_MAX; - double max_time = DBL_MIN; - double min_dbl = DBL_MAX; - double max_dbl = DBL_MIN; - for (int i=0;iFieldCount();i++) { - for (int j=0;jField(i)->keyframes.size();j++) { - const EffectKeyframe& key = row->Field(i)->keyframes.at(j); - min_time = qMin(key.time, min_time); - max_time = qMax(key.time, max_time); - min_dbl = qMin(key.data.toDouble(), min_dbl); - max_dbl = qMax(key.data.toDouble(), max_dbl); - can_set = true; - } - } - if (can_set) { - /* FIXME - min_time -= row->GetParentEffect()->parent_clip->clip_in(); - max_time -= row->GetParentEffect()->parent_clip->clip_in(); - */ - - set_view_to_rect(min_time, min_dbl, max_time, max_dbl); - } - } -} - -void GraphView::set_view_to_rect(double x1, double y1, double x2, double y2) { - double padding = 1.5; - double x_diff = double(x2 - x1); - double y_diff = (y2 - y1); - double x_diff_padded = (x_diff+10)*padding; - double y_diff_padded = (y_diff+10)*padding; - set_zoom(double(width()) / x_diff_padded, double(height()) / y_diff_padded); - - set_scroll_x(qRound((double(x1) - ((x_diff_padded-x_diff)/2))*x_zoom)); - set_scroll_y(qRound((double(y1) - ((y_diff_padded-y_diff)/2))*y_zoom)); -} - -void GraphView::draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos) { - // draws last line's text - QString str = QString::number(line_no*kGraphSize); - int text_sz = vert ? fontMetrics().height() : fontMetrics().width(str); - if (text_sz < (next_line_pos - line_pos)) { - QRect text_rect = vert ? QRect(0, line_pos-50, 50, 50) : QRect(line_pos, height()-50, 50, 50); - p.drawText(text_rect, Qt::AlignBottom | Qt::AlignLeft, str); - } -} - -void GraphView::draw_lines(QPainter& p, bool vert) { - int last_line = INT_MIN; - int last_line_x = INT_MIN; - int lim = vert ? height() : width(); - int scroll = vert ? y_scroll : x_scroll; - for (int i=0;i sort_keys_from_field(EffectField* field) { - QVector sorted_keys; - for (int k=0;kkeyframes.size();k++) { - bool inserted = false; - for (int j=0;jkeyframes.at(sorted_keys.at(j)).time > field->keyframes.at(k).time) { - sorted_keys.insert(j, k); - inserted = true; - break; - } - } - if (!inserted) { - sorted_keys.append(k); - } - } - return sorted_keys; -} - -void GraphView::paintEvent(QPaintEvent *) { - QPainter p(this); - - if (panel_sequence_viewer->seq != nullptr) { - // draw grid lines - - p.setPen(Qt::gray); - - draw_lines(p, true); - draw_lines(p, false); - - // draw keyframes - if (row != nullptr) { - QPen line_pen; - line_pen.setWidth(kBezierLineSize); - - for (int i=row->FieldCount()-1;i>=0;i--) { - EffectField* field = row->Field(i); - - if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { - // sort keyframes by time - QVector sorted_keys = sort_keys_from_field(field); - - int last_key_x = 0; - int last_key_y = 0; - - // draw lines - for (int j=0;jkeyframes.at(sorted_keys.at(j)); - - int key_x = get_screen_x(key.time); - int key_y = get_screen_y(key.data.toDouble()); - - line_pen.setColor(get_curve_color(i, row->FieldCount())); - p.setPen(line_pen); - if (j == 0) { - p.drawLine(0, key_y, key_x, key_y); - } else { - const EffectKeyframe& last_key = field->keyframes.at(sorted_keys.at(j-1)); - - double pre_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j), false); - double last_post_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j-1), true); - - if (last_key.type == EFFECT_KEYFRAME_HOLD) { - // hold - p.drawLine(last_key_x, last_key_y, key_x, last_key_y); - p.drawLine(key_x, last_key_y, key_x, key_y); - } else if (last_key.type == EFFECT_KEYFRAME_BEZIER || key.type == EFFECT_KEYFRAME_BEZIER) { - QPainterPath bezier_path; - bezier_path.moveTo(last_key_x, last_key_y); - if (last_key.type == EFFECT_KEYFRAME_BEZIER && key.type == EFFECT_KEYFRAME_BEZIER) { - // cubic bezier - bezier_path.cubicTo( - QPointF(last_key_x+last_post_handle*x_zoom, last_key_y-last_key.post_handle.y()*y_zoom), - QPointF(key_x+pre_handle*x_zoom, key_y-key.pre_handle.y()*y_zoom), - QPointF(key_x, key_y) - ); - } else if (key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier - // last keyframe is the bezier one - bezier_path.quadTo( - QPointF(last_key_x+last_post_handle*x_zoom, last_key_y-last_key.post_handle.y()*y_zoom), - QPointF(key_x, key_y) - ); - } else { - // this keyframe is the bezier one - bezier_path.quadTo( - QPointF(key_x+pre_handle*x_zoom, key_y-key.pre_handle.y()*y_zoom), - QPointF(key_x, key_y) - ); - } - p.drawPath(bezier_path); - } else { - // linear - p.drawLine(last_key_x, last_key_y, key_x, key_y); - } - } - last_key_x = key_x; - last_key_y = key_y; - } - if (last_key_x < width()) p.drawLine(last_key_x, last_key_y, width(), last_key_y); - - // draw keys - for (int j=0;jkeyframes.at(sorted_keys.at(j)); - - int key_x = get_screen_x(key.time); - int key_y = get_screen_y(key.data.toDouble()); - - if (key.type == EFFECT_KEYFRAME_BEZIER) { - p.setPen(Qt::gray); - - // pre handle line - QPointF pre_point(key_x + key.pre_handle.x()*x_zoom, key_y - key.pre_handle.y()*y_zoom); - p.drawLine(pre_point, QPointF(key_x, key_y)); - p.drawEllipse(pre_point, kBezierHandleSize, kBezierHandleSize); - - // post handle line - QPointF post_point(key_x + key.post_handle.x()*x_zoom, key_y - key.post_handle.y()*y_zoom); - p.drawLine(post_point, QPointF(key_x, key_y)); - p.drawEllipse(post_point, kBezierHandleSize, kBezierHandleSize); - } - - bool selected = false; - for (int k=0;kseq->playhead - visible_in)*x_zoom) - x_scroll); - p.drawLine(playhead_x, 0, playhead_x, height()); - - if (rect_select) { - olive::ui::DrawSelectionRectangle(p, QRect(rect_select_x, rect_select_y, rect_select_w, rect_select_h)); - p.setBrush(Qt::NoBrush); - } - } - - p.setPen(Qt::white); - - QRect border = rect(); - border.setWidth(border.width()-1); - border.setHeight(border.height()-1); - p.drawRect(border); -} - -void GraphView::mousePressEvent(QMouseEvent *event) { - if (row != nullptr) { - mousedown = true; - start_x = event->pos().x(); - start_y = event->pos().y(); - - // selecting - int sel_key = -1; - int sel_key_field = -1; - current_handle = kBezierHandleNone; - - if (click_add && (event->buttons() & Qt::LeftButton)) { - selected_keys.clear(); - selected_keys_fields.clear(); - - EffectKeyframe key; - key.time = get_value_x(event->pos().x()); - key.data = get_value_y(event->pos().y()); - key.type = click_add_type; - click_add_key = click_add_field->keyframes.size(); - click_add_field->keyframes.append(key); - update_ui(false); - click_add_proc = true; - } else { - for (int i=0;iFieldCount();i++) { - EffectField* field = row->Field(i); - if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { - for (int j=0;jkeyframes.size();j++) { - const EffectKeyframe& key = field->keyframes.at(j); - int key_x = get_screen_x(key.time); - int key_y = get_screen_y(key.data.toDouble()); - if (event->pos().x() > key_x-KEYFRAME_SIZE - && event->pos().x() < key_x+KEYFRAME_SIZE - && event->pos().y() > key_y-KEYFRAME_SIZE - && event->pos().y() < key_y+KEYFRAME_SIZE) { - sel_key = j; - sel_key_field = i; - break; - } else { - // selecting a handle - QPointF pre_point(key_x + key.pre_handle.x()*x_zoom, key_y - key.pre_handle.y()*y_zoom); - QPointF post_point(key_x + key.post_handle.x()*x_zoom, key_y - key.post_handle.y()*y_zoom); - if (event->pos().x() > pre_point.x()-kBezierHandleSize - && event->pos().x() < pre_point.x()+kBezierHandleSize - && event->pos().y() > pre_point.y()-kBezierHandleSize - && event->pos().y() < pre_point.y()+kBezierHandleSize) { - current_handle = kBezierHandlePre; - } else if (event->pos().x() > post_point.x()-kBezierHandleSize - && event->pos().x() < post_point.x()+kBezierHandleSize - && event->pos().y() > post_point.y()-kBezierHandleSize - && event->pos().y() < post_point.y()+kBezierHandleSize) { - current_handle = kBezierHandlePost; - } - - if (current_handle != kBezierHandleNone) { - sel_key = j; - sel_key_field = i; - handle_index = j; - handle_field = i; - old_pre_handle_x = key.pre_handle.x(); - old_pre_handle_y = key.pre_handle.y(); - old_post_handle_x = key.post_handle.x(); - old_post_handle_y = key.post_handle.y(); - break; - } - } - } - } - if (sel_key > -1) break; - } - - bool already_selected = false; - if (sel_key > -1) { - for (int i=0;imodifiers() & Qt::ShiftModifier) && current_handle == kBezierHandleNone) { - selected_keys.removeAt(i); - selected_keys_fields.removeAt(i); - } - already_selected = true; - break; - } - } - } - if (!already_selected) { - if (!(event->modifiers() & Qt::ShiftModifier)) { - selected_keys.clear(); - selected_keys_fields.clear(); - } - if (sel_key > -1) { - selected_keys.append(sel_key); - selected_keys_fields.append(sel_key_field); - } else { - rect_select = true; - rect_select_x = event->pos().x(); - rect_select_y = event->pos().y(); - rect_select_w = 0; - rect_select_h = 0; - rect_select_offset = selected_keys.size(); - } - } - - selection_update(); - } - } -} - -void GraphView::mouseMoveEvent(QMouseEvent *event) { - if (!mousedown || !click_add) unsetCursor(); - if (mousedown) { - if (event->buttons() & Qt::MiddleButton || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { - set_scroll_x(x_scroll + start_x - event->pos().x()); - set_scroll_y(y_scroll + event->pos().y() - start_y); - start_x = event->pos().x(); - start_y = event->pos().y(); - update(); - } else if (click_add_proc) { - click_add_field->keyframes[click_add_key].time = get_value_x(event->pos().x()); - click_add_field->keyframes[click_add_key].data = get_value_y(event->pos().y()); - update_ui(false); - } else if (rect_select) { - rect_select_w = event->pos().x() - rect_select_x; - rect_select_h = event->pos().y() - rect_select_y; - - selected_keys.resize(rect_select_offset); - selected_keys_fields.resize(rect_select_offset); - - for (int i=0;iFieldCount();i++) { - EffectField* f = row->Field(i); - for (int j=0;jkeyframes.size();j++) { - bool already_selected = false; - for (int k=0;kkeyframes.at(j).time), get_screen_y(f->keyframes.at(j).data.toDouble())); - QRect select_rect(rect_select_x, rect_select_y, rect_select_w, rect_select_h); - if (select_rect.contains(key_screen_point)) { - selected_keys.append(j); - selected_keys_fields.append(i); - } - } - } - } - update(); - } else { - switch (current_handle) { - case kBezierHandleNone: - for (int i=0;iField(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].time = qRound(selected_keys_old_vals.at(i) + (double(event->pos().x() - start_x)/x_zoom)); - if (event->modifiers() & Qt::ShiftModifier) { - row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = selected_keys_old_doubles.at(i); - } else { - row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = qRound(selected_keys_old_doubles.at(i) + (double(start_y - event->pos().y())/y_zoom)); - } - } - moved_keys = true; - update_ui(false); - break; - case kBezierHandlePre: - case kBezierHandlePost: - { - double new_pre_handle_x = old_pre_handle_x; - double new_pre_handle_y = old_pre_handle_y; - double new_post_handle_x = old_post_handle_x; - double new_post_handle_y = old_post_handle_y; - - double x_diff = double(event->pos().x() - start_x)/x_zoom; - double y_diff = double(start_y - event->pos().y())/y_zoom; - - if (current_handle == kBezierHandlePre) { - new_pre_handle_x += x_diff; - if (!(event->modifiers() & Qt::ShiftModifier)) new_pre_handle_y += y_diff; - if (!(event->modifiers() & Qt::ControlModifier)) { - new_post_handle_x = -new_pre_handle_x; - new_post_handle_y = -new_pre_handle_y; - } - } else { - new_post_handle_x += x_diff; - if (!(event->modifiers() & Qt::ShiftModifier)) new_post_handle_y += y_diff; - if (!(event->modifiers() & Qt::ControlModifier)) { - new_pre_handle_x = -new_post_handle_x; - new_pre_handle_y = -new_post_handle_y; - } - } - - EffectKeyframe& key = row->Field(handle_field)->keyframes[handle_index]; - key.pre_handle = QPointF(qMin(0.0, new_pre_handle_x), new_pre_handle_y); - key.post_handle = QPointF(qMax(0.0, new_post_handle_x), new_post_handle_y); - - moved_keys = true; - update_ui(false); - } - break; - } - } - } else if (row != nullptr) { - // clicking on the curve - click_add = false; - - bool hovering_key = false; - - for (int i=0;iFieldCount();i++) { - for (int j=0;jField(i)->keyframes.size();j++) { - const EffectKeyframe& key = row->Field(i)->keyframes.at(j); - int key_x = get_screen_x(key.time); - int key_y = get_screen_y(key.data.toDouble()); - QRect test_rect( - key_x - KEYFRAME_SIZE, - key_y - KEYFRAME_SIZE, - KEYFRAME_SIZE+KEYFRAME_SIZE, - KEYFRAME_SIZE+KEYFRAME_SIZE - ); - QRect pre_rect( - qRound(key_x + key.pre_handle.x()*x_zoom - kBezierHandleSize), - qRound(key_y + key.pre_handle.y()*y_zoom - kBezierHandleSize), - kBezierHandleSize+kBezierHandleSize, - kBezierHandleSize+kBezierHandleSize - ); - QRect post_rect( - qRound(key_x + key.post_handle.x()*x_zoom - kBezierHandleSize), - qRound(key_y + key.post_handle.y()*y_zoom - kBezierHandleSize), - kBezierHandleSize+kBezierHandleSize, - kBezierHandleSize+kBezierHandleSize - ); - - if (test_rect.contains(event->pos()) - || pre_rect.contains(event->pos()) - || post_rect.contains(event->pos())) { - hovering_key = true; - break; - } - } - } - - if (!hovering_key) { - for (int i=0;iFieldCount();i++) { - EffectField* f = row->Field(i); - if (field_visibility.at(i)) { - QVector sorted_keys = sort_keys_from_field(f); - - if (!sorted_keys.isEmpty()) { - if (event->pos().x() <= get_screen_x(f->keyframes.at(sorted_keys.first()).time)) { - int y_comp = get_screen_y(f->keyframes.at(sorted_keys.first()).data.toDouble()); - if (event->pos().y() >= y_comp-kBezierLineSize - && event->pos().y() <= y_comp+kBezierLineSize) { - // dout << "make an EARLY key on field" << i; - click_add = true; - click_add_type = f->keyframes.at(sorted_keys.first()).type; - } - } else if (event->pos().x() >= get_screen_x(f->keyframes.at(sorted_keys.last()).time)) { - int y_comp = get_screen_y(f->keyframes.at(sorted_keys.last()).data.toDouble()); - if (event->pos().y() >= y_comp-kBezierLineSize - && event->pos().y() <= y_comp+kBezierLineSize) { - // dout << "make an LATE key on field" << i; - click_add = true; - click_add_type = f->keyframes.at(sorted_keys.last()).type; - } - } else { - for (int j=1;jkeyframes.at(sorted_keys.at(j-1)); - const EffectKeyframe& key = f->keyframes.at(sorted_keys.at(j)); - - int last_key_x = get_screen_x(last_key.time); - int key_x = get_screen_x(key.time); - int last_key_y = get_screen_y(last_key.data.toDouble()); - int key_y = get_screen_y(key.data.toDouble()); - - click_add_type = last_key.type; - - if (event->pos().x() >= last_key_x - && event->pos().x() <= key_x) { - QRect mouse_rect(event->pos().x()-kBezierLineSize, event->pos().y()-kBezierLineSize, kBezierLineSize+kBezierLineSize, kBezierLineSize+kBezierLineSize); - // NOTE: FILTHY copy/paste from paintEvent - if (last_key.type == EFFECT_KEYFRAME_HOLD) { - // hold - if (event->pos().y() >= last_key_y-kBezierLineSize - && event->pos().y() <= last_key_y+kBezierLineSize) { - // dout << "make an HOLD key on field" << i << "after key" << j; - click_add = true; - } - } else if (last_key.type == EFFECT_KEYFRAME_BEZIER || key.type == EFFECT_KEYFRAME_BEZIER) { - QPainterPath bezier_path; - bezier_path.moveTo(last_key_x, last_key_y); - if (last_key.type == EFFECT_KEYFRAME_BEZIER && key.type == EFFECT_KEYFRAME_BEZIER) { - // cubic bezier - bezier_path.cubicTo( - QPointF(last_key_x+last_key.post_handle.x()*x_zoom, last_key_y-last_key.post_handle.y()*y_zoom), - QPointF(key_x+key.pre_handle.x()*x_zoom, key_y-key.pre_handle.y()*y_zoom), - QPointF(key_x, key_y) - ); - } else if (key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier - // last keyframe is the bezier one - bezier_path.quadTo( - QPointF(last_key_x+last_key.post_handle.x()*x_zoom, last_key_y-last_key.post_handle.y()*y_zoom), - QPointF(key_x, key_y) - ); - } else { - // this keyframe is the bezier one - bezier_path.quadTo( - QPointF(key_x+key.pre_handle.x()*x_zoom, key_y-key.pre_handle.y()*y_zoom), - QPointF(key_x, key_y) - ); - } - if (bezier_path.intersects(mouse_rect)) { - // dout << "make an BEZIER key on field" << i << "after key" << j; - click_add = true; - } - } else { - // linear - QPainterPath linear_path; - linear_path.moveTo(last_key_x, last_key_y); - linear_path.lineTo(key_x, key_y); - if (linear_path.intersects(mouse_rect)) { - // dout << "make an LINEAR key on field" << i << "after key" << j; - click_add = true; - } - } - } - } - } - } - } - if (click_add) { - click_add_field = f; - setCursor(Qt::CrossCursor); - break; - } - } - } - } -} - -void GraphView::mouseReleaseEvent(QMouseEvent *) { - if (click_add_proc) { - olive::undo_stack.push(new KeyframeAdd(click_add_field, click_add_key)); - } else if (moved_keys && selected_keys.size() > 0) { - ComboAction* ca = new ComboAction(); - switch (current_handle) { - case kBezierHandleNone: - for (int i=0;iField(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)]; - ca->append(new SetDouble(&key.time, selected_keys_old_vals.at(i), key.time)); - ca->append(new SetQVariant(&key.data, selected_keys_old_doubles.at(i), key.data)); - } - break; - case kBezierHandlePre: - case kBezierHandlePost: - { - EffectKeyframe& key = row->Field(handle_field)->keyframes[handle_index]; - ca->append(new SetPointF(&key.pre_handle, QPointF(old_pre_handle_x, old_pre_handle_y), key.pre_handle)); - ca->append(new SetPointF(&key.post_handle, QPointF(old_post_handle_x, old_post_handle_y), key.post_handle)); - } - break; - } - olive::undo_stack.push(ca); - } - moved_keys = false; - mousedown = false; - click_add = false; - click_add_proc = false; - if (rect_select) { - rect_select = false; - selection_update(); - update(); - } -} - -void GraphView::wheelEvent(QWheelEvent *event) { - - bool redraw = false; - bool zooming = false; - - // Respect the "Scroll Wheel Zooms" option here; Ctrl toggles. - // Default zoom: zoom uniformly (both axes equally) - // Alt: zoom vertically - // Shift: zoom horizontally - // Alt + Shift: zoom uniformly - - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool ctrl = (event->modifiers() & Qt::ControlModifier); - bool alt = (event->modifiers() & Qt::AltModifier); - - int delta_h = event->angleDelta().x(); - int delta_v = event->angleDelta().y(); - - double new_x_zoom = x_zoom; - double new_y_zoom = y_zoom; - - if (ctrl != olive::config.scroll_zooms) { - zooming = true; - } - - if (zooming) { - // Combine "source" deltas when zooming. Key modifiers determine axis - delta_h = delta_h + delta_v; - delta_v = delta_h; - } - - // If Alt is held but not Shift, make it a vertical zoom - if (zooming && alt && !shift) { - delta_h = 0; - } - - // If Shift is held but not Alt, make it a horizontal zoom - if (zooming && shift && !alt) { - delta_v = 0; - } - - if (!zooming) { - // Shift to swap axes - if (shift) { - std::swap(delta_h, delta_v); - } - - // Minus to correct for scroll vs. zoom behavior on horiz axis - set_scroll_x(x_scroll - (delta_h / 10)); - set_scroll_y(y_scroll + (delta_v / 10)); - - redraw = true; - } - - if (zooming && (delta_v != 0)) { - double zoom_diff = (kGraphZoomSpeed*y_zoom); - new_y_zoom = y_zoom + (zoom_diff * (delta_v / 120.0)); - - // Center zoom around the mouse cursor vertically - int true_mouse_y = height()-event->pos().y(); - set_scroll_y(qRound((double(y_scroll + true_mouse_y) / y_zoom) * new_y_zoom) - true_mouse_y); - - redraw = true; - } - - if (zooming && (delta_h != 0)) { - double zoom_diff = (kGraphZoomSpeed*x_zoom); - - new_x_zoom = x_zoom + (zoom_diff * (delta_h / 120.0)); - - // Center zoom around the mouse cursor horizontally - set_scroll_x(qRound((double(x_scroll + event->pos().x()) / x_zoom) * new_x_zoom) - event->pos().x()); - - redraw = true; - } - - if (zooming) { - set_zoom(new_x_zoom, new_y_zoom); - } - - if (redraw) { - update(); - } -} - -void GraphView::set_row(NodeIO *r) { - if (row != r) { - selected_keys.clear(); - selected_keys_fields.clear(); - selected_keys_old_vals.clear(); - selected_keys_old_doubles.clear(); - emit selection_changed(false, -1); - row = r; - if (row != nullptr) { - field_visibility.resize(row->FieldCount()); - for (int i=0;iFieldCount();i++) { - field_visibility[i] = row->Field(i)->IsEnabled(); - } - // FIXME - //visible_in = row->ParentNode()->parent_clip->timeline_in(); - set_view_to_all(); - } else { - update(); - } - } -} - -void GraphView::set_selected_keyframe_type(int type) { - if (selected_keys.size() > 0) { - ComboAction* ca = new ComboAction(); - for (int i=0;iField(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)]; - ca->append(new SetInt(&key.type, type)); - } - olive::undo_stack.push(ca); - update_ui(false); - } -} - -void GraphView::set_field_visibility(int field, bool b) { - field_visibility[field] = b; - update(); -} - -void GraphView::delete_selected_keys() { - if (row != nullptr) { - QVector fields; - for (int i=0;iField(selected_keys_fields.at(i))); - } - delete_keyframes(fields, selected_keys); - } -} - -void GraphView::select_all() { - if (row != nullptr) { - selected_keys.clear(); - selected_keys_fields.clear(); - for (int i=0;iFieldCount();i++) { - EffectField* field = row->Field(i); - for (int j=0;jkeyframes.size();j++) { - selected_keys.append(j); - selected_keys_fields.append(i); - } - } - selection_update(); - } -} - -void GraphView::set_scroll_x(int s) { - x_scroll = s; - emit x_scroll_changed(x_scroll); -} - -void GraphView::set_scroll_y(int s) { - y_scroll = s; - emit y_scroll_changed(y_scroll); -} - -void GraphView::set_zoom(double xz, double yz) { - x_zoom = xz; - y_zoom = yz; - emit zoom_changed(x_zoom, y_zoom); -} - -int GraphView::get_screen_x(double d) { - if (row != nullptr) { - // FIXME - //d -= row->GetParentEffect()->parent_clip->clip_in(); - } - return qRound((d*x_zoom) - x_scroll); -} - -int GraphView::get_screen_y(double d) { - return qRound(height() + y_scroll - d*y_zoom); -} - -long GraphView::get_value_x(int i) { - long frame = qRound((i + x_scroll)/x_zoom); - if (row != nullptr) { - // FIXME - //frame += row->GetParentEffect()->parent_clip->clip_in(); - } - return frame; -} - -double GraphView::get_value_y(int i) { - return double(height() + y_scroll - i)/y_zoom; -} - -void GraphView::selection_update() { - selected_keys_old_vals.clear(); - selected_keys_old_doubles.clear(); - - int selected_key_type = -1; - - for (int i=0;iField(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i)); - selected_keys_old_vals.append(key.time); - selected_keys_old_doubles.append(key.data.toDouble()); - - if (selected_key_type == -1) { - selected_key_type = key.type; - } else if (selected_key_type != key.type) { - selected_key_type = -2; - } - } - - update(); - - emit selection_changed(selected_keys.size() > 0, selected_key_type); -} diff --git a/ui/graphview.h b/ui/graphview.h deleted file mode 100644 index 9aa4e4842..000000000 --- a/ui/graphview.h +++ /dev/null @@ -1,122 +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 GRAPHVIEW_H -#define GRAPHVIEW_H - -#include -#include - -#include "nodes/nodeio.h" -#include "effects/effectfields.h" - -QColor get_curve_color(int index, int length); - -class GraphView : public QWidget { - Q_OBJECT -public: - GraphView(QWidget* parent = nullptr); - - void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void wheelEvent(QWheelEvent *event); - - void set_row(NodeIO* r); - - void set_selected_keyframe_type(int type); - void set_field_visibility(int field, bool b); - - void delete_selected_keys(); - void select_all(); -signals: - void x_scroll_changed(int); - void y_scroll_changed(int); - void zoom_changed(double, double); - void selection_changed(bool, int); -private: - int x_scroll; - int y_scroll; - bool mousedown; - int start_x; - int start_y; - - double x_zoom; - double y_zoom; - - void set_scroll_x(int s); - void set_scroll_y(int s); - void set_zoom(double xz, double yz); - - int get_screen_x(double); - int get_screen_y(double); - long get_value_x(int); - double get_value_y(int); - - void selection_update(); - - QVector field_visibility; - - QVector selected_keys; - QVector selected_keys_fields; - QVector selected_keys_old_vals; - QVector selected_keys_old_doubles; - - double old_pre_handle_x; - double old_pre_handle_y; - double old_post_handle_x; - double old_post_handle_y; - - int handle_field; - int handle_index; - - bool moved_keys; - - int current_handle; - - void draw_lines(QPainter &p, bool vert); - void draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos); - - NodeIO* row; - - bool rect_select; - int rect_select_x; - int rect_select_y; - int rect_select_w; - int rect_select_h; - int rect_select_offset; - - long visible_in; - - bool click_add; - bool click_add_proc; - EffectField* click_add_field; - int click_add_key; - int click_add_type; -private slots: - void show_context_menu(const QPoint& pos); - void reset_view(); - void set_view_to_selection(); - void set_view_to_all(); - void set_view_to_rect(double x1, double y1, double x2, double y2); -}; - -#endif // GRAPHVIEW_H diff --git a/ui/icons.cpp b/ui/icons.cpp deleted file mode 100644 index da6345668..000000000 --- a/ui/icons.cpp +++ /dev/null @@ -1,114 +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 "icons.h" - -#include - -#include "global/global.h" -#include "global/config.h" - -QIcon olive::icon::LeftArrow; -QIcon olive::icon::RightArrow; -QIcon olive::icon::UpArrow; -QIcon olive::icon::DownArrow; -QIcon olive::icon::Diamond; -QIcon olive::icon::Clock; - -QIcon olive::icon::MediaVideo; -QIcon olive::icon::MediaAudio; -QIcon olive::icon::MediaImage; -QIcon olive::icon::MediaError; -QIcon olive::icon::MediaSequence; -QIcon olive::icon::MediaFolder; - -QIcon olive::icon::ViewerGoToStart; -QIcon olive::icon::ViewerPrevFrame; -QIcon olive::icon::ViewerPlay; -QIcon olive::icon::ViewerPause; -QIcon olive::icon::ViewerNextFrame; -QIcon olive::icon::ViewerGoToEnd; - -QIcon olive::icon::CreateIconFromSVG(const QString &path, bool create_disabled) -{ - QIcon icon; - - QPainter p; - - // Draw the icon as a solid color - QPixmap normal(path); - - // Color the icon dark if the user is using a dark theme - if (olive::styling::UseDarkIcons()) { - p.begin(&normal); - p.setCompositionMode(QPainter::CompositionMode_SourceIn); - p.fillRect(normal.rect(), QColor(32, 32, 32)); - p.end(); - } - - icon.addPixmap(normal, QIcon::Normal, QIcon::On); - - if (create_disabled) { - - // Create semi-transparent disabled icon - QPixmap disabled(normal.size()); - disabled.fill(Qt::transparent); - - // draw semi-transparent version of icon for the disabled variant - p.begin(&disabled); - p.setCompositionMode(QPainter::CompositionMode_SourceOver); - p.setOpacity(0.5); - p.drawPixmap(0, 0, normal); - p.end(); - - icon.addPixmap(disabled, QIcon::Disabled, QIcon::On); - - } - - return icon; -} - -void olive::icon::Initialize() -{ - qInfo() << "Initializing icons"; - - LeftArrow = CreateIconFromSVG(":/icons/tri-left.svg", false); - RightArrow = CreateIconFromSVG(":/icons/tri-right.svg", false); - UpArrow = CreateIconFromSVG(":/icons/tri-up.svg", false); - DownArrow = CreateIconFromSVG(":/icons/tri-down.svg", false); - Diamond = CreateIconFromSVG(":/icons/diamond.svg", false); - Clock = CreateIconFromSVG(":/icons/clock.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); - MediaFolder = CreateIconFromSVG(":/icons/folder.svg", false); - - ViewerGoToStart = CreateIconFromSVG(QStringLiteral(":/icons/prev.svg")); - ViewerPrevFrame = CreateIconFromSVG(QStringLiteral(":/icons/rew.svg")); - ViewerPlay = CreateIconFromSVG(QStringLiteral(":/icons/play.svg")); - ViewerPause = CreateIconFromSVG(":/icons/pause.svg", false); - ViewerNextFrame = CreateIconFromSVG(QStringLiteral(":/icons/ff.svg")); - ViewerGoToEnd = CreateIconFromSVG(QStringLiteral(":/icons/next.svg")); - - qInfo() << "Finished initializing icons"; -} diff --git a/ui/icons.h b/ui/icons.h deleted file mode 100644 index 9ace7f109..000000000 --- a/ui/icons.h +++ /dev/null @@ -1,66 +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 ICONS_H -#define ICONS_H - -#include - -namespace olive { - namespace icon { - extern QIcon LeftArrow; - extern QIcon RightArrow; - extern QIcon UpArrow; - extern QIcon DownArrow; - extern QIcon Diamond; - extern QIcon Clock; - - extern QIcon MediaVideo; - extern QIcon MediaAudio; - extern QIcon MediaImage; - extern QIcon MediaError; - extern QIcon MediaSequence; - extern QIcon MediaFolder; - - extern QIcon ViewerGoToStart; - extern QIcon ViewerPrevFrame; - extern QIcon ViewerPlay; - extern QIcon ViewerPause; - extern QIcon ViewerNextFrame; - extern QIcon ViewerGoToEnd; - - void Initialize(); - - /** - * @brief Converts an SVG into a QIcon with a semi-transparent for the QIcon::Disabled property - * - * @param path - * - * Path to SVG file - * - * @param create_disabled - * - * Create a semi-transparent disabled option. - */ - QIcon CreateIconFromSVG(const QString &path, bool create_disabled = true); - } -} - -#endif // ICONS_H diff --git a/ui/keyframedrawing.cpp b/ui/keyframedrawing.cpp deleted file mode 100644 index 951565611..000000000 --- a/ui/keyframedrawing.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 "keyframedrawing.h" - -#include "nodes/oldeffectnode.h" -#include "timeline/clip.h" - -#define KEYFRAME_POINT_COUNT 4 - -// routine for drawing a keyframe onscreen -void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r, int g, int b) { - if (darker) { - r *= 0.625; - g *= 0.625; - b *= 0.625; - } - p.setPen(QColor(0, 0, 0)); - p.setBrush(QColor(r, g, b)); - - switch (type) { - case EFFECT_KEYFRAME_LINEAR: - { - QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)}; - p.drawPolygon(points, KEYFRAME_POINT_COUNT); - } - break; - case EFFECT_KEYFRAME_BEZIER: - p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE); - break; - case EFFECT_KEYFRAME_HOLD: - p.drawRect(QRect(x - KEYFRAME_SIZE, y - KEYFRAME_SIZE, KEYFRAME_SIZE*2, KEYFRAME_SIZE*2)); - break; - } - - p.setBrush(Qt::NoBrush); -} - -// adjusts keyframe's internal time (in clip time) to timeline time -long adjust_row_keyframe(NodeIO* row, long time, long visible_in) { - return 0; - /* FIXME - return time - - row->GetParentEffect()->parent_clip->clip_in() - + (row->GetParentEffect()->parent_clip->timeline_in() - visible_in); - */ -} diff --git a/ui/keyframedrawing.h b/ui/keyframedrawing.h deleted file mode 100644 index 319704ddf..000000000 --- a/ui/keyframedrawing.h +++ /dev/null @@ -1,34 +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 KEYFRAMEDRAWING_H -#define KEYFRAMEDRAWING_H - -#include - -#define KEYFRAME_SIZE 6 -#define KEYFRAME_COLOR 160 - -class NodeIO; - -void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r = KEYFRAME_COLOR, int g = KEYFRAME_COLOR, int b = KEYFRAME_COLOR); -long adjust_row_keyframe(NodeIO* row, long time, long visible_in); - -#endif // KEYFRAMEDRAWING_H diff --git a/ui/keyframenavigator.cpp b/ui/keyframenavigator.cpp deleted file mode 100644 index 0ddd5b33b..000000000 --- a/ui/keyframenavigator.cpp +++ /dev/null @@ -1,98 +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 "keyframenavigator.h" - -#include -#include -#include -#include -#include - -#include "ui/icons.h" - -KeyframeNavigator::KeyframeNavigator(QWidget *parent, bool addLeftPad) : QWidget(parent) { - setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); - - key_controls = new QHBoxLayout(this); - key_controls->setSpacing(0); - key_controls->setMargin(0); - - if (addLeftPad) { - key_controls->addStretch(); - } - - QSizePolicy button_size_policy; - button_size_policy.setRetainSizeWhenHidden(true); - - left_key_nav = new QPushButton(this); - left_key_nav->setSizePolicy(button_size_policy); - left_key_nav->setIcon(olive::icon::LeftArrow); - left_key_nav->setIconSize(left_key_nav->iconSize()*0.5); - left_key_nav->setVisible(false); - key_controls->addWidget(left_key_nav); - connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_previous_key())); - connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - - key_addremove = new QPushButton(this); - key_addremove->setSizePolicy(button_size_policy); - key_addremove->setIcon(olive::icon::Diamond); - key_addremove->setIconSize(key_addremove->iconSize()*0.5); - key_addremove->setVisible(false); - key_controls->addWidget(key_addremove); - connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(toggle_key())); - connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - - right_key_nav = new QPushButton(this); - right_key_nav->setSizePolicy(button_size_policy); - right_key_nav->setIcon(olive::icon::RightArrow); - right_key_nav->setIconSize(right_key_nav->iconSize()*0.5); - right_key_nav->setVisible(false); - key_controls->addWidget(right_key_nav); - connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_next_key())); - connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - - keyframe_enable = new QPushButton(this); - keyframe_enable->setIcon(olive::icon::Clock); - keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); - keyframe_enable->setIconSize(keyframe_enable->iconSize()*0.75); - keyframe_enable->setCheckable(true); - keyframe_enable->setToolTip(tr("Enable Keyframes")); - connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(keyframe_enabled_changed(bool))); - connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool))); - connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - key_controls->addWidget(keyframe_enable); -} - -KeyframeNavigator::~KeyframeNavigator() {} - -void KeyframeNavigator::enable_keyframes(bool b) { - keyframe_enable->setChecked(b); -} - -void KeyframeNavigator::enable_keyframe_toggle(bool b) { - keyframe_enable->setVisible(b); -} - -void KeyframeNavigator::keyframe_ui_enabled(bool enabled) { - left_key_nav->setVisible(enabled); - key_addremove->setVisible(enabled); - right_key_nav->setVisible(enabled); -} diff --git a/ui/keyframenavigator.h b/ui/keyframenavigator.h deleted file mode 100644 index ec0842bfc..000000000 --- a/ui/keyframenavigator.h +++ /dev/null @@ -1,55 +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 KEYFRAMENAVIGATOR_H -#define KEYFRAMENAVIGATOR_H - -#include - -class QHBoxLayout; -class QPushButton; - -class KeyframeNavigator : public QWidget -{ - Q_OBJECT -public: - KeyframeNavigator(QWidget* parent = nullptr, bool addLeftPad = true); - ~KeyframeNavigator(); - - void enable_keyframe_toggle(bool); -public slots: - void enable_keyframes(bool); -signals: - void goto_previous_key(); - void toggle_key(); - void goto_next_key(); - void keyframe_enabled_changed(bool); - void clicked(); -private slots: - void keyframe_ui_enabled(bool); -private: - QHBoxLayout* key_controls; - QPushButton* left_key_nav; - QPushButton* key_addremove; - QPushButton* right_key_nav; - QPushButton* keyframe_enable; -}; - -#endif // KEYFRAMENAVIGATOR_H diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp deleted file mode 100644 index 3e7ecac77..000000000 --- a/ui/keyframeview.cpp +++ /dev/null @@ -1,450 +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 "keyframeview.h" - -#include -#include - -#include "nodes/oldeffectnode.h" -#include "ui/collapsiblewidget.h" -#include "panels/panels.h" -#include "timeline/clip.h" -#include "panels/timeline.h" -#include "ui/timelineheader.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "panels/viewer.h" -#include "ui/viewerwidget.h" -#include "timeline/sequence.h" -#include "panels/grapheditor.h" -#include "ui/keyframedrawing.h" -#include "ui/clickablelabel.h" -#include "ui/resizablescrollbar.h" -#include "ui/rectangleselect.h" -#include "effects/keyframe.h" -#include "ui/graphview.h" -#include "ui/menu.h" -#include "global/math.h" - -KeyframeView::KeyframeView(QWidget *parent) : - QWidget(parent), - visible_in(0), - visible_out(0), - mousedown(false), - dragging(false), - keys_selected(false), - select_rect(false), - x_scroll(0), - y_scroll(0), - scroll_drag(false) -{ - setFocusPolicy(Qt::ClickFocus); - setMouseTracking(true); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); -} - -void KeyframeView::SetEffects(const QVector &open_effects) -{ - open_effects_ = open_effects; -} - -void KeyframeView::show_context_menu(const QPoint& pos) { - if (selected_fields.size() > 0) { - Menu menu(this); - - QAction* linear = menu.addAction(tr("Linear")); - linear->setData(EFFECT_KEYFRAME_LINEAR); - QAction* bezier = menu.addAction(tr("Bezier")); - bezier->setData(EFFECT_KEYFRAME_BEZIER); - QAction* hold = menu.addAction(tr("Hold")); - hold->setData(EFFECT_KEYFRAME_HOLD); - menu.addSeparator(); - menu.addAction("Graph Editor"); - - connect(&menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_set_key_type(QAction*))); - menu.exec(mapToGlobal(pos)); - } -} - -void KeyframeView::menu_set_key_type(QAction* a) { - if (a->data().isNull()) { - // load graph editor - panel_graph_editor->show(); - } else { - ComboAction* ca = new ComboAction(); - for (int i=0;iappend(new SetInt(&f->keyframes[selected_keyframes.at(i)].type, a->data().toInt())); - } - olive::undo_stack.push(ca); - update_ui(false); - } -} - -void KeyframeView::paintEvent(QPaintEvent*) { - QPainter p(this); - - rowY.clear(); - rows.clear(); - - if (!open_effects_.isEmpty()) { - visible_in = LONG_MAX; - visible_out = 0; - - for (int i=0;iGetEffect()->parent_clip; - visible_in = qMin(visible_in, c->timeline_in()); - visible_out = qMax(visible_out, c->timeline_out()); - } - - for (int j=0;jGetEffect(); - - if (container->IsExpanded()) { - for (int j=0;jParameterCount();j++) { - NodeIO* row = e->Parameter(j); - - int keyframe_y = container->GetRowY(j, this); - - QVector key_times; - - for (int l=0;lFieldCount();l++) { - EffectField* f = row->Field(l); - for (int k=0;kkeyframes.size();k++) { - if (!key_times.contains(f->keyframes.at(k).time)) { - bool keyframe_selected = keyframeIsSelected(f, k); - long keyframe_frame = adjust_row_keyframe(row, f->keyframes.at(k).time, visible_in); - - // see if any other keyframes have this time - int appearances = 0; - for (int m=0;mFieldCount();m++) { - EffectField* compf = row->Field(m); - for (int n=0;nkeyframes.size();n++) { - if (f->keyframes.at(k).time == compf->keyframes.at(n).time) { - appearances++; - } - } - } - - if (appearances != row->FieldCount()) { - QColor cc = get_curve_color(l, row->FieldCount()); - draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected, cc.red(), cc.green(), cc.blue()); - } else { - draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected); - } - - key_times.append(f->keyframes.at(k).time); - } - } - } - - rows.append(row); - rowY.append(keyframe_y); - } - } - } - - int max_width = getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in); - if (max_width < width()) { - p.fillRect(QRect(max_width, 0, width(), height()), QColor(0, 0, 0, 64)); - } - panel_effect_controls->horizontalScrollBar->setMaximum(qMax(max_width - width(), 0)); - header->set_visible_in(visible_in); - - int playhead_x = getScreenPointFromFrame(panel_effect_controls->zoom, - open_effects_.first()->GetEffect()->parent_clip->track()->sequence()->playhead-visible_in) - x_scroll; - if (dragging && olive::timeline::snapped) { - p.setPen(Qt::white); - } else { - p.setPen(Qt::red); - } - p.drawLine(playhead_x, 0, playhead_x, height()); - } - - if (select_rect) { - olive::ui::DrawSelectionRectangle(p, QRect(rect_select_x, rect_select_y, rect_select_w, rect_select_h)); - } - - /*if (mouseover && mouseover_row < rowY.size()) { - draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, mouseover_frame - visible_in), rowY.at(mouseover_row), true); - }*/ -} - -void KeyframeView::wheelEvent(QWheelEvent *e) { - emit wheel_event_signal(e); -} - -bool KeyframeView::keyframeIsSelected(EffectField *field, int keyframe) { - for (int i=0;iupdate_panel(); - update(); -} - -void KeyframeView::delete_selected_keyframes() { - delete_keyframes(selected_fields, selected_keyframes); -} - -void KeyframeView::set_x_scroll(int s) { - x_scroll = s; - update_keys(); -} - -void KeyframeView::set_y_scroll(int s) { - y_scroll = s; - update_keys(); -} - -void KeyframeView::resize_move(double d) { - panel_effect_controls->zoom *= d; - header->update_zoom(panel_effect_controls->zoom); - update(); -} - -void KeyframeView::mousePressEvent(QMouseEvent *event) { - rect_select_x = event->x(); - rect_select_y = event->y(); - rect_select_w = 0; - rect_select_h = 0; - - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND || event->buttons() & Qt::MiddleButton) { - scroll_drag = true; - return; - } - - old_key_vals.clear(); - - int mouse_x = event->x() + x_scroll; - int mouse_y = event->y(); - int row_index = -1; - int field_index = -1; - int keyframe_index = -1; - long frame_diff = 0; - long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x-KEYFRAME_SIZE); - drag_frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x); - long frame_max = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x+KEYFRAME_SIZE); - for (int i=0;i rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) { - NodeIO* row = rows.at(i); - - row->FocusRow(); - - for (int k=0;kFieldCount();k++) { - EffectField* f = row->Field(k); - for (int j=0;jkeyframes.size();j++) { - /* FIXME - long eval_keyframe_time = f->keyframes.at(j).time-row->GetParentEffect()->parent_clip->clip_in()+(row->GetParentEffect()->parent_clip->timeline_in()-visible_in); - if (eval_keyframe_time >= frame_min && eval_keyframe_time <= frame_max) { - long eval_frame_diff = qAbs(eval_keyframe_time - drag_frame_start); - if (keyframe_index == -1 || eval_frame_diff < frame_diff) { - row_index = i; - field_index = k; - keyframe_index = j; - frame_diff = eval_frame_diff; - } - } - */ - } - } - break; - } - } - bool already_selected = false; - keys_selected = false; - if (keyframe_index > -1) { - already_selected = keyframeIsSelected(rows.at(row_index)->Field(field_index), keyframe_index); - } else { - select_rect = true; - } - if (!already_selected) { - if (!(event->modifiers() & Qt::ShiftModifier)) { - selected_fields.clear(); - selected_keyframes.clear(); - } - if (keyframe_index > -1) { - selected_fields.append(rows.at(row_index)->Field(field_index)); - selected_keyframes.append(keyframe_index); - - // find other field with keyframes at the same time - long comp_time = rows.at(row_index)->Field(field_index)->keyframes.at(keyframe_index).time; - for (int i=0;iFieldCount();i++) { - if (i != field_index) { - EffectField* f = rows.at(row_index)->Field(i); - for (int j=0;jkeyframes.size();j++) { - if (f->keyframes.at(j).time == comp_time) { - selected_fields.append(f); - selected_keyframes.append(j); - } - } - } - } - } - } - - if (selected_fields.size() > 0) { - for (int i=0;ikeyframes.at(selected_keyframes.at(i)).time); - } - keys_selected = true; - } - - rect_select_offset = selected_fields.size(); - - update_keys(); - - if (event->button() == Qt::LeftButton) { - mousedown = true; - } -} - -void KeyframeView::mouseMoveEvent(QMouseEvent* event) { - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { - setCursor(Qt::OpenHandCursor); - } else { - unsetCursor(); - } - if (scroll_drag) { - panel_effect_controls->horizontalScrollBar->setValue(panel_effect_controls->horizontalScrollBar->value() + rect_select_x - event->pos().x()); - panel_effect_controls->verticalScrollBar->setValue(panel_effect_controls->verticalScrollBar->value() + rect_select_y - event->pos().y()); - rect_select_x = event->pos().x(); - rect_select_y = event->pos().y(); - } else if (mousedown) { - int mouse_x = event->x() + x_scroll; - - long current_frame = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x); - panel_effect_controls->scroll_to_frame(current_frame + visible_in); - - if (select_rect) { - // do a rect select - selected_fields.resize(rect_select_offset); - selected_keyframes.resize(rect_select_offset); - - rect_select_w = event->x() - rect_select_x; - rect_select_h = event->y() - rect_select_y; - - int min_row = qMin(rect_select_y, event->y())-KEYFRAME_SIZE; - int max_row = qMax(rect_select_y, event->y())+KEYFRAME_SIZE; - - long frame_start = getFrameFromScreenPoint(panel_effect_controls->zoom, rect_select_x+x_scroll); - long min_frame = qMin(frame_start, current_frame)-KEYFRAME_SIZE; - long max_frame = qMax(frame_start, current_frame)+KEYFRAME_SIZE; - - for (int i=0;i= min_row && rowY.at(i) <= max_row) { - NodeIO* row = rows.at(i); - for (int k=0;kFieldCount();k++) { - EffectField* field = row->Field(k); - for (int j=0;jkeyframes.size();j++) { - long keyframe_frame = adjust_row_keyframe(row, field->keyframes.at(j).time, visible_in); - if (!keyframeIsSelected(field, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) { - selected_fields.append(field); - selected_keyframes.append(j); - } - } - } - } - } - - update_keys(); - } else if (keys_selected) { - // move keyframes - long frame_diff = current_frame - drag_frame_start; - - // snapping to playhead - olive::timeline::snapped = false; - if (olive::timeline::snapping) { - for (int i=0;iGetParentRow()->GetParentEffect()->parent_clip; - long key_time = old_key_vals.at(i) + frame_diff - c->clip_in() + c->timeline_in(); - long key_eval = key_time; - if (olive::timeline::SnapToPoint(c->track()->sequence()->playhead, &key_eval, header->get_zoom())) { - frame_diff += (key_eval - key_time); - break; - } - */ - } - } - - // validate frame_diff (make sure no keyframes overlap each other) - for (int i=0;ikeyframes.size();j++) { - while (!keyframeIsSelected(field, j) && field->keyframes.at(j).time == eval_key + frame_diff) { - if (last_frame_diff > frame_diff) { - frame_diff++; - olive::timeline::snapped = false; - } else { - frame_diff--; - olive::timeline::snapped = false; - } - } - } - } - - // apply frame_diffs - for (int i=0;ikeyframes[selected_keyframes.at(i)].time = old_key_vals.at(i) + frame_diff; - } - - last_frame_diff = frame_diff; - - dragging = true; - - update_ui(false); - } - } -} - -void KeyframeView::mouseReleaseEvent(QMouseEvent*) { - if (dragging) { - ComboAction* ca = new ComboAction(); - for (int i=0;iappend(new SetDouble( - &selected_fields.at(i)->keyframes[selected_keyframes.at(i)].time, - old_key_vals.at(i), - selected_fields.at(i)->keyframes.at(selected_keyframes.at(i)).time - )); - } - olive::undo_stack.push(ca); - } - - select_rect = false; - dragging = false; - mousedown = false; - scroll_drag = false; - olive::timeline::snapped = false; - update_ui(false); -} diff --git a/ui/keyframeview.h b/ui/keyframeview.h deleted file mode 100644 index 2211afbb0..000000000 --- a/ui/keyframeview.h +++ /dev/null @@ -1,92 +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 KEYFRAMEVIEW_H -#define KEYFRAMEVIEW_H - -#include -#include - -#include "ui/effectui.h" - -class Clip; -class OldEffectNode; -class NodeIO; -class EffectField; -class TimelineHeader; - -class KeyframeView : public QWidget { - Q_OBJECT -public: - KeyframeView(QWidget* parent = nullptr); - - void SetEffects(const QVector& open_effects); - - void delete_selected_keyframes(); - - TimelineHeader* header; - - long visible_in; - long visible_out; -signals: - void wheel_event_signal(QWheelEvent*); -public slots: - void set_x_scroll(int); - void set_y_scroll(int); - void resize_move(double d); -private: - QVector open_effects_; - - QVector selected_fields; - QVector selected_keyframes; - QVector rowY; - QVector rows; - QVector old_key_vals; - void mousePressEvent(QMouseEvent* event); - void mouseMoveEvent(QMouseEvent* event); - void mouseReleaseEvent(QMouseEvent *event); - void paintEvent(QPaintEvent *event); - void wheelEvent(QWheelEvent* e); - bool mousedown; - bool dragging; - bool keys_selected; - bool select_rect; - bool scroll_drag; - - bool keyframeIsSelected(EffectField *field, int keyframe); - - long drag_frame_start; - long last_frame_diff; - int rect_select_x; - int rect_select_y; - int rect_select_w; - int rect_select_h; - int rect_select_offset; - - int x_scroll; - int y_scroll; - - void update_keys(); -private slots: - void show_context_menu(const QPoint& pos); - void menu_set_key_type(QAction*); -}; - -#endif // KEYFRAMEVIEW_H diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp deleted file mode 100644 index 9aa622a28..000000000 --- a/ui/labelslider.cpp +++ /dev/null @@ -1,368 +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 "labelslider.h" - -#include -#include -#include -#include - -#include "undo/undo.h" -#include "global/timing.h" -#include "global/config.h" -#include "global/math.h" -#include "global/debug.h" -#include "ui/styling.h" -#include "ui/menu.h" - -LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) { - // set a default frame rate - fallback, shouldn't ever really be used - frame_rate = 30; - - decimal_places = 1; - drag_start = false; - drag_proc = false; - min_enabled = false; - max_enabled = false; - SetColor(); - SetDefaultCursor(); - internal_value = -1; - set = false; - display_type = Normal; - - SetDefault(0); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&))); -} - -void LabelSlider::SetFrameRate(double d) { - frame_rate = d; -} - -void LabelSlider::SetDecimalPlaces(int places) -{ - decimal_places = places; -} - -void LabelSlider::SetDisplayType(const DisplayType& type) { - display_type = type; - setText(ValueToString()); -} - -void LabelSlider::SetValue(double v) { - set = true; - if (!qFuzzyCompare(v, internal_value)) { - if (min_enabled && v < min_value) { - internal_value = min_value; - } else if (max_enabled && v > max_value) { - internal_value = max_value; - } else { - internal_value = v; - } - - setText(ValueToString()); - } -} - -bool LabelSlider::IsDragging() { - return drag_proc; -} - -QString LabelSlider::ValueToString() { - double v = internal_value; - if (qIsNaN(v)) { - return "---"; - } else { - switch (display_type) { - case FrameNumber: - return frame_to_timecode(long(v), olive::config.timecode_view, frame_rate); - case Percent: - return QString::number((v*100), 'f', decimal_places).append("%"); - case Decibel: - { - QString db_str; - - // -96 dB is considered -infinity - if (amplitude_to_db(v) <= -96) { - // hex sequence for -infinity - db_str = "-\xE2\x88\x9E"; - } else { - db_str = QString::number(amplitude_to_db(v), 'f', decimal_places); - } - - // add "dB" suffix - db_str.append(" dB"); - - return db_str; - } - default: - return QString::number(v, 'f', decimal_places); - } - } -} - -void LabelSlider::SetColor(QString c) { - if (c.isEmpty()) { - if (olive::styling::UseDarkIcons()) { - c = "#0080ff"; - } else { - c = "#ffc000"; - } - } - setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}"); -} - -double LabelSlider::value() { - return internal_value; -} - -void LabelSlider::SetDefault(double v) { - default_value = v; - if (!set) { - SetValue(v); - set = false; - } -} - -void LabelSlider::SetMinimum(double v) { - min_value = v; - min_enabled = true; -} - -void LabelSlider::SetMaximum(double v) { - max_value = v; - max_enabled = true; -} - -void LabelSlider::mousePressEvent(QMouseEvent *ev) { - // if primary button is clicked - if (ev->button() == Qt::LeftButton && !drag_start) { - - // store initial value to be compared while dragging - drag_start_value = internal_value; - - // alt + click sets labelslider to default value - if (ev->modifiers() & Qt::AltModifier) { - - // reset to default - ResetToDefault(); - - } else { - - // if value isn't valid, we set to a "default" of 0 - if (qIsNaN(internal_value)) internal_value = 0; - - // hide the cursor and store information about it for dragging - SetActiveCursor(); - - drag_start = true; - drag_start_x = cursor().pos().x(); - drag_start_y = cursor().pos().y(); - } - - emit clicked(); - - } else { - - // handler if the user clicks with a non-primary button - // prevents mouse from getting stuck in "dragging" mode - mouseReleaseEvent(ev); - - } -} - -void LabelSlider::mouseMoveEvent(QMouseEvent* event) { - if (drag_start) { - // if we're dragging - - // we don't actually start fully dragging until the cursor has moved - // while the mouse is down, this helps prevent accidental drags - drag_proc = true; - - // get amount cursor moved by - double diff = (cursor().pos().x()-drag_start_x) + (drag_start_y-cursor().pos().y()); - - // ctrl + drag drags in smaller increments - if (event->modifiers() & Qt::ControlModifier) diff *= 0.01; - - if (display_type == Percent) { - // we'll also need to drag in smaller increments for a percent value - - diff *= 0.01; - } - - // determine what the new value will be - double new_value; - - if (display_type == Decibel) { - // we move in terms of dB for decibel display - - new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff); - - } else { - // for most display types, just add the mouse difference - - new_value = internal_value + diff; - } - - // set internal value - SetValue(new_value); - emit valueChanged(internal_value); - - // keep the cursor in the same location while dragging - cursor().setPos(drag_start_x, drag_start_y); - } -} - -void LabelSlider::mouseReleaseEvent(QMouseEvent*) { - if (drag_start) { - - // unhide cursor - SetDefaultCursor(); - - drag_start = false; - - if (drag_proc) { - // if we just finished fully dragging - - drag_proc = false; - - emit valueChanged(internal_value); - - } else { - - ShowDialog(); - - } - } -} - -void LabelSlider::SetDefaultCursor() { - setCursor(Qt::SizeHorCursor); -} - -void LabelSlider::SetActiveCursor() { - setCursor(Qt::BlankCursor); -} - -void LabelSlider::ShowContextMenu(const QPoint &pos) -{ - Menu menu(this); - - menu.addAction(tr("&Edit"), this, SLOT(ShowDialog())); - - menu.addSeparator(); - - menu.addAction(tr("&Reset to Default"), this, SLOT(ResetToDefault())); - - menu.exec(mapToGlobal(pos)); -} - -void LabelSlider::ResetToDefault() -{ - // if the value is not already default, and there is a default to set - if (!qFuzzyCompare(internal_value, default_value) - && !qIsNaN(default_value)) { - - // set back to default - SetValue(default_value); - emit valueChanged(internal_value); - - } -} - -void LabelSlider::ShowDialog() -{ - // if the user didn't actually drag, and just clicked in one place, - // we instead present a dialog prompt for the user to enter a - // specific value - - double d = internal_value; - - if (display_type == FrameNumber) { - - // ask the user to enter a timecode - QString s = QInputDialog::getText( - this, - tr("Set Value"), - tr("New value:"), - QLineEdit::Normal, - ValueToString() - ); - if (s.isEmpty()) return; - - // parse string timecode to a frame number - d = timecode_to_frame(s, olive::config.timecode_view, frame_rate); - - } else { - - // ask the user to enter a normal number value - bool ok; - - // value to show - double shown_value = internal_value; - if (display_type == Percent) { - shown_value *= 100; - } else if (display_type == Decibel) { - shown_value = amplitude_to_db(shown_value); - } - - // set correct minimum value - double shown_minimum_value; - if (min_enabled) { - // if this field has a minimum value set, use it - shown_minimum_value = min_value; - } else if (display_type == Decibel) { - // minimum decibel amount is -96db - shown_minimum_value = -96; - } else { - // lowest possible minimum integer - shown_minimum_value = INT_MIN; - } - - // percentages are stored 0.0 - 1.0 but displayed as 0% - 100% - d = QInputDialog::getDouble( - this, - tr("Set Value"), - tr("New value:"), - shown_value, - shown_minimum_value, - (max_enabled) ? max_value : INT_MAX, - decimal_places, - &ok - ); - if (!ok) return; - - // convert shown value back to internal value - if (display_type == Percent) { - d *= 0.01; - } else if (display_type == Decibel) { - d = db_to_amplitude(d); - } - } - - // if the value actually changed, trigger a change event - if (!qFuzzyCompare(d, internal_value)) { - SetValue(d); - emit valueChanged(internal_value); - } -} diff --git a/ui/labelslider.h b/ui/labelslider.h deleted file mode 100644 index a52125c27..000000000 --- a/ui/labelslider.h +++ /dev/null @@ -1,231 +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 LABELSLIDER_H -#define LABELSLIDER_H - -#include -#include - -/** - * @brief The LabelSlider class - * - * A UI element that shows a number and can be dragged to increase/decrease its value or clicked to enter a specific - * one. - */ -class LabelSlider : public QLabel -{ - Q_OBJECT -public: - LabelSlider(QWidget* parent = nullptr); - - /** - * @brief Set the value - * @param v - * - * Value to set to. - * - * @param userSet - * - * **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The - * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and - * **FALSE** will not. - */ - void SetValue(double v); - - /** - * @brief Set the default value - * - * If a default value is set, alt+clicking the LabelSlider will return to the default value. - * - * @param v - * - * Value to set as default - */ - void SetDefault(double v); - - /** - * @brief Returns the internal value as a double - * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will - * return as 400%, and a timecode will return as a frame number. - */ - double value(); - - enum DisplayType { - Normal, - FrameNumber, - Percent, - Decibel - }; - - /** - * @brief Sets the way to display the value - * - * * `LABELSLIDER_NORMAL` - Shows the value as a normal number - * * `LABELSLIDER_FRAMENUMBER` - Shows the number as a timecode according to `config.timecode_view`. By default, - * will render hh:mm:ss:ff - * * `LABELSLIDER_PERCENT` - Shows the number as a percentage. 1.0 becomes "100%", 0.5 becomes 50%, etc. - * * `LABELSLIDER_DECIBLE` - Shows the number as a decibel. 1.0 becomes "0 dB", 2.0 becomes roughly "6 dB", 0.5 - * becomes roughly "-6 dB", etc. - * - * @param type - * - * The display type to set to. - */ - void SetDisplayType(const DisplayType& type); - - /** - * @brief Returns whether the user is currently dragging - * @return **TRUE** if the user is dragging, **FALSE** if not. - */ - bool IsDragging(); - - /** - * @brief Set the display color - * @param c - * - * Color to set to - */ - void SetColor(QString c = nullptr); - - /** - * @brief Set the display frame rate - * - * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the - * timecode will be in. - * - * @param d - */ - void SetFrameRate(double d); - - /** - * @brief Set how many decimal places to show for a floating-point number - * - * Defaults to 1 - */ - void SetDecimalPlaces(int places); -public slots: - /** - * @brief Set the minimum value - * - * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than - * the minimum, it will automatically snap to the minimum. - * - * @param v - * - * Value to set as minimum - */ - void SetMinimum(double v); - - /** - * @brief Set the maximum value - * - * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than - * the maximum, it will automatically snap to the maximum. - * - * @param v - * - * Value to set as maximum - */ - void SetMaximum(double v); - -protected: - void mousePressEvent(QMouseEvent *ev); - void mouseMoveEvent(QMouseEvent *ev); - void mouseReleaseEvent(QMouseEvent *ev); -private: - - /** - * @brief Convert the internal value to a displayed string according to `display_type` - * @return The internal value as a string - */ - QString ValueToString(); - - double default_value; - double internal_value; - double drag_start_value; - - int decimal_places; - - bool min_enabled; - double min_value; - bool max_enabled; - double max_value; - - bool drag_start; - bool drag_proc; - int drag_start_x; - int drag_start_y; - - bool set; - - DisplayType display_type; - - double frame_rate; - - /** - * @brief Internal function to set the standard cursor (usually SizeHorCursor) - */ - void SetDefaultCursor(); - - /** - * @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible) - */ - void SetActiveCursor(); -private slots: - /** - * @brief Context menu slot to be connected to QWidget::customContextMenuRequested(const QPoint&) - * - * @param pos - * - * Current cursor position - */ - void ShowContextMenu(const QPoint& pos); - - /** - * @brief Slot to reset current value to the default value - */ - void ResetToDefault(); - - /** - * @brief Show prompt asking for value - * - * Triggered when the user clicks on the LabelSlider without dragging or triggers right click > Edit. - * Will show an input dialog asking for a new value to be entered manually. Asks for units in the selected - * display type and converts them back to the internal value type. - */ - void ShowDialog(); -signals: - /** - * @brief valueChanged signal - * - * Emitted if the value changed at it was instigated by the user. - */ - void valueChanged(double d); - - /** - * @brief clicked signal - * - * Emitted if the user clicks on the LabelSlider in any way - */ - void clicked(); -}; - -#endif // LABELSLIDER_H diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp deleted file mode 100644 index a32f4dd7b..000000000 --- a/ui/mainwindow.cpp +++ /dev/null @@ -1,1230 +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 "mainwindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "ui/menuhelper.h" -#include "project/projectelements.h" -#include "timeline/clip.h" -#include "global/config.h" -#include "global/path.h" -#include "global/debug.h" -#include "project/proxygenerator.h" -#include "project/projectfilter.h" -#include "ui/sourcetable.h" -#include "ui/viewerwidget.h" -#include "ui/sourceiconview.h" -#include "ui/timelineheader.h" -#include "ui/icons.h" -#include "ui/cursors.h" -#include "ui/focusfilter.h" -#include "panels/panels.h" -#include "dialogs/debugdialog.h" -#include "rendering/audio.h" -#include "rendering/renderfunctions.h" -#include "undo/undostack.h" -#include "effects/effectloaders.h" - -MainWindow* olive::MainWindow; - -void MainWindow::setup_layout(bool reset) { - // load panels from file - if (!reset) { - QFile panel_config(get_config_dir().filePath("layout")); - if (panel_config.exists() && panel_config.open(QFile::ReadOnly)) { - - // default to resetting unless we find layout data in the XML file - reset = true; - - // read XML layout file - QXmlStreamReader stream(&panel_config); - - // loop through XML for all data - while (!stream.atEnd()) { - stream.readNext(); - - if (stream.name() == "panels" && stream.isStartElement()) { - - // element contains MainWindow layout data to restore - stream.readNext(); - restoreState(QByteArray::fromBase64(stream.text().toUtf8()), 0); - reset = false; - - } else if (stream.name() == "panel" && stream.isStartElement()) { - - // element contains layout data specific to a panel, we'll find the panel and load it - - // get panel name from XML attribute - QString panel_name; - const QXmlStreamAttributes& attributes = stream.attributes(); - for (int i=0;iobjectName() == panel_name) { - - // found the panel, so we can load its state - stream.readNext(); - panel->LoadLayoutState(QByteArray::fromBase64(stream.text().toUtf8())); - - // we found it, no more need to loop through panels - found_panel = true; - - break; - - } - - } - - if (!found_panel) { - qWarning() << "Panel specified in layout data doesn't exist. Layout wasn't loaded."; - } - - } - - } - - } - - panel_config.close(); - } else { - reset = true; - } - } - - if (reset) { - // remove all panels from the main window - for (int i=0;iraise(); - addDockWidget(Qt::TopDockWidgetArea, panel_sequence_viewer); - addDockWidget(Qt::BottomDockWidgetArea, panel_timeline.first()); - - panel_project.first()->show(); - panel_effect_controls->show(); - panel_footage_viewer->show(); - panel_sequence_viewer->show(); - panel_timeline.first()->show(); - panel_graph_editor->hide(); - panel_node_editor->hide(); - - panel_project.first()->setFloating(false); - panel_effect_controls->setFloating(false); - panel_footage_viewer->setFloating(false); - panel_sequence_viewer->setFloating(false); - panel_timeline.first()->setFloating(false); - panel_graph_editor->setFloating(true); - panel_node_editor->setFloating(true); - - resizeDocks({panel_project.first(), panel_footage_viewer, panel_sequence_viewer}, - {width()/3, width()/3, width()/3}, - Qt::Horizontal); - - resizeDocks({panel_project.first(), panel_timeline.first()}, - {height()/2, height()/2}, - Qt::Vertical); - } - - layout()->update(); -} - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - first_show(true) -{ - EffectInit::StartLoading(); - - olive::cursor::Initialize(); - - open_debug_file(); - - olive::DebugDialog = new DebugDialog(this); - - olive::MainWindow = this; - - QWidget* centralWidget = new QWidget(this); - centralWidget->setMaximumSize(QSize(0, 0)); - setCentralWidget(centralWidget); - - setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); - - setDockNestingEnabled(true); - - layout()->invalidate(); - - QString data_dir = get_data_path(); - if (!data_dir.isEmpty()) { - QDir dir(data_dir); - dir.mkpath("."); - if (dir.exists()) { - qint64 a_month_ago = QDateTime::currentMSecsSinceEpoch() - 2592000000; - qint64 a_week_ago = QDateTime::currentMSecsSinceEpoch() - 604800000; - - // TODO put delete functions in another thread? - - // delete auto-recoveries older than 7 days - QStringList old_autorecoveries = dir.entryList(QStringList("autorecovery.ove.*"), QDir::Files); - int deleted_ars = 0; - for (int i=0;i 0) qInfo() << "Deleted" << deleted_ars << "autorecovery" << ((deleted_ars == 1) ? "file that was" : "files that were") << "older than 7 days"; - - // delete previews older than 30 days - QDir preview_dir = QDir(dir.filePath("previews")); - if (preview_dir.exists()) { - deleted_ars = 0; - QStringList old_prevs = preview_dir.entryList(QDir::Files); - for (int i=0;i 0) qInfo() << "Deleted" << deleted_ars << "preview" << ((deleted_ars == 1) ? "file that was" : "files that were") << "last read over 30 days ago"; - } - - // search for open recents list - olive::Global->load_recent_projects(); - } - } - QString config_path = get_config_path(); - if (!config_path.isEmpty()) { - QDir config_dir(config_path); - config_dir.mkpath("."); - QString config_fn = config_dir.filePath("config.xml"); - if (QFileInfo::exists(config_fn)) { - olive::config.load(config_fn); - } - } - - Restyle(); - - olive::icon::Initialize(); - - // Load OpenColorIO configuration if set - if (olive::config.enable_color_management && !olive::config.ocio_config_path.isEmpty()) { - try { - OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(olive::config.ocio_config_path.toUtf8())); - } catch (OCIO::Exception& e) { - QMessageBox::critical(this, - tr("OpenColorIO Config Error"), - tr("Failed to set OpenColorIO configuration: %1").arg(e.what()), - QMessageBox::Ok); - } - } - - alloc_panels(this); - - // populate menu bars - setup_menus(); - - QStatusBar* statusBar = new QStatusBar(this); - statusBar->showMessage(tr("Welcome to %1").arg(olive::AppName)); - setStatusBar(statusBar); - - olive::Global->check_for_autorecovery_file(); - - // lock panels if the config says so - set_panels_locked(olive::config.locked_panels); - - // set up output audio device - init_audio(); - - // start omnipotent proxy generator process - olive::proxy_generator.start(); - - // load preferred language from file - olive::Global->load_translation_from_config(); - - // set default strings - Retranslate(); -} - -MainWindow::~MainWindow() { - free_panels(); - close_debug_file(); -} - -void kbd_shortcut_processor(QByteArray& file, QMenu* menu, bool save, bool first) { - QList actions = menu->actions(); - for (int i=0;imenu() != nullptr) { - kbd_shortcut_processor(file, a->menu(), save, first); - } else if (!a->isSeparator()) { - if (save) { - // saving custom shortcuts - if (!a->property("default").isNull()) { - QKeySequence defks(a->property("default").toString()); - if (a->shortcut() != defks) { - // custom shortcut - if (!file.isEmpty()) file.append('\n'); - file.append(a->property("id").toString()); - file.append('\t'); - file.append(a->shortcut().toString()); - } - } - } else { - // loading custom shortcuts - if (first) { - // store default shortcut - a->setProperty("default", a->shortcut().toString()); - } else { - // restore default shortcut - a->setShortcut(a->property("default").toString()); - } - if (!a->property("id").isNull()) { - QString comp_str = a->property("id").toString(); - int shortcut_index = file.indexOf(comp_str); - if (shortcut_index == 0 || (shortcut_index > 0 && file.at(shortcut_index-1) == '\n')) { - shortcut_index += comp_str.size() + 1; - QString shortcut; - while (shortcut_index < file.size() && file.at(shortcut_index) != '\n') { - shortcut.append(file.at(shortcut_index)); - shortcut_index++; - } - QKeySequence ks(shortcut); - if (!ks.isEmpty()) { - a->setShortcut(ks); - } - } - } - } - } - } -} - -void MainWindow::load_shortcuts(const QString& fn) { - QByteArray shortcut_bytes; - QFile shortcut_path(fn); - if (shortcut_path.exists() && shortcut_path.open(QFile::ReadOnly)) { - shortcut_bytes = shortcut_path.readAll(); - shortcut_path.close(); - } - QList menus = menuBar()->actions(); - for (int i=0;imenu(); - kbd_shortcut_processor(shortcut_bytes, menu, false, true); - } -} - -void MainWindow::save_shortcuts(const QString& fn) { - // save main menu actions - QList menus = menuBar()->actions(); - QByteArray shortcut_file; - for (int i=0;imenu(); - kbd_shortcut_processor(shortcut_file, menu, true, false); - } - QFile shortcut_file_io(fn); - if (shortcut_file_io.open(QFile::WriteOnly)) { - shortcut_file_io.write(shortcut_file); - shortcut_file_io.close(); - } else { - qCritical() << "Failed to save shortcut file"; - } -} - -bool MainWindow::load_css_from_file(const QString &fn) { - QFile css_file(fn); - if (css_file.exists() && css_file.open(QFile::ReadOnly)) { - setStyleSheet(css_file.readAll()); - css_file.close(); - return true; - } - return false; -} - -void MainWindow::Restyle() -{ - // Set up UI style - if (!olive::styling::UseNativeUI()) { - qApp->setStyle(QStyleFactory::create("Fusion")); - - // Set up whether to load custom CSS or default CSS+palette - if (!olive::config.css_path.isEmpty() - && load_css_from_file(olive::config.css_path)) { - - qApp->setPalette(qApp->style()->standardPalette()); - - } else { - - // set default palette - QPalette palette; - - if (olive::config.style == olive::styling::kOliveDefaultLight) { - - palette.setColor(QPalette::Window, QColor(208, 208, 208)); - palette.setColor(QPalette::WindowText, Qt::black); - palette.setColor(QPalette::Base, QColor(240, 240, 240)); - palette.setColor(QPalette::AlternateBase, QColor(208, 208, 208)); - palette.setColor(QPalette::ToolTipBase, QColor(255, 255, 255)); - palette.setColor(QPalette::ToolTipText, Qt::black); - palette.setColor(QPalette::Text, Qt::black); - palette.setColor(QPalette::Button, QColor(208, 208, 208)); - palette.setColor(QPalette::ButtonText, Qt::black); - palette.setColor(QPalette::BrightText, Qt::red); - palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(208, 208, 208)); - palette.setColor(QPalette::Link, QColor(42, 130, 218)); - palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); - palette.setColor(QPalette::HighlightedText, Qt::white); - - /* Olive Mid - palette.setColor(QPalette::Window, QColor(128, 128, 128)); - palette.setColor(QPalette::WindowText, Qt::black); - palette.setColor(QPalette::Base, QColor(192, 192, 192)); - palette.setColor(QPalette::AlternateBase, QColor(128, 128, 128)); - palette.setColor(QPalette::ToolTipBase, QColor(192, 192, 192)); - palette.setColor(QPalette::ToolTipText, Qt::black); - palette.setColor(QPalette::Text, Qt::black); - palette.setColor(QPalette::Button, QColor(128, 128, 128)); - palette.setColor(QPalette::ButtonText, Qt::black); - palette.setColor(QPalette::BrightText, Qt::red); - palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); - palette.setColor(QPalette::Link, QColor(42, 130, 218)); - palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); - palette.setColor(QPalette::HighlightedText, Qt::black); - */ - - } else { - - palette.setColor(QPalette::Window, QColor(53,53,53)); - palette.setColor(QPalette::WindowText, Qt::white); - palette.setColor(QPalette::Base, QColor(25,25,25)); - palette.setColor(QPalette::AlternateBase, QColor(53,53,53)); - palette.setColor(QPalette::ToolTipBase, QColor(25,25,25)); - palette.setColor(QPalette::ToolTipText, Qt::white); - palette.setColor(QPalette::Text, Qt::white); - palette.setColor(QPalette::Button, QColor(53,53,53)); - palette.setColor(QPalette::ButtonText, Qt::white); - palette.setColor(QPalette::BrightText, Qt::red); - palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); - palette.setColor(QPalette::Link, QColor(42, 130, 218)); - palette.setColor(QPalette::Highlight, QColor(42, 130, 218)); - palette.setColor(QPalette::HighlightedText, Qt::white); - - // 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::config.use_native_menu_styling) { -#endif - stylesheet.append("QMenu::separator { background: #404040; }"); -#ifdef Q_OS_WIN - } -#endif - setStyleSheet(stylesheet); - - } - - qApp->setPalette(palette); - - } - } -} - -void MainWindow::editMenu_About_To_Be_Shown() { - undo_action->setEnabled(olive::undo_stack.canUndo()); - redo_action->setEnabled(olive::undo_stack.canRedo()); -} - -void MainWindow::setup_menus() { - QMenuBar* menuBar = new QMenuBar(this); - - if (olive::config.use_native_menu_styling) { - OliveGlobal::SetNativeStyling(menuBar); - } - - setMenuBar(menuBar); - - olive::MenuHelper.InitializeSharedMenus(); - - // INITIALIZE FILE MENU - - file_menu = MenuHelper::create_submenu(menuBar, this, SLOT(fileMenu_About_To_Be_Shown())); - - new_menu = MenuHelper::create_submenu(file_menu); - olive::MenuHelper.make_new_menu(new_menu); - - open_project = MenuHelper::create_menu_action(file_menu, "openproj", olive::Global.get(), SLOT(OpenProject()), QKeySequence("Ctrl+O")); - - open_recent = MenuHelper::create_submenu(file_menu); - - clear_open_recent_action = MenuHelper::create_menu_action(nullptr, "clearopenrecent", olive::Global.get(), SLOT(clear_recent_projects())); - - save_project = MenuHelper::create_menu_action(file_menu, "saveproj", olive::Global.get(), SLOT(save_project()), QKeySequence("Ctrl+S")); - - save_project_as = MenuHelper::create_menu_action(file_menu, "saveprojas", olive::Global.get(), SLOT(save_project_as()), QKeySequence("Ctrl+Shift+S")); - - file_menu->addSeparator(); - - import_action = MenuHelper::create_menu_action(file_menu, "import", olive::Global.get(), SLOT(open_import_dialog()), QKeySequence("Ctrl+I")); - - file_menu->addSeparator(); - - export_action = MenuHelper::create_menu_action(file_menu, "export", olive::Global.get(), SLOT(open_export_dialog()), QKeySequence("Ctrl+M")); - - file_menu->addSeparator(); - - exit_action = MenuHelper::create_menu_action(file_menu, "exit", this, SLOT(close())); - - // INITIALIZE EDIT MENU - - edit_menu = MenuHelper::create_submenu(menuBar, this, SLOT(editMenu_About_To_Be_Shown())); - - undo_action = MenuHelper::create_menu_action(edit_menu, "undo", olive::Global.get(), SLOT(undo()), QKeySequence("Ctrl+Z")); - redo_action = MenuHelper::create_menu_action(edit_menu, "redo", olive::Global.get(), SLOT(redo()), QKeySequence("Ctrl+Shift+Z")); - - edit_menu->addSeparator(); - - olive::MenuHelper.make_edit_functions_menu(edit_menu); - - edit_menu->addSeparator(); - - select_all_action = MenuHelper::create_menu_action(edit_menu, "selectall", &olive::FocusFilter, SLOT(select_all()), QKeySequence("Ctrl+A")); - deselect_all_action = MenuHelper::create_menu_action(edit_menu, "deselectall", panel_timeline.first(), SLOT(deselect()), QKeySequence("Ctrl+Shift+A")); - - edit_menu->addSeparator(); - - olive::MenuHelper.make_clip_functions_menu(edit_menu); - - edit_menu->addSeparator(); - - ripple_to_in_point_ = MenuHelper::create_menu_action(edit_menu, "rippletoin", panel_timeline.first(), SLOT(ripple_to_in_point()), QKeySequence("Q")); - ripple_to_out_point_ = MenuHelper::create_menu_action(edit_menu, "rippletoout", panel_timeline.first(), SLOT(ripple_to_out_point()), QKeySequence("W")); - edit_to_in_point_ = MenuHelper::create_menu_action(edit_menu, "edittoin", panel_timeline.first(), SLOT(edit_to_in_point()), QKeySequence("Ctrl+Alt+Q")); - edit_to_out_point_ = MenuHelper::create_menu_action(edit_menu, "edittoout", panel_timeline.first(), SLOT(edit_to_out_point()), QKeySequence("Ctrl+Alt+W")); - - edit_menu->addSeparator(); - - olive::MenuHelper.make_inout_menu(edit_menu); - delete_inout_point_ = MenuHelper::create_menu_action(edit_menu, "deleteinout", panel_timeline.first(), SLOT(delete_inout()), QKeySequence(";")); - ripple_delete_inout_point_ = MenuHelper::create_menu_action(edit_menu, "rippledeleteinout", panel_timeline.first(), SLOT(ripple_delete_inout()), QKeySequence("'")); - - edit_menu->addSeparator(); - - setedit_marker_ = MenuHelper::create_menu_action(edit_menu, "marker", &olive::FocusFilter, SLOT(set_marker()), QKeySequence("M")); - - // INITIALIZE VIEW MENU - - view_menu = MenuHelper::create_submenu(menuBar, this, SLOT(viewMenu_About_To_Be_Shown())); - - zoom_in_ = MenuHelper::create_menu_action(view_menu, "zoomin", &olive::FocusFilter, SLOT(zoom_in()), QKeySequence("=")); - zoom_out_ = MenuHelper::create_menu_action(view_menu, "zoomout", &olive::FocusFilter, SLOT(zoom_out()), QKeySequence("-")); - increase_track_height_ = MenuHelper::create_menu_action(view_menu, "vzoomin", panel_timeline.first(), SLOT(IncreaseTrackHeight()), QKeySequence("Ctrl+=")); - decrease_track_height_ = MenuHelper::create_menu_action(view_menu, "vzoomout", panel_timeline.first(), SLOT(DecreaseTrackHeight()), QKeySequence("Ctrl+-")); - - show_all = MenuHelper::create_menu_action(view_menu, "showall", panel_timeline.first(), SLOT(toggle_show_all()), QKeySequence("\\")); - show_all->setCheckable(true); - - view_menu->addSeparator(); - - rectified_waveforms = MenuHelper::create_menu_action(view_menu, "rectifiedwaveforms", &olive::MenuHelper, SLOT(toggle_bool_action())); - rectified_waveforms->setCheckable(true); - rectified_waveforms->setData(reinterpret_cast(&olive::config.rectified_waveforms)); - - view_menu->addSeparator(); - - QActionGroup* frame_view_mode_group = new QActionGroup(this); - - frames_action = MenuHelper::create_menu_action(view_menu, "modeframes", &olive::MenuHelper, SLOT(set_timecode_view())); - frames_action->setData(olive::kTimecodeFrames); - frames_action->setCheckable(true); - frame_view_mode_group->addAction(frames_action); - - drop_frame_action = MenuHelper::create_menu_action(view_menu, "modedropframe", &olive::MenuHelper, SLOT(set_timecode_view())); - drop_frame_action->setData(olive::kTimecodeDrop); - drop_frame_action->setCheckable(true); - frame_view_mode_group->addAction(drop_frame_action); - - nondrop_frame_action = MenuHelper::create_menu_action(view_menu, "modenondropframe", &olive::MenuHelper, SLOT(set_timecode_view())); - nondrop_frame_action->setData(olive::kTimecodeNonDrop); - nondrop_frame_action->setCheckable(true); - frame_view_mode_group->addAction(nondrop_frame_action); - - milliseconds_action = MenuHelper::create_menu_action(view_menu, "milliseconds", &olive::MenuHelper, SLOT(set_timecode_view())); - milliseconds_action->setData(olive::kTimecodeMilliseconds); - milliseconds_action->setCheckable(true); - frame_view_mode_group->addAction(milliseconds_action); - - view_menu->addSeparator(); - - title_safe_area_menu = MenuHelper::create_submenu(view_menu); - - QActionGroup* title_safe_group = new QActionGroup(this); - - title_safe_off = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafeoff", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); - title_safe_off->setCheckable(true); - title_safe_off->setData(qSNaN()); - title_safe_group->addAction(title_safe_off); - - title_safe_default = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafedefault", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); - title_safe_default->setCheckable(true); - title_safe_default->setData(0.0); - title_safe_group->addAction(title_safe_default); - - title_safe_43 = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafe43", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); - title_safe_43->setCheckable(true); - title_safe_43->setData(4.0/3.0); - title_safe_group->addAction(title_safe_43); - - title_safe_169 = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafe169", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); - title_safe_169->setCheckable(true); - title_safe_169->setData(16.0/9.0); - title_safe_group->addAction(title_safe_169); - - title_safe_custom = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafecustom", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); - title_safe_custom->setCheckable(true); - title_safe_custom->setData(-1.0); - title_safe_group->addAction(title_safe_custom); - - view_menu->addSeparator(); - - full_screen = MenuHelper::create_menu_action(view_menu, "fullscreen", this, SLOT(toggle_full_screen()), QKeySequence("F11")); - full_screen->setCheckable(true); - - full_screen_viewer_ = MenuHelper::create_menu_action(view_menu, "fullscreenviewer", &olive::FocusFilter, SLOT(set_viewer_fullscreen())); - - // INITIALIZE PLAYBACK MENU - - playback_menu = MenuHelper::create_submenu(menuBar, this, SLOT(playbackMenu_About_To_Be_Shown())); - - go_to_start_ = MenuHelper::create_menu_action(playback_menu, "gotostart", &olive::FocusFilter, SLOT(go_to_start()), QKeySequence("Home")); - previous_frame_ = MenuHelper::create_menu_action(playback_menu, "prevframe", &olive::FocusFilter, SLOT(prev_frame()), QKeySequence("Left")); - playpause_ = MenuHelper::create_menu_action(playback_menu, "playpause", &olive::FocusFilter, SLOT(playpause()), QKeySequence("Space")); - play_in_to_out_ = MenuHelper::create_menu_action(playback_menu, "playintoout", &olive::FocusFilter, SLOT(play_in_to_out()), QKeySequence("Shift+Space")); - next_frame_ = MenuHelper::create_menu_action(playback_menu, "nextframe", &olive::FocusFilter, SLOT(next_frame()), QKeySequence("Right")); - go_to_end_ = MenuHelper::create_menu_action(playback_menu, "gotoend", &olive::FocusFilter, SLOT(go_to_end()), QKeySequence("End")); - - playback_menu->addSeparator(); - - go_to_prev_cut_ = MenuHelper::create_menu_action(playback_menu, "prevcut", panel_sequence_viewer, SLOT(prev_cut()), QKeySequence("Up")); - go_to_next_cut_ = MenuHelper::create_menu_action(playback_menu, "nextcut", panel_sequence_viewer, SLOT(next_cut()), QKeySequence("Down")); - - playback_menu->addSeparator(); - - go_to_in_point_ = MenuHelper::create_menu_action(playback_menu, "gotoin", &olive::FocusFilter, SLOT(go_to_in()), QKeySequence("Shift+I")); - go_to_out_point_ = MenuHelper::create_menu_action(playback_menu, "gotoout", &olive::FocusFilter, SLOT(go_to_out()), QKeySequence("Shift+O")); - - playback_menu->addSeparator(); - - shuttle_left_ = MenuHelper::create_menu_action(playback_menu, "decspeed", &olive::FocusFilter, SLOT(decrease_speed()), QKeySequence("J")); - shuttle_stop_ = MenuHelper::create_menu_action(playback_menu, "pause", &olive::FocusFilter, SLOT(pause()), QKeySequence("K")); - shuttle_right_ = MenuHelper::create_menu_action(playback_menu, "incspeed", &olive::FocusFilter, SLOT(increase_speed()), QKeySequence("L")); - - playback_menu->addSeparator(); - - loop_action_ = MenuHelper::create_menu_action(playback_menu, "loop", &olive::MenuHelper, SLOT(toggle_bool_action())); - loop_action_->setCheckable(true); - loop_action_->setData(reinterpret_cast(&olive::config.loop)); - - // INITIALIZE WINDOW MENU - - window_menu = MenuHelper::create_submenu(menuBar, this, SLOT(windowMenu_About_To_Be_Shown())); - - window_project_action = MenuHelper::create_menu_action(window_menu, "panelproject", this, SLOT(toggle_panel_visibility())); - window_project_action->setCheckable(true); - window_project_action->setData(reinterpret_cast(panel_project.first())); - - window_effectcontrols_action = MenuHelper::create_menu_action(window_menu, "paneleffectcontrols", this, SLOT(toggle_panel_visibility())); - window_effectcontrols_action->setCheckable(true); - window_effectcontrols_action->setData(reinterpret_cast(panel_effect_controls)); - - window_timeline_action = MenuHelper::create_menu_action(window_menu, "paneltimeline", this, SLOT(toggle_panel_visibility())); - window_timeline_action->setCheckable(true); - window_timeline_action->setData(reinterpret_cast(panel_timeline.first())); - - window_graph_editor_action = MenuHelper::create_menu_action(window_menu, "panelgrapheditor", this, SLOT(toggle_panel_visibility())); - window_graph_editor_action->setCheckable(true); - window_graph_editor_action->setData(reinterpret_cast(panel_graph_editor)); - - window_node_editor_action = MenuHelper::create_menu_action(window_menu, "panelnodeeditor", this, SLOT(toggle_panel_visibility())); - window_node_editor_action->setCheckable(true); - window_node_editor_action->setData(reinterpret_cast(panel_node_editor)); - - window_footageviewer_action = MenuHelper::create_menu_action(window_menu, "panelfootageviewer", this, SLOT(toggle_panel_visibility())); - window_footageviewer_action->setCheckable(true); - window_footageviewer_action->setData(reinterpret_cast(panel_footage_viewer)); - - window_sequenceviewer_action = MenuHelper::create_menu_action(window_menu, "panelsequenceviewer", this, SLOT(toggle_panel_visibility())); - window_sequenceviewer_action->setCheckable(true); - window_sequenceviewer_action->setData(reinterpret_cast(panel_sequence_viewer)); - - window_menu->addSeparator(); - - maximize_panel_ = MenuHelper::create_menu_action(window_menu, "maximizepanel", this, SLOT(maximize_panel()), QKeySequence("`")); - - lock_panels_ = MenuHelper::create_menu_action(window_menu, "lockpanels", this, SLOT(set_panels_locked(bool))); - lock_panels_->setCheckable(true); - - window_menu->addSeparator(); - - reset_default_layout_ = MenuHelper::create_menu_action(window_menu, "resetdefaultlayout", this, SLOT(reset_layout())); - - // INITIALIZE TOOLS MENU - - tools_menu = MenuHelper::create_submenu(menuBar, this, SLOT(toolMenu_About_To_Be_Shown())); - tools_menu->setToolTipsVisible(true); - - QActionGroup* tools_group = new QActionGroup(this); - - pointer_tool_action = MenuHelper::create_menu_action(tools_menu, "pointertool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("V")); - pointer_tool_action->setCheckable(true); - pointer_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolArrowButton)); - tools_group->addAction(pointer_tool_action); - - edit_tool_action = MenuHelper::create_menu_action(tools_menu, "edittool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("X")); - edit_tool_action->setCheckable(true); - edit_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolEditButton)); - tools_group->addAction(edit_tool_action); - - ripple_tool_action = MenuHelper::create_menu_action(tools_menu, "rippletool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("B")); - ripple_tool_action->setCheckable(true); - ripple_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolRippleButton)); - tools_group->addAction(ripple_tool_action); - - razor_tool_action = MenuHelper::create_menu_action(tools_menu, "razortool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("C")); - razor_tool_action->setCheckable(true); - razor_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolRazorButton)); - tools_group->addAction(razor_tool_action); - - slip_tool_action = MenuHelper::create_menu_action(tools_menu, "sliptool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("Y")); - slip_tool_action->setCheckable(true); - slip_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolSlipButton)); - tools_group->addAction(slip_tool_action); - - slide_tool_action = MenuHelper::create_menu_action(tools_menu, "slidetool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("U")); - slide_tool_action->setCheckable(true); - slide_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolSlideButton)); - tools_group->addAction(slide_tool_action); - - hand_tool_action = MenuHelper::create_menu_action(tools_menu, "handtool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("H")); - hand_tool_action->setCheckable(true); - hand_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolHandButton)); - tools_group->addAction(hand_tool_action); - - transition_tool_action = MenuHelper::create_menu_action(tools_menu, "transitiontool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("T")); - transition_tool_action->setCheckable(true); - transition_tool_action->setData(reinterpret_cast(panel_timeline.first()->toolTransitionButton)); - tools_group->addAction(transition_tool_action); - - tools_menu->addSeparator(); - - snap_toggle = MenuHelper::create_menu_action(tools_menu, "snapping", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("S")); - snap_toggle->setCheckable(true); - snap_toggle->setData(reinterpret_cast(panel_timeline.first()->snappingButton)); - - tools_menu->addSeparator(); - - autocut_silence_ = MenuHelper::create_menu_action(tools_menu, "autocutsilence", olive::Global.get(), SLOT(open_autocut_silence_dialog())); - - tools_menu->addSeparator(); - - QActionGroup* autoscroll_group = new QActionGroup(this); - - no_autoscroll = MenuHelper::create_menu_action(tools_menu, "autoscrollno", &olive::MenuHelper, SLOT(set_autoscroll())); - no_autoscroll->setData(olive::AUTOSCROLL_NO_SCROLL); - no_autoscroll->setCheckable(true); - autoscroll_group->addAction(no_autoscroll); - - page_autoscroll = MenuHelper::create_menu_action(tools_menu, "autoscrollpage", &olive::MenuHelper, SLOT(set_autoscroll())); - page_autoscroll->setData(olive::AUTOSCROLL_PAGE_SCROLL); - page_autoscroll->setCheckable(true); - autoscroll_group->addAction(page_autoscroll); - - smooth_autoscroll = MenuHelper::create_menu_action(tools_menu, "autoscrollsmooth", &olive::MenuHelper, SLOT(set_autoscroll())); - smooth_autoscroll->setData(olive::AUTOSCROLL_SMOOTH_SCROLL); - smooth_autoscroll->setCheckable(true); - autoscroll_group->addAction(smooth_autoscroll); - - tools_menu->addSeparator(); - - preferences_action_ = MenuHelper::create_menu_action(tools_menu, "prefs", olive::Global.get(), SLOT(open_preferences()), QKeySequence("Ctrl+,")); - -#ifdef QT_DEBUG - clear_undo_action_ = MenuHelper::create_menu_action(tools_menu, "clearundo", olive::Global.get(), SLOT(clear_undo_stack())); -#endif - - // INITIALIZE HELP MENU - - help_menu = MenuHelper::create_submenu(menuBar); - - action_search_ = MenuHelper::create_menu_action(help_menu, "actionsearch", olive::Global.get(), SLOT(open_action_search()), QKeySequence("/")); - - help_menu->addSeparator(); - - debug_log_ = MenuHelper::create_menu_action(help_menu, "debuglog", olive::Global.get(), SLOT(open_debug_log())); - - help_menu->addSeparator(); - - about_action_ = MenuHelper::create_menu_action(help_menu, "about", olive::Global.get(), SLOT(open_about_dialog())); - - load_shortcuts(get_config_path() + "/shortcuts"); -} - -void MainWindow::Retranslate() -{ - file_menu->setTitle(tr("&File")); - new_menu->setTitle(tr("&New")); - open_project->setText(tr("&Open Project")); - clear_open_recent_action->setText(tr("Clear Recent List")); - open_recent->setTitle(tr("Open Recent")); - save_project->setText(tr("&Save Project")); - save_project_as->setText(tr("Save Project &As")); - import_action->setText(tr("&Import...")); - export_action->setText(tr("&Export...")); - exit_action->setText(tr("E&xit")); - - edit_menu->setTitle(tr("&Edit")); - undo_action->setText(tr("&Undo")); - redo_action->setText(tr("Redo")); - select_all_action->setText(tr("Select &All")); - deselect_all_action->setText(tr("Deselect All")); - ripple_to_in_point_->setText(tr("Ripple to In Point")); - ripple_to_out_point_->setText(tr("Ripple to Out Point")); - edit_to_in_point_->setText(tr("Edit to In Point")); - edit_to_out_point_->setText(tr("Edit to Out Point")); - delete_inout_point_->setText(tr("Delete In/Out Point")); - ripple_delete_inout_point_->setText(tr("Ripple Delete In/Out Point")); - setedit_marker_->setText(tr("Set/Edit Marker")); - - view_menu->setTitle(tr("&View")); - zoom_in_->setText(tr("Zoom In")); - zoom_out_->setText(tr("Zoom Out")); - increase_track_height_->setText(tr("Increase Track Height")); - decrease_track_height_->setText(tr("Decrease Track Height")); - show_all->setText(tr("Toggle Show All")); - rectified_waveforms->setText(tr("Rectified Waveforms")); - frames_action->setText(tr("Frames")); - drop_frame_action->setText(tr("Drop Frame")); - nondrop_frame_action->setText(tr("Non-Drop Frame")); - milliseconds_action->setText(tr("Milliseconds")); - - title_safe_area_menu->setTitle(tr("Title/Action Safe Area")); - title_safe_off->setText(tr("Off")); - title_safe_default->setText(tr("Default")); - title_safe_43->setText(tr("4:3")); - title_safe_169->setText(tr("16:9")); - title_safe_custom->setText(tr("Custom")); - - full_screen->setText(tr("Full Screen")); - full_screen_viewer_->setText(tr("Full Screen Viewer")); - - playback_menu->setTitle(tr("&Playback")); - go_to_start_->setText(tr("Go to Start")); - previous_frame_->setText(tr("Previous Frame")); - playpause_->setText(tr("Play/Pause")); - play_in_to_out_->setText(tr("Play In to Out")); - next_frame_->setText(tr("Next Frame")); - go_to_end_->setText(tr("Go to End")); - - go_to_prev_cut_->setText(tr("Go to Previous Cut")); - go_to_next_cut_->setText(tr("Go to Next Cut")); - go_to_in_point_->setText(tr("Go to In Point")); - go_to_out_point_->setText(tr("Go to Out Point")); - - shuttle_left_->setText(tr("Shuttle Left")); - shuttle_stop_->setText(tr("Shuttle Stop")); - shuttle_right_->setText(tr("Shuttle Right")); - - loop_action_->setText(tr("Loop")); - - window_menu->setTitle(tr("&Window")); - - window_project_action->setText(tr("Project")); - window_effectcontrols_action->setText(tr("Effect Controls")); - window_timeline_action->setText(tr("Timeline")); - window_graph_editor_action->setText(tr("Graph Editor")); - window_node_editor_action->setText(tr("Node Editor")); - window_footageviewer_action->setText(tr("Media Viewer")); - window_sequenceviewer_action->setText(tr("Sequence Viewer")); - - maximize_panel_->setText(tr("Maximize Panel")); - lock_panels_->setText(tr("Lock Panels")); - reset_default_layout_->setText(tr("Reset to Default Layout")); - - tools_menu->setTitle(tr("&Tools")); - - pointer_tool_action->setText(tr("Pointer Tool")); - edit_tool_action->setText(tr("Edit Tool")); - ripple_tool_action->setText(tr("Ripple Tool")); - razor_tool_action->setText(tr("Razor Tool")); - slip_tool_action->setText(tr("Slip Tool")); - slide_tool_action->setText(tr("Slide Tool")); - hand_tool_action->setText(tr("Hand Tool")); - transition_tool_action->setText(tr("Transition Tool")); - snap_toggle->setText(tr("Enable Snapping")); - autocut_silence_->setText(tr("Auto-Cut Silence")); - - no_autoscroll->setText(tr("No Auto-Scroll")); - page_autoscroll->setText(tr("Page Auto-Scroll")); - smooth_autoscroll->setText(tr("Smooth Auto-Scroll")); - - preferences_action_->setText(tr("Preferences")); -#ifdef QT_DEBUG - clear_undo_action_->setText(tr("Clear Undo")); -#endif - - help_menu->setTitle(tr("&Help")); - - action_search_->setText(tr("A&ction Search")); - debug_log_->setText(tr("Debug Log")); - about_action_->setText(tr("&About...")); - - panel_sequence_viewer->set_panel_name(QCoreApplication::translate("Viewer", "Sequence Viewer: %1")); - panel_footage_viewer->set_panel_name(QCoreApplication::translate("Viewer", "Media Viewer: %1")); - - // the recommended changeEvent() and event() methods of propagating language change messages provided mixed results - // (i.e. different panels failed to translate in different sessions), so we translate them manually here - for (int i=0;iRetranslate(); - } - olive::MenuHelper.Retranslate(); - - updateTitle(); -} - -void MainWindow::updateTitle() { - setWindowTitle(QString("%1 - %2[*]").arg(olive::AppName, - (olive::ActiveProjectFilename.isEmpty()) ? - tr("") : olive::ActiveProjectFilename) - ); -} - -void MainWindow::closeEvent(QCloseEvent *e) { - if (olive::Global->can_close_project()) { - // stop proxy generator thread - olive::proxy_generator.cancel(); - - panel_graph_editor->set_row(nullptr); - panel_effect_controls->Clear(true); - - panel_footage_viewer->viewer_widget()->close_window(); - panel_sequence_viewer->viewer_widget()->close_window(); - - olive::undo_stack.clear(); - - QString data_dir = get_data_path(); - QString config_path = get_config_path(); - - const QString& autorecovery_filename = olive::Global->get_autorecovery_filename(); - if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) { - if (QFile::exists(autorecovery_filename)) { - QFile::rename(autorecovery_filename, - autorecovery_filename + "." + QDateTime::currentDateTimeUtc().toString("yyyyMMddHHmmss")); - } - } - if (!config_path.isEmpty()) { - QDir config_dir = QDir(config_path); - - QString config_fn = config_dir.filePath("config.xml"); - - // save settings - olive::config.save(config_fn); - - // save panel layout - QFile panel_config(get_config_dir().filePath("layout")); - if (panel_config.open(QFile::WriteOnly)) { - QXmlStreamWriter stream(&panel_config); - stream.setAutoFormatting(true); - stream.writeStartDocument(); - - stream.writeStartElement("layout"); - - stream.writeTextElement("panels", saveState(0).toBase64()); - - // if the panels have any specific layout data to save, save it now - for (int i=0;iSaveLayoutState(); - - if (!layout_data.isEmpty()) { - - // layout data is matched with the panel's objectName(), which we can't do if the panel has no name - const QString& panel_name = olive::panels.at(i)->objectName(); - if (panel_name.isEmpty()) { - qWarning() << "Panel" << i << "had layout state data but no objectName(). Layout was not saved."; - } else { - stream.writeStartElement("panel"); - - stream.writeAttribute("name", panel_name); - - stream.writeCharacters(layout_data.toBase64()); - - stream.writeEndElement(); - } - } - } - - stream.writeEndElement(); // layout - - stream.writeEndDocument(); - panel_config.close(); - } else { - qCritical() << "Failed to save layout"; - } - - save_shortcuts(config_path + "/shortcuts"); - } - - stop_audio(); - - e->accept(); - } else { - e->ignore(); - } -} - -void MainWindow::paintEvent(QPaintEvent *event) { - QMainWindow::paintEvent(event); - - if (first_show) { - // set this to false immediately to prevent anything here being called again - first_show = false; - - /** - * @brief Set up the dock widget layout on the main window - * - * For some reason, Qt didn't like this in the constructor. It would lead to several geometry issues with HiDPI - * on Windows, and also seemed to break QMainWindow::restoreState() which is why it took so long to implement - * saving/restoring panel layouts. Putting it in showEvent() didn't help either, nor did putting it in - * changeEvent() (QEvent::type() == QEvent::Polish). This is the only place it's functioned as expected. - */ - setup_layout(false); - - /** - Signal that window has finished loading. - */ - emit finished_first_paint(); - } -} - -void MainWindow::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - - // if this was a LanguageEvent, run the retranslation function - Retranslate(); - - } else { - - // otherwise pass it to the base class - QMainWindow::changeEvent(e); - - } -} - -void MainWindow::reset_layout() { - setup_layout(true); -} - -void MainWindow::maximize_panel() { - // toggles between normal state and a state of one panel being maximized - if (temp_panel_state.isEmpty()) { - // get currently hovered panel - QDockWidget* focused_panel = get_focused_panel(true); - - // if the mouse is in fact hovering over a panel - if (focused_panel != nullptr) { - // store the current state of panels - temp_panel_state = saveState(); - - // remove all dock widgets that aren't the hovered panel - for (int i=0;isetVisible(false); - - // set it to floating - olive::panels.at(i)->setFloating(true); - } - } - } - } else { - // we must be maximized, restore previous state - restoreState(temp_panel_state); - - // clear temp panel state for next maximize call - temp_panel_state.clear(); - } -} - -void MainWindow::windowMenu_About_To_Be_Shown() { - QList window_actions = window_menu->actions(); - for (int i=0;idata().isNull()) { - a->setChecked(reinterpret_cast(a->data().value())->isVisible()); - } - } - - lock_panels_->setChecked(olive::config.locked_panels); -} - -void MainWindow::playbackMenu_About_To_Be_Shown() { - olive::MenuHelper.set_bool_action_checked(loop_action_); -} - -void MainWindow::viewMenu_About_To_Be_Shown() { - olive::MenuHelper.set_bool_action_checked(rectified_waveforms); - - olive::MenuHelper.set_int_action_checked(frames_action, olive::config.timecode_view); - olive::MenuHelper.set_int_action_checked(drop_frame_action, olive::config.timecode_view); - olive::MenuHelper.set_int_action_checked(nondrop_frame_action, olive::config.timecode_view); - olive::MenuHelper.set_int_action_checked(milliseconds_action, olive::config.timecode_view); - - title_safe_off->setChecked(!olive::config.show_title_safe_area); - title_safe_default->setChecked(olive::config.show_title_safe_area - && !olive::config.use_custom_title_safe_ratio); - title_safe_43->setChecked(olive::config.show_title_safe_area - && olive::config.use_custom_title_safe_ratio - && qFuzzyCompare(olive::config.custom_title_safe_ratio, title_safe_43->data().toDouble())); - title_safe_169->setChecked(olive::config.show_title_safe_area - && olive::config.use_custom_title_safe_ratio - && qFuzzyCompare(olive::config.custom_title_safe_ratio, title_safe_169->data().toDouble())); - title_safe_custom->setChecked(olive::config.show_title_safe_area - && olive::config.use_custom_title_safe_ratio - && !title_safe_43->isChecked() - && !title_safe_169->isChecked()); - - full_screen->setChecked(windowState() == Qt::WindowFullScreen); - - show_all->setChecked(panel_timeline.first()->showing_all); -} - -void MainWindow::toolMenu_About_To_Be_Shown() { - olive::MenuHelper.set_button_action_checked(pointer_tool_action); - olive::MenuHelper.set_button_action_checked(edit_tool_action); - olive::MenuHelper.set_button_action_checked(ripple_tool_action); - olive::MenuHelper.set_button_action_checked(razor_tool_action); - olive::MenuHelper.set_button_action_checked(slip_tool_action); - olive::MenuHelper.set_button_action_checked(slide_tool_action); - olive::MenuHelper.set_button_action_checked(hand_tool_action); - olive::MenuHelper.set_button_action_checked(transition_tool_action); - olive::MenuHelper.set_button_action_checked(snap_toggle); - - olive::MenuHelper.set_int_action_checked(no_autoscroll, olive::config.autoscroll); - olive::MenuHelper.set_int_action_checked(page_autoscroll, olive::config.autoscroll); - olive::MenuHelper.set_int_action_checked(smooth_autoscroll, olive::config.autoscroll); -} - -void MainWindow::toggle_panel_visibility() { - QAction* action = static_cast(sender()); - QDockWidget* w = reinterpret_cast(action->data().value()); - w->setVisible(!w->isVisible()); - - // layout has changed, we're no longer in maximized panel mode, - // so we clear this byte array - temp_panel_state.clear(); -} - -void MainWindow::set_panels_locked(bool locked) -{ - for (int i=0;isetFeatures(panel->features() & ~QDockWidget::DockWidgetMovable); - - // hide the title bar (only real way to do this is to replace it with an empty QWidget) - panel->setTitleBarWidget(new QWidget(panel)); - } else { - // re-enable moving on QDockWidget - panel->setFeatures(panel->features() | QDockWidget::DockWidgetMovable); - - // set the "custom" titlebar to null so the default gets restored - panel->setTitleBarWidget(nullptr); - } - } - - olive::config.locked_panels = locked; -} - -void MainWindow::fileMenu_About_To_Be_Shown() { - if (olive::Global->recent_project_count() > 0) { - open_recent->clear(); - open_recent->setEnabled(true); - for (int i=0;irecent_project_count();i++) { - QAction* action = open_recent->addAction(olive::Global->recent_project(i)); - action->setProperty("keyignore", true); - action->setData(i); - connect(action, SIGNAL(triggered()), &olive::MenuHelper, SLOT(open_recent_from_menu())); - } - open_recent->addSeparator(); - - open_recent->addAction(clear_open_recent_action); - } else { - open_recent->setEnabled(false); - } -} - -void MainWindow::toggle_full_screen() { - if (windowState() == Qt::WindowFullScreen) { - setWindowState(Qt::WindowNoState); // seems to be necessary for it to return to Maximized correctly on Linux - setWindowState(Qt::WindowMaximized); - } else { - setWindowState(Qt::WindowFullScreen); - } -} diff --git a/ui/mainwindow.h b/ui/mainwindow.h deleted file mode 100644 index 9bb0c2c45..000000000 --- a/ui/mainwindow.h +++ /dev/null @@ -1,353 +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 MAINWINDOW_H -#define MAINWINDOW_H - -#include - -class Project; -class EffectControls; -class Viewer; -class Timeline; - -class MainWindow : public QMainWindow { - Q_OBJECT -public: - explicit MainWindow(QWidget *parent); - virtual ~MainWindow() override; - - /** - * @brief Update window title - * - * Updates the window title to reflect the current project filename. Call if the project filename changes. - * - * NOTE: It's recommended to use update_project_filename() from Olive::Global to update the filename completely - * instead of calling this function directly (update_project_filename() calls this function in the process). - */ - void updateTitle(); - - /** - * @brief Load shortcut file. - * - * Loads a shortcut configuration from file and sets Olive to use them. - * - * @param fn - * - * URL of the shortcut file to be loaded - * - */ - void load_shortcuts(const QString &fn); - - /** - * @brief Save shortcut file. - * - * Saves the current shortcut configuration to file. Only saves shortcuts that have been changed from default. - * - * @param fn - * - * URL to save the shortcut file to. - */ - void save_shortcuts(const QString &fn); - - /** - * @brief Load a CSS/QSS style from file to customize Olive's interface. - * - * @param fn - * - * URL to load the CSS file from. - * - * @return - * - * **TRUE** if CSS was successfully loaded. - */ - bool load_css_from_file(const QString& fn); - - /** - * @brief Set application's QStyle based on values from Config - */ - void Restyle(); - -public slots: - /** - * @brief Toggles full screen mode. - * - * Toggles the main window between full screen and windowed modes. - */ - void toggle_full_screen(); - -signals: - /** - * @brief Signal emitted once when the main window has finished initializing - * - * Emitted the first time paintEvent runs. Connect this to functions that must be completed post-initialization. - */ - void finished_first_paint(); - -protected: - /** - * @brief Close event - * - * Confirms whether the project can be closed, and if so performs various clean-up functions before the application - * exits. It's preferable to call clean-up functions here rather than in the destructor because this will get called - * first. - */ - virtual void closeEvent(QCloseEvent *) override; - - /** - * @brief Paint event - * - * Overridden to provide the finished_first_paint() signal. - */ - virtual void paintEvent(QPaintEvent *) override; - - /** - * @brief Change event - * - * Overridden to handle language changes (e->type() == QEvent::LanguageChange) by calling Retranslate(). - * - * See documentation for QWidget::changeEvent() for more information. - * - * @param e - * @return - */ - virtual void changeEvent(QEvent* e) override; - -private slots: - /** - * @brief Maximizes the currently hovered panel. - * - * Saves the current state of the panels/dock widgets and removes all except the currently hovered panel, - * effectively maximizing the panel to the entire window. - */ - void maximize_panel(); - - /** - * @brief Reset panel layout to default. - * - * Resets the current panel layout to default. Doesn't save the current layout. - */ - void reset_layout(); - - /** - * @brief Function to prepare File menu. - * - * Primarily used to populate the Open Recent Projects menu. - */ - void fileMenu_About_To_Be_Shown(); - - /** - * @brief Function to prepare Edit menu. - * - * Primarily used to set the enabled state on Undo and Redo depending if there are undos/redos available. - */ - void editMenu_About_To_Be_Shown(); - - /** - * @brief Function to prepare Window menu. - * - * Primarily used to set the checked state of menu items corresponding to the panels that are currently visible. - */ - void windowMenu_About_To_Be_Shown(); - - /** - * @brief Function to prepare Playback menu. - * - * Primarily used to set the checked state on the "Loop" item. - */ - void playbackMenu_About_To_Be_Shown(); - - /** - * @brief Function to prepare View menu. - * - * Primarily used to set the checked state of various options in the view menu (e.g. title safe area, timecode - * units, etc.) - */ - void viewMenu_About_To_Be_Shown(); - - /** - * @brief Function to prepare Tools menu. - * - * Primarily used to set the checked state on various settings available from the Tools menu. - */ - void toolMenu_About_To_Be_Shown(); - - /** - * @brief Toggle whether a panel is visible or not. - * - * Assumes the sender() QAction has a pointer to a QDockWidget in its data variable. Casts it and toggles its - * visibility. - */ - void toggle_panel_visibility(); - - /** - * @brief Set panel lock - * - * @param locked - * - * If **TRUE** prevents panels from being moved around. Defaults to **FALSE**. - */ - void set_panels_locked(bool locked); - -private: - /** - * @brief Internal function for setting the panel layout to a predetermined preset. - * - * Resets layout to default and optionally loads a layout from file. If loading from file, this function will - * always load from `get_config_path() + "/layout"`. - * - * @param reset - * - * **TRUE** if this function should just reset the current layout. **FALSE** if it should load from the - * aforementioned layout file. - */ - void setup_layout(bool reset); - - /** - * @brief Initialize menu bar menus and items. - * - * Internal initialization function for all menus and menu items in the main window. Called once from the - * MainWindow() constructor. - */ - void setup_menus(); - - void Retranslate(); - - // file menu actions - QMenu* file_menu; - QMenu* new_menu; - QAction* open_project; - QMenu* open_recent; - QAction* open_action; - QAction* clear_open_recent_action; - QAction* save_project; - QAction* save_project_as; - QAction* import_action; - QAction* export_action; - QAction* exit_action; - - // edit menu actions - QMenu* edit_menu; - QAction* undo_action; - QAction* redo_action; - QAction* select_all_action; - QAction* deselect_all_action; - QAction* ripple_to_in_point_; - QAction* ripple_to_out_point_; - QAction* edit_to_in_point_; - QAction* edit_to_out_point_; - QAction* delete_inout_point_; - QAction* ripple_delete_inout_point_; - QAction* setedit_marker_; - - // view menu actions - QMenu* view_menu; - QAction* zoom_in_; - QAction* zoom_out_; - QAction* increase_track_height_; - QAction* decrease_track_height_; - QAction* frames_action; - QAction* drop_frame_action; - QAction* nondrop_frame_action; - QAction* milliseconds_action; - QAction* no_autoscroll; - QAction* page_autoscroll; - QAction* smooth_autoscroll; - - QMenu* title_safe_area_menu; - QAction* title_safe_off; - QAction* title_safe_default; - QAction* title_safe_43; - QAction* title_safe_169; - QAction* title_safe_custom; - - QAction* full_screen; - QAction* full_screen_viewer_; - QAction* show_all; - - // playback menu - QMenu* playback_menu; - - QAction* go_to_start_; - QAction* previous_frame_; - QAction* playpause_; - QAction* play_in_to_out_; - QAction* next_frame_; - QAction* go_to_end_; - QAction* go_to_prev_cut_; - QAction* go_to_next_cut_; - QAction* go_to_in_point_; - QAction* go_to_out_point_; - QAction* shuttle_left_; - QAction* shuttle_stop_; - QAction* shuttle_right_; - QAction* loop_action_; - - // window menu - - QMenu* window_menu; - - QAction* window_project_action; - QAction* window_effectcontrols_action; - QAction* window_timeline_action; - QAction* window_graph_editor_action; - QAction* window_node_editor_action; - QAction* window_footageviewer_action; - QAction* window_sequenceviewer_action; - - QAction* maximize_panel_; - QAction* lock_panels_; - QAction* reset_default_layout_; - - // tools menu - QMenu* tools_menu; - - QAction* pointer_tool_action; - QAction* edit_tool_action; - QAction* ripple_tool_action; - QAction* razor_tool_action; - QAction* slip_tool_action; - QAction* slide_tool_action; - QAction* hand_tool_action; - QAction* transition_tool_action; - QAction* snap_toggle; - QAction* rectified_waveforms; - QAction* autocut_silence_; - QAction* preferences_action_; - QAction* clear_undo_action_; - - // help menu - QMenu* help_menu; - QAction* action_search_; - QAction* debug_log_; - QAction* about_action_; - - // used to store the panel state when one panel is maximized - QByteArray temp_panel_state; - - // used in paintEvent() to determine the first paintEvent() performed - bool first_show; -}; - -namespace olive { -extern MainWindow* MainWindow; -} - -#endif // MAINWINDOW_H diff --git a/ui/mediaiconservice.cpp b/ui/mediaiconservice.cpp deleted file mode 100644 index ff8483891..000000000 --- a/ui/mediaiconservice.cpp +++ /dev/null @@ -1,105 +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 "mediaiconservice.h" - -const int kThrobberLimit = 20; -const int kThrobberSize = 50; - -#include "project/projectmodel.h" -#include "ui/icons.h" - -std::unique_ptr olive::media_icon_service; - -MediaIconService::MediaIconService() { - // set up animation timer - throbber_animator_.setInterval(20); - connect(&throbber_animator_, SIGNAL(timeout()), this, SLOT(AnimationUpdate())); - - // set up pixmap - throbber_pixmap_ = QPixmap(":/icons/throbber.png"); -} - -void MediaIconService::SetMediaIcon(Media *media, IconType icon_type) { - // if this icon is already part of the throbber animation loop, remove it - if (throbber_items_.contains(media)) { - throbber_lock_.lock(); - - throbber_items_.removeAll(media); - media->disable_thumbnail(false); - - throbber_lock_.unlock(); - - // if we aren't animating anything, no need to run the timer for now - if (throbber_items_.empty()) { - // ensure timer function is called in its own thread - QMetaObject::invokeMethod(&throbber_animator_, "stop", Qt::QueuedConnection); - } - } - - switch (icon_type) { - case ICON_TYPE_VIDEO: - olive::project_model.set_icon(media, olive::icon::MediaVideo); - break; - case ICON_TYPE_AUDIO: - olive::project_model.set_icon(media, olive::icon::MediaAudio); - break; - case ICON_TYPE_IMAGE: - olive::project_model.set_icon(media, olive::icon::MediaImage); - break; - case ICON_TYPE_LOADING: - throbber_items_.append(media); - - media->disable_thumbnail(true); - - // if the animation timer isn't running, start it - if (!throbber_animator_.isActive()) { - // set starting frame to 0 - throbber_animation_frame_ = 0; - - // ensure timer function is called in its own thread - QMetaObject::invokeMethod(&throbber_animator_, "start", Qt::QueuedConnection); - } - break; - case ICON_TYPE_ERROR: - olive::project_model.set_icon(media, olive::icon::MediaError); - break; - } - - emit IconChanged(); -} - -void MediaIconService::AnimationUpdate() { - if (throbber_animation_frame_ == kThrobberLimit) { - throbber_animation_frame_ = 0; - } - - QIcon throbber_ico = QIcon(throbber_pixmap_.copy(kThrobberSize*throbber_animation_frame_, 0, kThrobberSize, kThrobberSize)); - - throbber_lock_.lock(); - - for (int i=0;i. - -***/ - -#ifndef MEDIAICONSERVICE_H -#define MEDIAICONSERVICE_H - -#include -#include -#include - -#include "project/media.h" - -enum IconType { - ICON_TYPE_VIDEO, - ICON_TYPE_AUDIO, - ICON_TYPE_IMAGE, - ICON_TYPE_LOADING, - ICON_TYPE_ERROR -}; - -class MediaIconService : public QObject { - Q_OBJECT -public: - MediaIconService(); -public slots: - void SetMediaIcon(Media* media, IconType icon_type); -signals: - void IconChanged(); -private slots: - void AnimationUpdate(); -private: - int throbber_animation_frame_; - QVector throbber_items_; - QTimer throbber_animator_; - QPixmap throbber_pixmap_; - QMutex throbber_lock_; -}; - -namespace olive { -extern std::unique_ptr media_icon_service; -} - -#endif // MEDIAICONSERVICE_H diff --git a/ui/menu.cpp b/ui/menu.cpp deleted file mode 100644 index f81973be7..000000000 --- a/ui/menu.cpp +++ /dev/null @@ -1,40 +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 "menu.h" - -#include "global/global.h" -#include "global/config.h" - -Menu::Menu(QWidget *parent) : - QMenu(parent) -{ - if (olive::config.use_native_menu_styling) { - OliveGlobal::SetNativeStyling(this); - } -} - -Menu::Menu(const QString &title, QWidget *parent) : - QMenu(title, parent) -{ - if (olive::config.use_native_menu_styling) { - OliveGlobal::SetNativeStyling(this); - } -} diff --git a/ui/menu.h b/ui/menu.h deleted file mode 100644 index f7e542a09..000000000 --- a/ui/menu.h +++ /dev/null @@ -1,33 +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 MENU_H -#define MENU_H - -#include - -class Menu : public QMenu -{ -public: - Menu(QWidget* parent = nullptr); - Menu(const QString &title, QWidget *parent = nullptr); -}; - -#endif // MENU_H diff --git a/ui/menuhelper.cpp b/ui/menuhelper.cpp deleted file mode 100644 index 4ad3359db..000000000 --- a/ui/menuhelper.cpp +++ /dev/null @@ -1,325 +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 "menuhelper.h" - -#include -#include -#include -#include - -#include "global/config.h" -#include "global/clipboard.h" -#include "ui/mainwindow.h" -#include "global/global.h" -#include "panels/panels.h" -#include "ui/focusfilter.h" - -MenuHelper olive::MenuHelper; - -void MenuHelper::InitializeSharedMenus() -{ - new_project_ = create_menu_action(nullptr, "newproj", olive::Global.get(), SLOT(new_project()), QKeySequence("Ctrl+N")); - new_project_->setParent(this); - - new_sequence_ = create_menu_action(nullptr, "newseq", olive::Global.get(), SLOT(open_new_sequence_dialog()), QKeySequence("Ctrl+Shift+N")); - new_sequence_->setParent(this); - - new_folder_ = create_menu_action(nullptr, "newfolder", panel_project.first(), SLOT(new_folder())); - new_folder_->setParent(this); - - set_in_point_ = create_menu_action(nullptr, "setinpoint", &olive::FocusFilter, SLOT(set_in_point()), QKeySequence("I")); - set_in_point_->setParent(this); - - set_out_point_ = create_menu_action(nullptr, "setoutpoint", &olive::FocusFilter, SLOT(set_out_point()), QKeySequence("O")); - set_out_point_->setParent(this); - - reset_in_point_ = create_menu_action(nullptr, "resetin", &olive::FocusFilter, SLOT(clear_in())); - reset_in_point_->setParent(this); - - reset_out_point_ = create_menu_action(nullptr, "resetout", &olive::FocusFilter, SLOT(clear_out())); - reset_out_point_->setParent(this); - - clear_inout_point = create_menu_action(nullptr, "clearinout", &olive::FocusFilter, SLOT(clear_inout()), QKeySequence("G")); - clear_inout_point->setParent(this); - - add_default_transition_ = create_menu_action(nullptr, "deftransition", panel_timeline.first(), SLOT(add_transition()), QKeySequence("Ctrl+Shift+D")); - add_default_transition_->setParent(this); - - link_unlink_ = create_menu_action(nullptr, "linkunlink", panel_timeline.first(), SLOT(toggle_links()), QKeySequence("Ctrl+L")); - link_unlink_->setParent(this); - - enable_disable_ = create_menu_action(nullptr, "enabledisable", panel_timeline.first(), SLOT(toggle_enable_on_selected_clips()), QKeySequence("Shift+E")); - enable_disable_->setParent(this); - - nest_ = create_menu_action(nullptr, "nest", panel_timeline.first(), SLOT(nest())); - nest_->setParent(this); - - cut_ = create_menu_action(nullptr, "cut", &olive::FocusFilter, SLOT(cut()), QKeySequence("Ctrl+X")); - cut_->setParent(this); - - copy_ = create_menu_action(nullptr, "copy", &olive::FocusFilter, SLOT(copy()), QKeySequence("Ctrl+C")); - copy_->setParent(this); - - paste_ = create_menu_action(nullptr, "paste", olive::Global.get(), SLOT(paste()), QKeySequence("Ctrl+V")); - paste_->setParent(this); - - paste_insert_ = create_menu_action(nullptr, "pasteinsert", olive::Global.get(), SLOT(paste_insert()), QKeySequence("Ctrl+Shift+V")); - paste_insert_->setParent(this); - - duplicate_ = create_menu_action(nullptr, "duplicate", &olive::FocusFilter, SLOT(duplicate()), QKeySequence("Ctrl+D")); - duplicate_->setParent(this); - - delete_ = create_menu_action(nullptr, "delete", &olive::FocusFilter, SLOT(delete_function()), QKeySequence("Del")); - delete_->setParent(this); - - ripple_delete_ = create_menu_action(nullptr, "rippledelete", panel_timeline.first(), SLOT(ripple_delete()), QKeySequence("Shift+Del")); - ripple_delete_->setParent(this); - - split_ = create_menu_action(nullptr, "split", panel_timeline.first(), SLOT(split_at_playhead()), QKeySequence("Ctrl+K")); - split_->setParent(this); - - Retranslate(); -} - -void MenuHelper::make_new_menu(QMenu *parent) { - parent->addAction(new_project_); - parent->addSeparator(); - parent->addAction(new_sequence_); - parent->addAction(new_folder_); -} - -void MenuHelper::make_inout_menu(QMenu *parent) { - parent->addAction(set_in_point_); - parent->addAction(set_out_point_); - parent->addSeparator(); - parent->addAction(reset_in_point_); - parent->addAction(reset_out_point_); - parent->addAction(clear_inout_point); -} - -void MenuHelper::make_clip_functions_menu(QMenu *parent) { - parent->addAction(add_default_transition_); - parent->addAction(link_unlink_); - parent->addAction(enable_disable_); - parent->addAction(nest_); -} - -void MenuHelper::make_edit_functions_menu(QMenu *parent, bool objects_are_selected) { - if (objects_are_selected) { - parent->addAction(cut_); - parent->addAction(copy_); - } - - parent->addAction(paste_); - parent->addAction(paste_insert_); - - if (objects_are_selected) { - parent->addAction(duplicate_); - parent->addAction(delete_); - parent->addAction(ripple_delete_); - parent->addAction(split_); - } -} - -void MenuHelper::set_bool_action_checked(QAction *a) { - if (!a->data().isNull()) { - bool* variable = reinterpret_cast(a->data().value()); - a->setChecked(*variable); - } -} - -void MenuHelper::set_int_action_checked(QAction *a, const int& i) { - if (!a->data().isNull()) { - a->setChecked(a->data() == i); - } -} - -void MenuHelper::set_button_action_checked(QAction *a) { - a->setChecked(reinterpret_cast(a->data().value())->isChecked()); -} - -void MenuHelper::Retranslate() -{ - new_project_->setText(tr("&Project")); - new_sequence_->setText(tr("&Sequence")); - new_folder_->setText(tr("&Folder")); - set_in_point_->setText(tr("Set In Point")); - set_out_point_->setText(tr("Set Out Point")); - reset_in_point_->setText(tr("Reset In Point")); - reset_out_point_->setText(tr("Reset Out Point")); - clear_inout_point->setText(tr("Clear In/Out Point")); - add_default_transition_->setText(tr("Add Default Transition")); - link_unlink_->setText(tr("Link/Unlink")); - enable_disable_->setText(tr("Enable/Disable")); - nest_->setText(tr("Nest")); - cut_->setText(tr("Cu&t")); - copy_->setText(tr("Cop&y")); - paste_->setText(tr("&Paste")); - paste_insert_->setText(tr("Paste Insert")); - duplicate_->setText(tr("Duplicate")); - delete_->setText(tr("Delete")); - ripple_delete_->setText(tr("Ripple Delete")); - split_->setText(tr("Split")); -} - -void MenuHelper::toggle_bool_action() { - QAction* action = static_cast(sender()); - bool* variable = reinterpret_cast(action->data().value()); - *variable = !(*variable); - update_ui(false); -} - -void MenuHelper::set_titlesafe_from_menu() { - double tsa = static_cast(sender())->data().toDouble(); - - if (qIsNaN(tsa)) { - - // disable title safe area - olive::config.show_title_safe_area = false; - - } else { - - // using title safe area - olive::config.show_title_safe_area = true; - - // are we using the default area aspect ratio, or a specific one - if (qIsNull(tsa)) { - - // default title safe area - olive::config.use_custom_title_safe_ratio = false; - - } else { - - // using a specific aspect ratio - olive::config.use_custom_title_safe_ratio = true; - - if (tsa < 0.0) { - - // set a custom title safe area - QString input; - bool invalid = false; - QRegExp arTest("[0-9.]+:[0-9.]+"); - - do { - if (invalid) { - QMessageBox::critical(olive::MainWindow, tr("Invalid aspect ratio"), tr("The aspect ratio '%1' is invalid. Please try again.").arg(input)); - } - - input = QInputDialog::getText(olive::MainWindow, tr("Enter custom aspect ratio"), tr("Enter the aspect ratio to use for the title/action safe area (e.g. 16:9):")); - invalid = !arTest.exactMatch(input) && !input.isEmpty(); - } while (invalid); - - if (!input.isEmpty()) { - QStringList inputList = input.split(':'); - olive::config.custom_title_safe_ratio = inputList.at(0).toDouble()/inputList.at(1).toDouble(); - } - - } else { - - // specified tsa is a specific custom aspect ratio - olive::config.custom_title_safe_ratio = tsa; - } - - } - - } - - panel_sequence_viewer->viewer_widget()->update(); -} - -void MenuHelper::set_autoscroll() { - QAction* action = static_cast(sender()); - olive::config.autoscroll = action->data().toInt(); -} - -void MenuHelper::menu_click_button() { - reinterpret_cast(static_cast(sender())->data().value())->click(); -} - -void MenuHelper::set_timecode_view() { - QAction* action = static_cast(sender()); - olive::config.timecode_view = action->data().toInt(); - update_ui(false); -} - -void MenuHelper::open_recent_from_menu() { - int index = static_cast(sender())->data().toInt(); - olive::Global.get()->open_recent(index); -} - -void MenuHelper::create_effect_paste_action(QMenu *menu) -{ - QAction* paste_action = menu->addAction(tr("&Paste"), olive::Global.get(), SLOT(paste(bool))); - paste_action->setEnabled(olive::clipboard.Count() > 0 && olive::clipboard.type() == Clipboard::CLIPBOARD_TYPE_EFFECT); -} - -Menu* MenuHelper::create_submenu(QMenuBar* parent, - const QObject *receiver, - const char *member) { - Menu* menu = new Menu(parent); - - /* - menu->setStyle(QStyleFactory::create("windowsvista")); - menu->setPalette(menu->style()->standardPalette()); - menu->setStyleSheet(""); - */ - - parent->addMenu(menu); - - if (receiver != nullptr) { - QObject::connect(menu, SIGNAL(aboutToShow()), receiver, member); - } - - return menu; -} - -Menu* MenuHelper::create_submenu(QMenu* parent) { - Menu* menu = new Menu(parent); - - /* - menu->setStyle(QStyleFactory::create("windowsvista")); - menu->setPalette(menu->style()->standardPalette()); - menu->setStyleSheet(""); - */ - - parent->addMenu(menu); - return menu; -} - -QAction* MenuHelper::create_menu_action(QWidget *parent, - const char* id, - const QObject *receiver, - const char *member, - const QKeySequence &shortcut) { - QAction* action = new QAction(parent); - action->setProperty("id", id); - action->setShortcut(shortcut); - - if (receiver != nullptr) { - QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); - } - - if (parent != nullptr) { - parent->addAction(action); - } - - return action; -} diff --git a/ui/menuhelper.h b/ui/menuhelper.h deleted file mode 100644 index 73c71ad36..000000000 --- a/ui/menuhelper.h +++ /dev/null @@ -1,241 +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 MENUHELPER_H -#define MENUHELPER_H - -#include -#include - -#include "ui/menu.h" - -class MenuHelper : public QObject { - Q_OBJECT -public: - void InitializeSharedMenus(); - - /** - * @brief Creates a menu of new items that can be created - * - * Adds the full set of creatable items to a QMenu (e.g. new project, - * new sequence, new folder, etc.) - * - * @param parent - * - * The menu to add items to. - */ - void make_new_menu(QMenu* parent); - - /** - * @brief Creates a menu of options for working with in/out points - * - * Adds a set of options for working with sequence/footage in/out points, - * e.g. setting in/out points, clearing in/out points, etc. - * - * @param parent - * - * The menu to add items to. - */ - void make_inout_menu(QMenu* parent); - - /** - * @brief Creates a menu of clip functions - * - * Adds a set of clip functions including: - * * Add Default Transition - * * Link/Unlink - * * Enable/Disable - * * Nest - * - * @param parent - * - * The menu to add items to. - */ - void make_clip_functions_menu(QMenu* parent); - - /** - * @brief Creates standard edit menu (cut, copy, paste, etc.) - * - * @param parent - * - * The menu to add items to. - * - * @param objects_are_selected - * - * Some extra functions may be hidden in the event no clip is actually selected. Set this to **FALSE** to hide those - * functions. - */ - void make_edit_functions_menu(QMenu* parent, bool objects_are_selected = true); - - /** - * @brief Sets the checked state of a menu item based on a Boolean variable. - * - * Many menu items simply toggle a Boolean variable. This is a convenience function, assuming the QAction's data - * variable is a pointer to a Boolean variable, that sets the checked state of the QAction to the enabled state - * of the Boolean. Used heavily in functions like toolMenu_About_To_Be_Shown() - * - * @param a - * - * The QAction to set the checked state of. - */ - void set_bool_action_checked(QAction* a); - - /** - * @brief Sets the checked state of a menu item based on an integer variable. - * - * Many menu items simply set a variable to a particular integer. This is a convenience function, assuming the - * QAction's data variable is an integer to set a variable to, that sets the checked state of the QAction to - * whether the QAction's integer equals the integer variable. Used heavily in functions like - * viewMenu_About_To_Be_Shown() - * - * @param a - * - * The QAction to set the checked state of - * - * @param i - * - * The integer variable to compare the QAction's integer to - */ - void set_int_action_checked(QAction* a, const int& i); - - /** - * @brief Sets the checked state of a menu item based on a QPushButton. - * - * Some menu items function largely as a proxy to a QPushButton. Assuming the QAction's data variable is a - * pointer to a QPushButton, this sets a QAction's checked state to the checked state of the QPushButton. - * - * @param a - */ - void set_button_action_checked(QAction* a); - - void Retranslate(); - - static Menu *create_submenu(QMenuBar* parent, - const QObject *receiver = nullptr, - const char *member = nullptr); - static Menu* create_submenu(QMenu* parent); - static QAction* create_menu_action(QWidget *parent, - const char* id, - const QObject *receiver = nullptr, - const char *member = nullptr, - const QKeySequence &shortcut = 0); - -public slots: - - /** - * @brief Sets a QAction's Boolean reference to the opposite of its current value - * - * Many menu items simply toggle a Boolean variable. This is a convenience function, assuming the QAction's data - * variable is a pointer to a Boolean variable, that sets the Boolean variable to the opposite of its current value. - */ - void toggle_bool_action(); - - /** - * @brief Set Title/Action Safe Area from QAction - * - * A receiver for several Title/Action Safe Area setting items. Assumes the sender() is a QAction with a data - * variable as a `double`. The `double` can be the following values: - * * NaN (qSNaN()) - Disable Title/Action Safe Area - * * 0 - Enable Title/Action Safe Area, default aspect ratio (match current active Sequence's aspect ratio). - * * Negative Value - Enable Title/Action Safe Area, any negative number assumes a custom aspect ratio. Will ask - * the user to enter an aspect ratio and will use the result. - * * Positive Value - Enable Title/Action Safe Area, use value as the aspect ratio. - */ - void set_titlesafe_from_menu(); - - /** - * @brief Set Autoscroll setting from QAction - * - * Assumes the sender() is a QAction with an integer as its data variable. The data variable should be - * `AUTOSCROLL_NO_SCROLL`, `AUTOSCROLL_PAGE_SCROLL` (default) or `AUTOSCROLL_SMOOTH_SCROLL`. - */ - void set_autoscroll(); - - /** - * @brief Clicks a QPushButton referenced by a QAction when triggered. - * - * Some menu items function largely as a proxy to a QPushButton. Assuming the QAction's data variable is a - * pointer to a QPushButton, this triggers a click() event on that QPushButton. - */ - void menu_click_button(); - - /** - * @brief Sets the current timecode setting - * - * Assumes the sender() is a QAction with an integer as its data variable. The data variable should be - * `AUTOSCROLL_NO_AUTOSCROLL`, `AUTOSCROLL_PAGE_AUTOSCROLL` (default) or `AUTOSCROLL_SMOOTH_AUTOSCROLL`. - */ - void set_timecode_view(); - - /** - * @brief Calls open_recent() in Olive::Global using the index from a QAction - * - * Assumes the sender() is a QAction with an integer as its data variable. The data variable is an index of - * the internal auto-recovery project list. - */ - void open_recent_from_menu(); - - /** - * @brief Create a "Paste" action on the specified menu that's enabled only if the clipboard contains effects - * - * @param menu - * - * Menu to add action to - */ - void create_effect_paste_action(QMenu *menu); - -private: - QAction* new_project_; - QAction* new_sequence_; - QAction* new_folder_; - - QAction* set_in_point_; - QAction* set_out_point_; - QAction* reset_in_point_; - QAction* reset_out_point_; - QAction* clear_inout_point; - - QAction* add_default_transition_; - QAction* link_unlink_; - QAction* enable_disable_; - QAction* nest_; - - QAction* cut_; - QAction* copy_; - QAction* paste_; - QAction* paste_insert_; - QAction* duplicate_; - QAction* delete_; - QAction* ripple_delete_; - QAction* split_; - -private slots: - - -}; - -namespace olive { -/** - * @brief A global MenuHelper object to assist menu creation throughout Olive. - */ -extern MenuHelper MenuHelper; -}; - -#endif // MENUHELPER_H diff --git a/ui/nodeedgeui.cpp b/ui/nodeedgeui.cpp deleted file mode 100644 index 4ea6c3e28..000000000 --- a/ui/nodeedgeui.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "nodeedgeui.h" - -#include -#include - -#include "global/math.h" -#include "ui/effectui.h" - -NodeEdgeUI::NodeEdgeUI(NodeEdge* edge) : - edge_(edge), - output_node_(nullptr), - input_node_(nullptr) -{ - setPen(QPen(Qt::white, 2)); -} - -void NodeEdgeUI::adjust() -{ - if (output_node_ == nullptr) { - // Locate the output and input nodes' UIs - - QList all_items = scene()->items(); - - for (int j=0;j(all_items.at(j)); - if (node != nullptr) { - - // Check if this node has the output row - int row_index = node->GetNode()->IndexOfParameter(edge_->output()); - - if (row_index > -1) { - output_node_ = node; - output_index_ = row_index; - } - - // Check if this node has the input row - row_index = node->GetNode()->IndexOfParameter(edge_->input()); - - if (row_index > -1) { - input_node_ = node; - input_index_ = row_index; - } - } - } - } - - setPath(GetEdgePath(output_node_->pos() + output_node_->GetNodeSocketRects().at(output_index_).center(), - input_node_->pos() + input_node_->GetNodeSocketRects().at(input_index_).center())); -} - -NodeEdge *NodeEdgeUI::edge() -{ - return edge_; -} - -QPainterPath NodeEdgeUI::GetEdgePath(const QPointF &start_pos, const QPointF &end_pos) -{ - double mid_x = double_lerp(start_pos.x(), end_pos.x(), 0.5); - - QPainterPath path_; - path_.moveTo(start_pos); - path_.cubicTo(QPointF(mid_x, start_pos.y()), - QPointF(mid_x, end_pos.y()), - end_pos); - - return path_; -} diff --git a/ui/nodeedgeui.h b/ui/nodeedgeui.h deleted file mode 100644 index 3634334d2..000000000 --- a/ui/nodeedgeui.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef NODEEDGEUI_H -#define NODEEDGEUI_H - -#include - -#include "nodeui.h" - -class NodeEdgeUI : public QGraphicsPathItem { -public: - NodeEdgeUI(NodeEdge* edge); - - static QPainterPath GetEdgePath(const QPointF& start_pos, const QPointF& end_pos); - - void adjust(); - NodeEdge* edge(); - -private: - NodeEdge* edge_; - - NodeUI* output_node_; - int output_index_; - NodeUI* input_node_; - int input_index_; -}; - -#endif // NODEEDGEUI_H diff --git a/ui/nodeui.cpp b/ui/nodeui.cpp deleted file mode 100644 index 45c51f836..000000000 --- a/ui/nodeui.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "nodeui.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ui/effectui.h" -#include "ui/nodeedgeui.h" - -const int kRoundedRectRadius = 5; -const int kTextPadding = 4; -const int kNodePlugSize = 12; - -NodeUI::NodeUI() : - node_(nullptr), - drag_destination_(nullptr), - clicked_socket_(-1) -{ - setFlag(QGraphicsItem::ItemIsMovable, true); - setFlag(QGraphicsItem::ItemIsSelectable, true); -} - -void NodeUI::AddToScene(QGraphicsScene *scene) -{ - scene->addItem(this); -} - -void NodeUI::SetNode(Node *n) -{ - node_ = n; - - QRectF rectangle; - - rectangle.setTopLeft(pos()); - rectangle.setSize(QSizeF(200, GetRowY(node_->ParameterCount()))); - - QRectF inner_rect = rectangle; - inner_rect.setX(inner_rect.x() + kNodePlugSize/2); - inner_rect.setWidth(inner_rect.width() - kNodePlugSize/2); - - drag_path_ = QPainterPath(); - drag_path_.addRoundedRect(inner_rect, kRoundedRectRadius, kRoundedRectRadius); - - setRect(rectangle); -} - -Node *NodeUI::GetNode() -{ - return node_; -} - -void NodeUI::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - Q_UNUSED(widget) - - // Draw node sockets - QVector sockets = GetNodeSocketRects(); - if (!sockets.isEmpty()) { - painter->setPen(Qt::black); - painter->setBrush(Qt::gray); - - for (int i=0;idrawEllipse(sockets.at(i)); - } - } - - // Draw main background rounded rectangle - QPalette palette = qApp->palette(); - - if (option->state & QStyle::State_Selected) { - painter->setPen(palette.highlight().color()); - } else { - painter->setPen(palette.base().color()); - } - painter->setBrush(palette.window()); - painter->drawPath(drag_path_); - - // Draw node title - painter->setPen(palette.text().color()); - int left_text_x = rect().x() + kNodePlugSize/2 + kTextPadding; - painter->drawText(left_text_x, - GetRowY(-1) + qApp->fontMetrics().ascent(), - node_->name()); - - // Draw node row names - for (int i=0;iParameterCount();i++) { - int text_x; - - if (node_->Parameter(i)->IsNodeOutput()) { - // right alignment - text_x = rect().right() - kNodePlugSize/2 - qApp->fontMetrics().width(node_->Parameter(i)->name()) - kTextPadding; - } else { - // left alignment - text_x = left_text_x; - } - - painter->drawText(text_x, - GetRowY(i) + qApp->fontMetrics().ascent(), - node_->Parameter(i)->name()); - } - - // Draw title splitter line - int line_y = GetRowY(-1) + qApp->fontMetrics().height() + kTextPadding/2; - painter->drawLine(rect().x() + kNodePlugSize/2, line_y, rect().right() - kNodePlugSize/2, line_y); -} - -void NodeUI::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - QVector sockets = GetNodeSocketRects(); - - clicked_socket_ = -1; - drag_destination_ = nullptr; - - for (int i=0;ipos())) { - clicked_socket_ = i; - break; - } - } - - if (clicked_socket_ > -1) { - - // See if this socket already has an edge connected - QVector edges = node_->Parameter(clicked_socket_)->edges(); - if (!edges.isEmpty() && edges.last()->input()->ParentNode() == node_) { - - NodeEdge* e = edges.last().get(); - - // If this node is the edge's "input", then we'll drag that instead of creating a new edge - - NodeIO* other_row = e->output(); - - Node* other_node = other_row->ParentNode(); - - int other_row_index = other_node->IndexOfParameter(other_row); - - NodeUI* other_node_ui = FindUIFromNode(other_node); - - // Start an edge at the opposite end - drag_line_start_ = other_node_ui->pos() + other_node_ui->GetNodeSocketRects().at(other_row_index).center(); - - drag_source_ = other_row; - - // Disconnect the existing edge, and treat our dynamic one as an edit of that one - NodeIO::DisconnectEdge(edges.last()); - - - - } else { - - // Start a new edge here - drag_line_start_ = pos() + sockets.at(clicked_socket_).center(); - - drag_source_ = node_->Parameter(clicked_socket_); - - } - - drag_line_ = scene()->addPath(NodeEdgeUI::GetEdgePath(drag_line_start_, event->scenePos())); - - if (!edges.isEmpty()) { - drag_line_->setPen(QPen(Qt::white, 2)); - } else { - drag_line_->setPen(QPen(Qt::gray, 2)); - } - - event->accept(); - } else { - QGraphicsItem::mousePressEvent(event); - } -} - -void NodeUI::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (clicked_socket_ > -1) { - - bool line_is_touching_node = false; - drag_destination_ = nullptr; - - QPointF drag_line_end = event->scenePos(); - - // Get all the graphics items at this mouse position - QList mouse_items = scene()->items(event->scenePos()); - for (int j=0;j(mouse_items.at(j)); - if (mouse_node != nullptr) { - - // If so, get this node's sockets and loop through them - QVector mouse_nodes_sockets = mouse_node->GetNodeSocketRects(); - for (int i=0;iscenePos() - mouse_node->pos())) { - - // If so, see if the two rows can be connected - - NodeIO* local_row = drag_source_; - NodeIO* remote_row = mouse_node->GetRowFromIndex(i); - - // Ensure one is an input and one is an output and whether their data types are compatible - if (local_row->IsNodeInput() != remote_row->IsNodeInput()) { - - // Determine which row is the input and which row is the output - NodeIO* input_row = (local_row->IsNodeInput()) ? local_row : remote_row; - NodeIO* output_row = (local_row->IsNodeInput()) ? remote_row : local_row; - - if (input_row->CanAcceptDataType(output_row->OutputDataType())) { - // This is a valid connection - line_is_touching_node = true; - - // Snap drag line to this socket - drag_line_end = mouse_node->pos() + mouse_nodes_sockets.at(i).center(); - - // Cancel loop since we have a connection now - j = mouse_items.size(); - - // Cache destination row - drag_destination_ = remote_row; - } - } - - break; - } - } - } - } - - if (line_is_touching_node) { - drag_line_->setPen(QPen(Qt::white, 2)); - } else { - drag_line_->setPen(QPen(Qt::gray, 2)); - } - - drag_line_->setPath(NodeEdgeUI::GetEdgePath(drag_line_start_, drag_line_end)); - - event->accept(); - - } else { - QGraphicsItem::mouseMoveEvent(event); - } -} - -void NodeUI::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - if (clicked_socket_ > -1) { - scene()->removeItem(drag_line_); - delete drag_line_; - - event->accept(); - - if (drag_destination_ != nullptr) { - NodeIO::ConnectEdge(drag_source_, drag_destination_); - } - } else { - QGraphicsItem::mouseReleaseEvent(event); - } -} - -QVector NodeUI::GetNodeSocketRects() -{ - QVector rects; - - if (node_ != nullptr) { - Node* e = node_; - - for (int i=0;iParameterCount();i++) { - - NodeIO* row = e->Parameter(i); - - if (row->IsNodeInput() || row->IsNodeOutput()) { - qreal x = (row->IsNodeOutput()) ? rect().right() - kNodePlugSize : rect().x(); - int y = GetRowY(i) + qApp->fontMetrics().height()/2; - - rects.append(QRectF(x, - rect().y() + y - kNodePlugSize/2, - kNodePlugSize, - kNodePlugSize)); - } - } - } - - return rects; -} - -NodeIO *NodeUI::GetRowFromIndex(int i) -{ - if (node_ != nullptr && i < node_->ParameterCount()) { - return node_->Parameter(i); - } - return nullptr; -} - -NodeUI *NodeUI::FindUIFromNode(Node* n) -{ - QList all_items = scene()->items(); - - for (int j=0;j(all_items.at(j)); - if (node != nullptr) { - - // Check if this node has the specified - - if (node->node_ == n) { - return node; - } - } - } - - return nullptr; -} - -int NodeUI::GetRowY(int index) -{ - return (qApp->fontMetrics().height() + kTextPadding) * (index + 1) + kTextPadding; -} diff --git a/ui/nodeui.h b/ui/nodeui.h deleted file mode 100644 index 39645c329..000000000 --- a/ui/nodeui.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef NODEUI_H -#define NODEUI_H - -#include -#include - -class EffectUI; -class NodeIO; -class NodeEdge; -class Node; - -class NodeUI : public QGraphicsRectItem { -public: - NodeUI(); - - void AddToScene(QGraphicsScene* scene); - //void Resize(const QSize& s); - void SetNode(Node* n); - Node* GetNode(); - - QVector GetNodeSocketRects(); - -protected: - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; - - virtual void mousePressEvent(QGraphicsSceneMouseEvent * event) override; - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - -private: - NodeIO *GetRowFromIndex(int i); - NodeUI* FindUIFromNode(Node *n); - int GetRowY(int index); - - Node* node_; - - QGraphicsPathItem* drag_line_; - QPointF drag_line_start_; - NodeIO* drag_source_; - NodeIO* drag_destination_; - QPainterPath drag_path_; - - int clicked_socket_; - -}; - - - -#endif // NODEUI_H diff --git a/ui/nodeview.cpp b/ui/nodeview.cpp deleted file mode 100644 index 5a3f6ed52..000000000 --- a/ui/nodeview.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "nodeview.h" - -#include -#include -#include - -#include "ui/menu.h" -#include "nodes/oldeffectnode.h" - -NodeView::NodeView(QGraphicsScene *scene, QWidget *parent) : - QGraphicsView(scene, parent), - hand_moving_(false) -{ - setMouseTracking(true); - setWindowTitle(tr("Node Editor")); - - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); -} - -void NodeView::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::MidButton) { - hand_moving_ = true; - drag_start_ = event->pos(); - } else if (event->button() == Qt::RightButton && scene()->itemAt(mapToScene(event->pos()), QTransform()) == nullptr) { - - // If the user clicked with the right button on empty space, show the context menu - emit RequestContextMenu(); - - } else { - QGraphicsView::mousePressEvent(event); - } -} - -void NodeView::mouseMoveEvent(QMouseEvent *event) -{ - if (hand_moving_) { - QPoint delta = event->pos() - drag_start_; - - horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); - verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); - - drag_start_ = event->pos(); - } else { - QGraphicsView::mouseMoveEvent(event); - } -} - -void NodeView::mouseReleaseEvent(QMouseEvent *event) -{ - if (!hand_moving_) { - QGraphicsView::mouseReleaseEvent(event); - } - hand_moving_ = false; -} - -void NodeView::wheelEvent(QWheelEvent *event) -{ - if (event->modifiers() & Qt::ControlModifier) { - if (event->angleDelta().y() < 0) { - scale(0.9, 0.9); - } else { - scale(1.1, 1.1); - } - } else { - QGraphicsView::wheelEvent(event); - } -} diff --git a/ui/nodeview.h b/ui/nodeview.h deleted file mode 100644 index 648aef23d..000000000 --- a/ui/nodeview.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef NODEVIEW_H -#define NODEVIEW_H - -#include - -#include "timeline/tracktypes.h" - -class NodeView : public QGraphicsView { - Q_OBJECT -public: - NodeView(QGraphicsScene *scene, QWidget* parent = nullptr); - -signals: - void RequestContextMenu(); - -protected: - virtual void mousePressEvent(QMouseEvent *event) override; - virtual void mouseMoveEvent(QMouseEvent *event) override; - virtual void mouseReleaseEvent(QMouseEvent *event) override; - virtual void wheelEvent(QWheelEvent *event) override; - -private: - bool hand_moving_; - QPoint drag_start_; - -}; - -#endif // NODEVIEW_H diff --git a/ui/panel.cpp b/ui/panel.cpp deleted file mode 100644 index b8cc85b21..000000000 --- a/ui/panel.cpp +++ /dev/null @@ -1,65 +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 "panel.h" - -#include -#include - -QVector olive::panels; - -Panel::Panel(QWidget *parent) : QDockWidget (parent) { - olive::panels.append(this); -} - -Panel::~Panel() -{ - olive::panels.removeAll(this); -} - -bool Panel::focused() -{ - return hasFocus(); -} - -void Panel::LoadLayoutState(const QByteArray &) {} - -QByteArray Panel::SaveLayoutState() -{ - return QByteArray(); -} - -void Panel::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - /** - - NOTE: While overriding changeEvent() is the official documented way of handling runtime language change events, - I found it buggy to do it this way (some panels would change and others wouldn't, and the panels that did/didn't - change would be different each time). The current workaround is calling Retranslate() on each panel manually - from MainWindow::Retranslate which is triggered by its own changeEvent() that seems fairly reliable. Currently - this function is mostly a no-op. - - */ -// Retranslate(); - } else { - QDockWidget::changeEvent(e); - } -} diff --git a/ui/panel.h b/ui/panel.h deleted file mode 100644 index 28c2210c3..000000000 --- a/ui/panel.h +++ /dev/null @@ -1,46 +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 PANEL_H -#define PANEL_H - -#include - -class Panel : public QDockWidget { - Q_OBJECT -public: - Panel(QWidget* parent = nullptr); - virtual ~Panel() override; - - virtual void Retranslate() = 0; - - virtual bool focused(); - - virtual void LoadLayoutState(const QByteArray& data); - virtual QByteArray SaveLayoutState(); -protected: - virtual void changeEvent(QEvent* e) override; -}; - -namespace olive { - extern QVector panels; -} - -#endif // PANEL_H diff --git a/ui/playbutton.cpp b/ui/playbutton.cpp deleted file mode 100644 index ffe2e925a..000000000 --- a/ui/playbutton.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "playbutton.h" - -PlayButton::PlayButton(QWidget* parent) : QPushButton(parent) -{ - play_text = ">"; - pause_text = "||"; - - setText(play_text); -} diff --git a/ui/playbutton.h b/ui/playbutton.h deleted file mode 100644 index b78d7deb7..000000000 --- a/ui/playbutton.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef PLAYBUTTON_H -#define PLAYBUTTON_H - -#include - -class PlayButton : public QPushButton -{ -public: - PlayButton(QWidget* parent = 0); -private: - QString play_text; - QString pause_text; -}; - -#endif // PLAYBUTTON_H diff --git a/ui/rectangleselect.cpp b/ui/rectangleselect.cpp deleted file mode 100644 index 4df214de9..000000000 --- a/ui/rectangleselect.cpp +++ /dev/null @@ -1,27 +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 "rectangleselect.h" - -void olive::ui::DrawSelectionRectangle(QPainter& painter, const QRect& rect) { - painter.setPen(QColor(204, 204, 204)); - painter.setBrush(QColor(0, 0, 0, 32)); - painter.drawRect(rect); -} diff --git a/ui/rectangleselect.h b/ui/rectangleselect.h deleted file mode 100644 index cc784dfe5..000000000 --- a/ui/rectangleselect.h +++ /dev/null @@ -1,45 +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 RECTANGLESELECT_H -#define RECTANGLESELECT_H - -#include - -namespace olive { -namespace ui { - -/** - * @brief Routine for drawing a drag selection rectangle for any given QPainter - * - * @param painter - * - * QPainter object to use for drawing - * - * @param rect - * - * Rectangle to draw - */ -void DrawSelectionRectangle(QPainter& painter, const QRect& rect); - -} -} - -#endif // RECTANGLESELECT_H diff --git a/ui/resizablescrollbar.cpp b/ui/resizablescrollbar.cpp deleted file mode 100644 index 1fab95d8a..000000000 --- a/ui/resizablescrollbar.cpp +++ /dev/null @@ -1,126 +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 "resizablescrollbar.h" - -#include -#include -#include - -#include "global/debug.h" - -#define RESIZE_HANDLE_SIZE 10 - -ResizableScrollBar::ResizableScrollBar(QWidget *parent) : - QScrollBar(parent), - resize_init(false), - resize_proc(false) -{ - setSingleStep(20); - setMaximum(0); - setMouseTracking(true); -} - -bool ResizableScrollBar::is_resizing() { - return resize_proc; -} - -void ResizableScrollBar::resizeEvent(QResizeEvent *event) { - setPageStep(event->size().width()); -} - -void ResizableScrollBar::mousePressEvent(QMouseEvent *e) { - if (resize_init) { - QStyleOptionSlider opt; - initStyleOption(&opt); - - QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, - QStyle::SC_ScrollBarSlider, this); - - resize_proc = true; - resize_start = e->pos().x(); - - resize_start_max = maximum(); - resize_start_width = sr.width(); - } else { - QScrollBar::mousePressEvent(e); - } -} - -void ResizableScrollBar::mouseMoveEvent(QMouseEvent *e) { - QStyleOptionSlider opt; - initStyleOption(&opt); - - QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, - QStyle::SC_ScrollBarSlider, this); - QRect gr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, - QStyle::SC_ScrollBarGroove, this); - - if (resize_proc) { - int diff = (e->pos().x() - resize_start); - if (resize_top) diff = -diff; - double scale = double(sr.width())/double(sr.width()+diff); - if (!qIsInf(scale) && !qIsNull(scale)) { - emit resize_move(scale); - resize_start = e->pos().x(); - - if (resize_top) { - int slider_min = gr.x(); - int slider_max = gr.right() - (sr.width()+diff); - int val = QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x() - slider_min, slider_max - slider_min, opt.upsideDown); - - setValue(val); - } else { - setValue(qRound(value() * scale)); - } - } - } else { - bool new_resize_init = false; - - if ((orientation() == Qt::Horizontal && e->pos().x() > sr.left()-RESIZE_HANDLE_SIZE && e->pos().x() < sr.left()+RESIZE_HANDLE_SIZE) - || (orientation() == Qt::Vertical && e->pos().y() > sr.top()-RESIZE_HANDLE_SIZE && e->pos().y() < sr.top()+RESIZE_HANDLE_SIZE)) { - new_resize_init = true; - resize_top = true; - } else if ((orientation() == Qt::Horizontal && e->pos().x() > sr.right()-RESIZE_HANDLE_SIZE && e->pos().x() < sr.right()+RESIZE_HANDLE_SIZE) - || (orientation() == Qt::Vertical && e->pos().y() > sr.bottom()-RESIZE_HANDLE_SIZE && e->pos().y() < sr.bottom()+RESIZE_HANDLE_SIZE)) { - new_resize_init = true; - resize_top = false; - } - - if (resize_init != new_resize_init) { - if (new_resize_init) { - setCursor(Qt::SizeHorCursor); - } else { - unsetCursor(); - } - resize_init = new_resize_init; - } - - QScrollBar::mouseMoveEvent(e); - } -} - -void ResizableScrollBar::mouseReleaseEvent(QMouseEvent *e) { - if (resize_proc) { - resize_proc = false; - } else { - QScrollBar::mouseReleaseEvent(e); - } -} diff --git a/ui/resizablescrollbar.h b/ui/resizablescrollbar.h deleted file mode 100644 index f7abc04d1..000000000 --- a/ui/resizablescrollbar.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 RESIZABLESCROLLBAR_H -#define RESIZABLESCROLLBAR_H - -#include - -class ResizableScrollBar : public QScrollBar -{ - Q_OBJECT -public: - ResizableScrollBar(QWidget * parent = nullptr); - bool is_resizing(); -signals: - void resize_move(double i); -protected: - void resizeEvent(QResizeEvent *event) override; - void mousePressEvent(QMouseEvent *) override; - void mouseMoveEvent(QMouseEvent *) override; - void mouseReleaseEvent(QMouseEvent *) override; -private: - bool resize_init; - bool resize_proc; - int resize_start; - bool resize_top; - - int resize_start_max; - int resize_start_width; -}; - -#endif // RESIZABLESCROLLBAR_H diff --git a/ui/sourceiconview.cpp b/ui/sourceiconview.cpp deleted file mode 100644 index 39b689536..000000000 --- a/ui/sourceiconview.cpp +++ /dev/null @@ -1,215 +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 "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())); -} - -void SourceIconView::show_context_menu() { - commons_.show_context_menu(this, selectedIndexes()); -} - -void SourceIconView::item_click(const QModelIndex& index) { - if (selectedIndexes().size() == 1 && index.column() == 0) { - commons_.item_click(project_parent->item_to_media(index), index); - } -} - -void SourceIconView::mousePressEvent(QMouseEvent* event) { - commons_.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(); - commons_.dropEvent(this, event, drop_item, selectedIndexes()); -} - -void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) { - if (selectedIndexes().size() == 1) { - Media* m = project_parent->item_to_media(selectedIndexes().at(0)); - if (m->get_type() == MEDIA_TYPE_FOLDER) { - setRootIndex(selectedIndexes().at(0)); - emit changed_root(); - return; - } - } - - // 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 &) 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 deleted file mode 100644 index 01da47956..000000000 --- a/ui/sourceiconview.h +++ /dev/null @@ -1,61 +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 SOURCEICONVIEW_H -#define SOURCEICONVIEW_H - -#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 -public: - 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); -signals: - void changed_root(); -private slots: - void show_context_menu(); - void item_click(const QModelIndex& index); -private: - SourcesCommon& commons_; - SourceIconDelegate delegate_; -}; - -#endif // SOURCEICONVIEW_H diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp deleted file mode 100644 index baac4f429..000000000 --- a/ui/sourcetable.cpp +++ /dev/null @@ -1,97 +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 "sourcetable.h" -#include "panels/project.h" - -#include "project/footage.h" -#include "panels/timeline.h" -#include "panels/viewer.h" -#include "panels/panels.h" -#include "rendering/renderfunctions.h" -#include "undo/undo.h" -#include "timeline/sequence.h" -#include "mainwindow.h" -#include "global/config.h" -#include "project/media.h" -#include "project/sourcescommon.h" -#include "global/debug.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -SourceTable::SourceTable(SourcesCommon& commons) : commons_(commons) { - setSortingEnabled(true); - setAcceptDrops(true); - sortByColumn(0, Qt::AscendingOrder); - setContextMenuPolicy(Qt::CustomContextMenu); - setEditTriggers(QAbstractItemView::NoEditTriggers); - setDragDropMode(QAbstractItemView::DragDrop); - setSelectionMode(QAbstractItemView::ExtendedSelection); - 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() { - commons_.show_context_menu(this, selectionModel()->selectedRows()); -} - -void SourceTable::item_click(const QModelIndex& index) { - if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) { - commons_.item_click(project_parent->item_to_media(index), index); - } -} - -void SourceTable::mousePressEvent(QMouseEvent* event) { - commons_.mousePressEvent(event); - QTreeView::mousePressEvent(event); -} - -void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) { - commons_.mouseDoubleClickEvent(selectionModel()->selectedRows()); -} - -void SourceTable::dragEnterEvent(QDragEnterEvent *event) { - if (event->mimeData()->hasUrls()) { - event->acceptProposedAction(); - } else { - QTreeView::dragEnterEvent(event); - } -} - -void SourceTable::dragMoveEvent(QDragMoveEvent *event) { - if (event->mimeData()->hasUrls()) { - event->acceptProposedAction(); - } else { - QTreeView::dragMoveEvent(event); - } -} - -void SourceTable::dropEvent(QDropEvent* event) { - commons_.dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows()); -} diff --git a/ui/sourcetable.h b/ui/sourcetable.h deleted file mode 100644 index ffd02787d..000000000 --- a/ui/sourcetable.h +++ /dev/null @@ -1,52 +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 SOURCETABLE_H -#define SOURCETABLE_H - -#include -#include -#include - -#include "project/sourcescommon.h" - -class Project; -class Media; - -class SourceTable : public QTreeView -{ - Q_OBJECT -public: - SourceTable(SourcesCommon& commons); - Project* project_parent; -protected: - void mousePressEvent(QMouseEvent*); - void mouseDoubleClickEvent(QMouseEvent *); - void dragEnterEvent(QDragEnterEvent *event); - void dragMoveEvent(QDragMoveEvent *event); - void dropEvent(QDropEvent *event); -private slots: - void item_click(const QModelIndex& index); - void show_context_menu(); -private: - SourcesCommon& commons_; -}; - -#endif // SOURCETABLE_H diff --git a/ui/styling.cpp b/ui/styling.cpp deleted file mode 100644 index b80d4d845..000000000 --- a/ui/styling.cpp +++ /dev/null @@ -1,44 +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 "styling.h" - -#include "global/config.h" - -bool olive::styling::UseDarkIcons() -{ - return olive::config.style == kOliveDefaultLight || olive::config.style == kNativeDarkIcons; -} - -QColor olive::styling::GetIconColor() -{ - if (UseDarkIcons()) { - return Qt::black; - } else { - return Qt::white; - } -} - - - -bool olive::styling::UseNativeUI() -{ - return olive::config.style == kNativeLightIcons || olive::config.style == kNativeDarkIcons; -} diff --git a/ui/styling.h b/ui/styling.h deleted file mode 100644 index f50c1ccab..000000000 --- a/ui/styling.h +++ /dev/null @@ -1,87 +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 STYLING_H -#define STYLING_H - -#include - -namespace olive { - namespace styling { - - /** - * @brief Officially supported styles to use in Olive - */ - enum Style { - /** - Qt Fusion-based cross-platform UI. The default styling of Olive. Can also be heavily customized with a CSS - file. - */ - kOliveDefaultDark, - - /** - Qt Fusion-based cross-platform UI. The default styling of Olive. Can also be heavily customized with a CSS - file. This will use the - */ - kOliveDefaultLight, - - /** - Use current OS's native styling (or at least Qt's default). Most UIs use a light theming, so this will - automatically implement dark icons/UI elements. - */ - kNativeDarkIcons, - - /** - Use current OS's native styling (or at least Qt's default). Most UIs use a light theming, but in case one - doesn't, this option will provide light icons for use with a dark theme. - */ - kNativeLightIcons - }; - - /** - * @brief Return whether to use dark icons or light icons - * @return - * - * **TRUE** if icons should be dark. - */ - bool UseDarkIcons(); - - /** - * @brief Return whether to use native UI or Fusion - * @return - * - * **TRUE** if UI should use native styling - */ - bool UseNativeUI(); - - /** - * @brief Return the current icon color based on Config::use_dark_icons. - * - * Also used by some other UI elements like the lines and text on the TimelineHeader - * - * @return - * - * Either white or black depending on Config::use_dark_icons - */ - QColor GetIconColor(); - } -} - -#endif // STYLING_H diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp deleted file mode 100644 index 2b9f44f41..000000000 --- a/ui/texteditex.cpp +++ /dev/null @@ -1,117 +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 "texteditex.h" - -#include -#include - -#include "dialogs/texteditdialog.h" -#include "ui/menu.h" -#include "mainwindow.h" - -TextEditEx::TextEditEx(QWidget *parent, bool enable_rich_text) : - QWidget(parent), - enable_rich_text_(enable_rich_text) -{ - QVBoxLayout* layout = new QVBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(0); - - layout->setSpacing(0); - layout->setMargin(0); - - text_editor_ = new QTextEdit(); - text_editor_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding); - connect(text_editor_, SIGNAL(textChanged()), this, SLOT(queue_text_modified())); - layout->addWidget(text_editor_); - - QPushButton* edit_button = new QPushButton(tr("Edit Text")); - layout->addWidget(edit_button); - connect(edit_button, SIGNAL(clicked(bool)), this, SLOT(open_text_edit())); - - /* - text_editor_->setContextMenuPolicy(Qt::CustomContextMenu); - connect(text_editor_, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); - */ -} - -void TextEditEx::setUndoRedoEnabled(bool e) -{ - text_editor_->setUndoRedoEnabled(e); -} - -QTextDocument *TextEditEx::document() -{ - return text_editor_->document(); -} - -QTextCursor TextEditEx::textCursor() -{ - return text_editor_->textCursor(); -} - -void TextEditEx::setTextCursor(const QTextCursor &cursor) -{ - text_editor_->setTextCursor(cursor); -} - -void TextEditEx::setTextHeight(int h) -{ - text_editor_->setFixedHeight(h); -} - -void TextEditEx::setHtml(const QString &text) -{ - text_editor_->setHtml(text); -} - -void TextEditEx::setPlainText(const QString &text) -{ - text_editor_->setPlainText(text); -} - -void TextEditEx::text_edit_menu() { - Menu menu; - - menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit())); - - menu.exec(QCursor::pos()); -} - -void TextEditEx::open_text_edit() { - const QString& current_text = (enable_rich_text_) ? text_editor_->toHtml() : text_editor_->toPlainText(); - - TextEditDialog ted(olive::MainWindow, current_text, enable_rich_text_); - ted.exec(); - QString result = ted.get_string(); - if (!result.isEmpty()) { - if (enable_rich_text_) { - text_editor_->setHtml(result); - } else { - text_editor_->setPlainText(result); - } - } -} - -void TextEditEx::queue_text_modified() -{ - emit textModified(enable_rich_text_ ? text_editor_->toHtml() : text_editor_->toPlainText()); -} diff --git a/ui/texteditex.h b/ui/texteditex.h deleted file mode 100644 index 047bac38a..000000000 --- a/ui/texteditex.h +++ /dev/null @@ -1,52 +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 TEXTEDITEX_H -#define TEXTEDITEX_H - -#include -#include - -class TextEditEx : public QWidget { - Q_OBJECT -public: - TextEditEx(QWidget* parent = nullptr, bool enable_rich_text = true); - - void setUndoRedoEnabled(bool e); - QTextDocument* document(); - QTextCursor textCursor(); - void setTextCursor(const QTextCursor &cursor); - void setTextHeight(int h); -public slots: - void setHtml(const QString &text); - void setPlainText(const QString &text); -signals: - void textModified(const QString& s); -private slots: - void text_edit_menu(); - void open_text_edit(); - void queue_text_modified(); -private: - QTextEdit* text_editor_; - - bool enable_rich_text_; -}; - -#endif // TEXTEDITEX_H diff --git a/ui/timelinearea.cpp b/ui/timelinearea.cpp deleted file mode 100644 index 9d6e07989..000000000 --- a/ui/timelinearea.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "timelinearea.h" - -#include - -#include "panels/timeline.h" -#include "global/config.h" - -int olive::timeline::kTimelineLabelFixedWidth = 200; - -TimelineArea::TimelineArea(Timeline* timeline, olive::timeline::Alignment alignment) : - timeline_(timeline), - sequence_(nullptr), - alignment_(alignment) -{ - QHBoxLayout* layout = new QHBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(0); - - // LABELS - label_container_ = new QWidget(); - label_container_layout_ = new QVBoxLayout(label_container_); - label_container_layout_->setMargin(0); - label_container_layout_->setSpacing(0); - label_container_layout_->addStretch(); - - // LABEL SCROLLAREA - QScrollArea* label_area = new QScrollArea(); - label_area->setFrameShape(QFrame::NoFrame); - label_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - label_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - label_area->verticalScrollBar()->setMaximum(INT_MAX); - label_area->setWidgetResizable(true); - label_area->setFixedWidth(olive::timeline::kTimelineLabelFixedWidth); - label_area->setWidget(label_container_); - layout->addWidget(label_area); - - // VIEW - view_ = new TimelineView(timeline_); - view_->SetAlignment(alignment_); - layout->addWidget(view_); - - // SCROLLBAR - scrollbar_ = new QScrollBar(Qt::Vertical); - layout->addWidget(scrollbar_); - - connect(scrollbar_, SIGNAL(valueChanged(int)), view_, SLOT(setScroll(int))); - connect(scrollbar_, SIGNAL(valueChanged(int)), label_area->verticalScrollBar(), SLOT(setValue(int))); - connect(view_, SIGNAL(setScrollMaximum(int)), this, SLOT(setScrollMaximum(int))); - connect(view_, SIGNAL(requestScrollChange(int)), scrollbar_, SLOT(setValue(int))); -} - -void TimelineArea::SetTrackType(Sequence *sequence, olive::TrackType track_type) -{ - if (sequence_ != nullptr) { - disconnect(sequence_, SIGNAL(NodeGraphChanged()), this, SLOT(RefreshLabels())); - } - - sequence_ = sequence; - type_ = track_type; - - if (sequence_ != nullptr) { - - connect(sequence_, SIGNAL(NodeGraphChanged()), this, SLOT(RefreshLabels())); - - } - - RefreshLabels(); - - view_->SetTrackType(sequence_, type_); -} - -void TimelineArea::SetAlignment(olive::timeline::Alignment alignment) -{ - view_->SetAlignment(alignment); - alignment_ = alignment; - - RefreshLabels(); -} - -olive::TrackType TimelineArea::track_type() -{ - return type_; -} - -TimelineView *TimelineArea::view() -{ - return view_; -} - -void TimelineArea::wheelEvent(QWheelEvent *event) -{ - - // TODO: implement pixel scrolling - - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool ctrl = (event->modifiers() & Qt::ControlModifier); - bool alt = (event->modifiers() & Qt::AltModifier); - - // "Scroll Zooms" false + Control up : not zooming - // "Scroll Zooms" false + Control down: zooming - // "Scroll Zooms" true + Control up : zooming - // "Scroll Zooms" true + Control down: not zooming - bool zooming = (olive::config.scroll_zooms != ctrl); - - // Allow shift for axis swap, but don't swap on zoom... Unless - // we need to override Qt's axis swap via Alt - bool swap_hv = ((shift != olive::config.invert_timeline_scroll_axes) & - !zooming) | (alt & !shift & zooming); - - int delta_h = swap_hv ? event->angleDelta().y() : event->angleDelta().x(); - int delta_v = swap_hv ? event->angleDelta().x() : event->angleDelta().y(); - - if (zooming) { - - // Zoom only uses vertical scrolling, to avoid glitches on touchpads. - // Don't do anything if not scrolling vertically. - - if (delta_v != 0) { - - // delta_v == 120 for one click of a mousewheel. Less or more for a - // touchpad gesture. Calculate speed to compensate. - // 120 = ratio of 4/3 (1.33), -120 = ratio of 3/4 (.75) - - double zoom_ratio = 1.0 + (abs(delta_v) * 0.33 / 120); - - if (delta_v < 0) { - zoom_ratio = 1.0 / zoom_ratio; - } - - timeline_->multiply_zoom(zoom_ratio); - } - - } else { - - // Use the Timeline's main scrollbar for horizontal scrolling, and this - // widget's scrollbar for vertical scrolling. - - QScrollBar* bar_v = scrollbar_; - QScrollBar* bar_h = timeline_->horizontalScrollBar; - - // Match the wheel events to the size of a step as per - // https://doc.qt.io/qt-5/qwheelevent.html#angleDelta - - int step_h = bar_h->singleStep() * delta_h / -120; - int step_v = bar_v->singleStep() * delta_v / -120; - - // Apply to appropriate scrollbars - - bar_h->setValue(bar_h->value() + step_h); - bar_v->setValue(bar_v->value() + step_v); - } -} - -void TimelineArea::RefreshLabels() -{ - if (sequence_ == nullptr) { - - labels_.clear(); - - } else { - - QVector track_list = sequence_->GetTrackList(type_); - - labels_.resize(track_list.size()); - for (int i=0;i(); - labels_[i]->SetTrack(track_list.at(i)); - labels_[i]->SetAlignment(alignment_); - - switch (alignment_) { - case olive::timeline::kAlignmentTop: - label_container_layout_->insertWidget(label_container_layout_->count()-1, labels_[i].get()); - break; - case olive::timeline::kAlignmentBottom: - label_container_layout_->insertWidget(1, labels_[i].get()); - break; - case olive::timeline::kAlignmentSingle: - break; - } - } - } -} - -void TimelineArea::resizeEvent(QResizeEvent *) -{ - scrollbar_->setPageStep(view_->height()); -} - -void TimelineArea::setScrollMaximum(int maximum) -{ - scrollbar_->setMaximum(qMax(0, maximum - view_->height())); - label_container_->setMinimumHeight(maximum); -// label_container_->setFixedHeight(maximum); -} diff --git a/ui/timelinearea.h b/ui/timelinearea.h deleted file mode 100644 index 1440e29e3..000000000 --- a/ui/timelinearea.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef TIMELINEAREA_H -#define TIMELINEAREA_H - -#include "timeline/sequence.h" -#include "timeline/track.h" -#include "timeline/timelinefunctions.h" -#include "ui/timelineview.h" -#include "ui/timelinelabel.h" - -class TimelineArea : public QWidget -{ - Q_OBJECT -public: - TimelineArea(Timeline *timeline, olive::timeline::Alignment alignment = olive::timeline::kAlignmentTop); - - void SetTrackType(Sequence* sequence, olive::TrackType track_type); - void SetAlignment(olive::timeline::Alignment alignment); - - olive::TrackType track_type(); - TimelineView* view(); - - virtual void wheelEvent(QWheelEvent *event) override; -public slots: - void RefreshLabels(); -protected: - virtual void resizeEvent(QResizeEvent *event) override; -private: - Timeline* timeline_; - Sequence* sequence_; - olive::TrackType type_; - TimelineView* view_; - QVector labels_; - olive::timeline::Alignment alignment_; - QVBoxLayout* label_container_layout_; - QScrollBar* scrollbar_; - QWidget* label_container_; -private slots: - void setScrollMaximum(int); -}; - -#endif // TIMELINEAREA_H diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp deleted file mode 100644 index d6cd92f3c..000000000 --- a/ui/timelineheader.cpp +++ /dev/null @@ -1,496 +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 "timelineheader.h" - -#include -#include -#include -#include -#include - -#include "mainwindow.h" -#include "panels/panels.h" -#include "global/math.h" -#include "timeline/sequence.h" -#include "undo/undo.h" -#include "project/media.h" -#include "global/timing.h" -#include "global/config.h" -#include "global/global.h" -#include "ui/menu.h" -#include "ui/menuhelper.h" -#include "global/debug.h" -#include "undo/undostack.h" - -#define CLICK_RANGE 5 -#define PLAYHEAD_SIZE 6 -#define LINE_MIN_PADDING 50 -#define SUBLINE_MIN_PADDING 50 // TODO play with this - -// used only if center_timeline_timecodes is FALSE -#define TEXT_PADDING_FROM_LINE 4 - -bool center_scroll_to_playhead(QScrollBar* bar, double zoom, long playhead) { - // returns true is the scroll was changed, false if not - int target_scroll = qMin(bar->maximum(), qMax(0, getScreenPointFromFrame(zoom, playhead)-(bar->width()>>1))); - if (target_scroll == bar->value()) { - return false; - } - bar->setValue(target_scroll); - return true; -} - -TimelineHeader::TimelineHeader(QWidget *parent) : - QWidget(parent), - snapping(true), - dragging(false), - resizing_workarea(false), - zoom(1), - in_visible(0), - fm(font()), - dragging_markers(false), - scroll(0), - height_actual(fm.height()) -{ - setCursor(Qt::ArrowCursor); - setMouseTracking(true); - setFocusPolicy(Qt::ClickFocus); - show_text(true); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(show_context_menu(const QPoint &))); -} - -void TimelineHeader::set_scroll(int s) { - scroll = s; - update(); -} - -long TimelineHeader::getHeaderFrameFromScreenPoint(int x) { - return getFrameFromScreenPoint(zoom, x + scroll) + in_visible; -} - -int TimelineHeader::getHeaderScreenPointFromFrame(long frame) { - return getScreenPointFromFrame(zoom, frame - in_visible) - scroll; -} - -void TimelineHeader::set_playhead(int mouse_x) { - long frame = getHeaderFrameFromScreenPoint(mouse_x); - if (snapping) viewer->seq->SnapPoint(&frame, zoom, false, true, true); - if (frame != viewer->seq->playhead) { - viewer->seek(frame); - } -} - -int TimelineHeader::get_marker_offset() { - return (text_enabled) ? height()/2 : 0; -} - -void TimelineHeader::set_visible_in(long i) { - in_visible = i; - update(); -} - -void TimelineHeader::set_in_point(long new_in) { - long new_out = viewer->seq->workarea_out; - if (new_out == new_in) { - new_in--; - } else if (new_out < new_in) { - new_out = viewer->seq->GetEndFrame(); - } - - olive::undo_stack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); - update_parents(); -} - -void TimelineHeader::set_out_point(long new_out) { - long new_in = viewer->seq->workarea_in; - if (new_out == new_in) { - new_out++; - } else if (new_in > new_out || new_in < 0) { - new_in = 0; - } - - olive::undo_stack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); - update_parents(); -} - -void TimelineHeader::set_scrollbar_max(QScrollBar* bar, long sequence_end_frame, int offset) { - bar->setMaximum(qMax(0, getScreenPointFromFrame(zoom, sequence_end_frame) - offset)); -} - -void TimelineHeader::show_text(bool enable) { - text_enabled = enable; - if (enable) { - setFixedHeight(height_actual*2); - } else { - setFixedHeight(height_actual); - } - update(); -} - -void TimelineHeader::mousePressEvent(QMouseEvent* event) { - if (viewer->seq != nullptr && event->buttons() & Qt::LeftButton) { - if (resizing_workarea) { - sequence_end = viewer->seq->GetEndFrame(); - } else { - /*int - QPoint start(in_x, height()+2); - QPainterPath path; - path.moveTo(start + QPoint(1,0)); - path.lineTo(in_x-PLAYHEAD_SIZE, yoff); - path.lineTo(in_x+PLAYHEAD_SIZE+1, yoff);*/ - - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool clicked_on_marker = false; - int playhead_x = getHeaderScreenPointFromFrame(viewer->seq->playhead); - - if (event->pos().y() > get_marker_offset() - && (event->pos().x() < playhead_x-PLAYHEAD_SIZE - || event->pos().x() > playhead_x+PLAYHEAD_SIZE)) { - for (int i=0;imarker_ref->size();i++) { - int marker_pos = getHeaderScreenPointFromFrame(viewer->marker_ref->at(i).frame); - if (event->pos().x() > marker_pos - MARKER_SIZE && event->pos().x() < marker_pos + MARKER_SIZE) { - bool found = false; - for (int j=0;jmarker_ref->at(selected_markers.at(i)).frame; - } - drag_start = event->pos().x(); - dragging_markers = true; - } else { - if (selected_markers.size() > 0 && !shift) { - selected_markers.clear(); - update(); - } - set_playhead(event->pos().x()); - } - } - dragging = true; - } -} - -void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { - if (viewer->seq != nullptr) { - if (dragging) { - if (resizing_workarea) { - long frame = getHeaderFrameFromScreenPoint(event->pos().x()); - if (snapping) viewer->seq->SnapPoint(&frame, zoom, true, true, false); - - if (resizing_workarea_in) { - temp_workarea_in = qMax(qMin(temp_workarea_out-1, frame), 0L); - } else { - temp_workarea_out = qMin(qMax(temp_workarea_in+1, frame), sequence_end); - } - - update_parents(); - } else if (dragging_markers) { - long frame_movement = getHeaderFrameFromScreenPoint(event->pos().x()) - getHeaderFrameFromScreenPoint(drag_start); - - // snap markers - for (int i=0;iseq->SnapPoint(&fm, zoom, true, false, true)) { - frame_movement = fm - selected_marker_original_times.at(i); - break; - } - } - - // validate markers (ensure none go below 0) - long validator; - for (int i=0;imarker_ref[0][selected_markers.at(i)].frame = selected_marker_original_times.at(i) + frame_movement; - } - - update_parents(); - } else { - set_playhead(event->pos().x()); - } - } else { - resizing_workarea = false; - unsetCursor(); - if (viewer->seq != nullptr && viewer->seq->using_workarea) { - long min_frame = getHeaderFrameFromScreenPoint(event->pos().x() - CLICK_RANGE) - 1; - long max_frame = getHeaderFrameFromScreenPoint(event->pos().x() + CLICK_RANGE) + 1; - if (viewer->seq->workarea_in > min_frame && viewer->seq->workarea_in < max_frame) { - resizing_workarea = true; - resizing_workarea_in = true; - } else if (viewer->seq->workarea_out > min_frame && viewer->seq->workarea_out < max_frame) { - resizing_workarea = true; - resizing_workarea_in = false; - } - if (resizing_workarea) { - temp_workarea_in = viewer->seq->workarea_in; - temp_workarea_out = viewer->seq->workarea_out; - setCursor(Qt::SizeHorCursor); - } - } - } - } -} - -void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { - if (viewer->seq != nullptr) { - dragging = false; - if (resizing_workarea) { - olive::undo_stack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, temp_workarea_in, temp_workarea_out)); - } else if (dragging_markers && selected_markers.size() > 0) { - bool moved = false; - ComboAction* ca = new ComboAction(); - for (int i=0;imarker_ref[0][selected_markers.at(i)]; - if (selected_marker_original_times.at(i) != m->frame) { - ca->append(new MoveMarkerAction(m, selected_marker_original_times.at(i), m->frame)); - moved = true; - } - } - if (moved) { - olive::undo_stack.push(ca); - } else { - delete ca; - } - } - - resizing_workarea = false; - dragging = false; - dragging_markers = false; - olive::timeline::snapped = false; - update_parents(); - } -} - -void TimelineHeader::focusOutEvent(QFocusEvent*) { - selected_markers.clear(); - update(); -} - -void TimelineHeader::update_parents() { - viewer->update_parents(); -} - -void TimelineHeader::update_zoom(double z) { - zoom = z; - update(); -} - -double TimelineHeader::get_zoom() { - return zoom; -} - -void TimelineHeader::delete_markers() { - if (selected_markers.size() > 0) { - - // Send command to delete selected markers - DeleteMarkerAction* dma = new DeleteMarkerAction(viewer->marker_ref); - dma->markers.append(selected_markers); - olive::undo_stack.push(dma); - - // remove any indices for the selected markers that no longer exist - for (int i=0;i= viewer->marker_ref->size()) { - selected_markers.removeAt(i); - i--; - } - } - - // if we removed all the indices, re-select the last marker in the array so something is always selected - // (allows users to hold delete when deleting markers) - if (selected_markers.isEmpty() && !viewer->marker_ref->isEmpty()) { - selected_markers.append(viewer->marker_ref->size() - 1); - } - - update_parents(); - } -} - -void TimelineHeader::paintEvent(QPaintEvent*) { - if (viewer->seq != nullptr && zoom > 0) { - QPainter p(this); - int yoff = get_marker_offset(); - - double interval = viewer->seq->frame_rate(); - int textWidth = 0; - int lastTextBoundary = INT_MIN; - - int lastLineX = INT_MIN; - - int sublineCount = 1; - int sublineTest = qRound(interval*zoom); - int sublineInterval = 1; - while (sublineTest > SUBLINE_MIN_PADDING - && sublineInterval >= 1) { - sublineCount *= 2; - sublineInterval = (interval/sublineCount); - sublineTest = qRound(sublineInterval*zoom); - } - sublineCount = qMin(sublineCount, qRound(interval)); - - int text_x, fullTextWidth; - QString timecode; - - // find where to start drawing lines (lineX algorithm reversed if lineX = 0) - int i = qFloor(double(scroll)/zoom/interval); - - while (true) { - long frame = qRound(interval*i); - int lineX = qRound(frame*zoom) - scroll; - - if (lineX > width()) break; - - // draw text - bool draw_text = false; - if (text_enabled && lineX-textWidth > lastTextBoundary) { - timecode = frame_to_timecode(frame + in_visible, olive::config.timecode_view, viewer->seq->frame_rate()); - fullTextWidth = fm.width(timecode); - textWidth = fullTextWidth>>1; - - text_x = lineX; - - // centers the text to that point on the timeline, LEFT aligns it if not - if (olive::config.center_timeline_timecodes) { - text_x -= textWidth; - } else { - text_x += TEXT_PADDING_FROM_LINE; - } - - lastTextBoundary = lineX+textWidth; - if (lastTextBoundary >= 0) { - draw_text = true; - } - } - - if (lineX > lastLineX+LINE_MIN_PADDING) { - if (draw_text) { - p.setPen(olive::styling::GetIconColor()); - p.drawText(QRect(text_x, 0, fullTextWidth, yoff), timecode); - } - - // draw line markers - p.setPen(Qt::gray); - p.drawLine(lineX, (!olive::config.center_timeline_timecodes && draw_text) ? 0 : yoff, lineX, height()); - - // draw sub-line markers - for (int j=1;jseq->using_workarea) { - in_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_in : viewer->seq->workarea_in)); - int out_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_out : viewer->seq->workarea_out)); - p.fillRect(QRect(in_x, 0, out_x-in_x, height()), QColor(0, 192, 255, 128)); - p.setPen(olive::styling::GetIconColor()); - p.drawLine(in_x, 0, in_x, height()); - p.drawLine(out_x, 0, out_x, height()); - } - - // draw markers - for (int i=0;imarker_ref->size();i++) { - const Marker& m = viewer->marker_ref->at(i); - - int marker_x = getHeaderScreenPointFromFrame(m.frame); - - bool selected = false; - for (int j=0;jseq->playhead); - QPoint start(in_x, height()+2); - QPainterPath path; - path.moveTo(start + QPoint(1,0)); - path.lineTo(in_x-PLAYHEAD_SIZE, yoff); - path.lineTo(in_x+PLAYHEAD_SIZE+1, yoff); - path.lineTo(start); - p.fillPath(path, Qt::red); - - // Draw white line at the top for clarity - p.setPen(Qt::gray); - p.drawLine(0, 0, width(), 0); - } -} - -void TimelineHeader::show_context_menu(const QPoint &pos) { - Menu menu(this); - - // Add items for setting the in/out points of a QMenu - olive::MenuHelper.make_inout_menu(&menu); - - menu.addSeparator(); - - QAction* center_timecodes = menu.addAction(tr("Center Timecodes"), &olive::MenuHelper, SLOT(toggle_bool_action())); - center_timecodes->setCheckable(true); - center_timecodes->setChecked(olive::config.center_timeline_timecodes); - center_timecodes->setData(reinterpret_cast(&olive::config.center_timeline_timecodes)); - - menu.exec(mapToGlobal(pos)); -} - -void TimelineHeader::resized_scroll_listener(double d) { - update_zoom(zoom * d); -} diff --git a/ui/timelineheader.h b/ui/timelineheader.h deleted file mode 100644 index e2a954e46..000000000 --- a/ui/timelineheader.h +++ /dev/null @@ -1,99 +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 TIMELINEHEADER_H -#define TIMELINEHEADER_H - -#include -#include -class Viewer; -class QScrollBar; - -bool center_scroll_to_playhead(QScrollBar* bar, double zoom, long playhead); - -class TimelineHeader : public QWidget -{ - Q_OBJECT -public: - explicit TimelineHeader(QWidget *parent = 0); - void set_in_point(long p); - void set_out_point(long p); - - Viewer* viewer; - - bool snapping; - - void show_text(bool enable); - double get_zoom(); - void delete_markers(); - void set_scrollbar_max(QScrollBar* bar, long sequence_end_frame, int offset); - -public slots: - void update_zoom(double z); - void set_scroll(int); - void set_visible_in(long i); - void show_context_menu(const QPoint &pos); - void resized_scroll_listener(double d); - -protected: - void paintEvent(QPaintEvent*); - void mousePressEvent(QMouseEvent*); - void mouseMoveEvent(QMouseEvent*); - void mouseReleaseEvent(QMouseEvent*); - void focusOutEvent(QFocusEvent*); - -private: - void update_parents(); - - bool dragging; - - bool resizing_workarea; - bool resizing_workarea_in; - long temp_workarea_in; - long temp_workarea_out; - long sequence_end; - - double zoom; - - long in_visible; - - void set_playhead(int mouse_x); - - int get_marker_offset(); - - QFontMetrics fm; - - int drag_start; - bool dragging_markers; - QVector selected_markers; - QVector selected_marker_original_times; - - long getHeaderFrameFromScreenPoint(int x); - int getHeaderScreenPointFromFrame(long frame); - - int scroll; - - int height_actual; - bool text_enabled; - -signals: -}; - -#endif // TIMELINEHEADER_H diff --git a/ui/timelinelabel.cpp b/ui/timelinelabel.cpp deleted file mode 100644 index 37d7fd0b8..000000000 --- a/ui/timelinelabel.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "timelinelabel.h" - -#include -#include -#include - -TimelineLabel::TimelineLabel() : - track_(nullptr), - alignment_(olive::timeline::kAlignmentTop) -{ - QHBoxLayout* layout = new QHBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(layout->spacing()/2); - - label_ = new ClickableLabel(); - layout->addWidget(label_); - connect(label_, SIGNAL(double_clicked()), this, SLOT(RenameTrack())); - - mute_button_ = new QPushButton("M"); - QSize fixed_size(mute_button_->sizeHint().height(), mute_button_->sizeHint().height()); - fixed_size *= 0.75; - mute_button_->setFixedSize(fixed_size); - mute_button_->setStyleSheet("QPushButton::checked { background: red; }"); - mute_button_->setCheckable(true); - layout->addWidget(mute_button_); - - solo_button_ = new QPushButton("S"); - solo_button_->setFixedSize(fixed_size); - solo_button_->setStyleSheet("QPushButton::checked { background: yellow; }"); - solo_button_->setCheckable(true); - layout->addWidget(solo_button_); - - lock_button_ = new QPushButton("L"); - lock_button_->setFixedSize(fixed_size); - lock_button_->setStyleSheet("QPushButton::checked { background: gray; }"); - lock_button_->setCheckable(true); - layout->addWidget(lock_button_); -} - -void TimelineLabel::SetTrack(Track *track) -{ - if (track_ != nullptr) { - disconnect(mute_button_, SIGNAL(toggled(bool)), track_, SLOT(SetMuted(bool))); - disconnect(solo_button_, SIGNAL(toggled(bool)), track_, SLOT(SetSoloed(bool))); - disconnect(lock_button_, SIGNAL(toggled(bool)), track_, SLOT(SetLocked(bool))); - } - - track_ = track; - - if (track_ != nullptr) { - UpdateState(); - - connect(mute_button_, SIGNAL(toggled(bool)), track_, SLOT(SetMuted(bool))); - connect(solo_button_, SIGNAL(toggled(bool)), track_, SLOT(SetSoloed(bool))); - connect(lock_button_, SIGNAL(toggled(bool)), track_, SLOT(SetLocked(bool))); - - connect(track_, SIGNAL(HeightChanged(int)), this, SLOT(UpdateHeight(int))); - } -} - -void TimelineLabel::UpdateState() -{ - label_->setText(track_->name()); - - UpdateHeight(track_->height()); - - mute_button_->setChecked(track_->IsMuted()); - solo_button_->setChecked(track_->IsSoloed()); - lock_button_->setChecked(track_->IsLocked()); -} - -void TimelineLabel::SetAlignment(olive::timeline::Alignment alignment) -{ - alignment_ = alignment; - update(); -} - -void TimelineLabel::paintEvent(QPaintEvent *) -{ - if (alignment_ != olive::timeline::kAlignmentTop && alignment_ != olive::timeline::kAlignmentBottom) { - return; - } - - QPainter p(this); - - p.setPen(QColor(0, 0, 0, 96)); - - int line_y = (alignment_ == olive::timeline::kAlignmentTop) ? height() - 1 : 0; - - p.drawLine(0, line_y, width(), line_y); -} - -void TimelineLabel::RenameTrack() -{ - bool ok; - QString new_name = QInputDialog::getText(this, - tr("Rename Track"), - tr("Enter the new name for this track"), - QLineEdit::Normal, - track_->name(), - &ok); - if (ok) { - track_->SetName(new_name); - - UpdateState(); - } -} - -void TimelineLabel::UpdateHeight(int h) -{ - setFixedHeight(h+1); -} diff --git a/ui/timelinelabel.h b/ui/timelinelabel.h deleted file mode 100644 index 348c59ceb..000000000 --- a/ui/timelinelabel.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef TIMELINELABEL_H -#define TIMELINELABEL_H - -#include -#include - -#include "ui/clickablelabel.h" -#include "timeline/track.h" -#include "timeline/timelinefunctions.h" - -class TimelineLabel : public QWidget -{ - Q_OBJECT -public: - TimelineLabel(); - - void SetTrack(Track* track); - void UpdateState(); - void SetAlignment(olive::timeline::Alignment alignment); -protected: - virtual void paintEvent(QPaintEvent *event) override; -private: - QPushButton* mute_button_; - QPushButton* solo_button_; - QPushButton* lock_button_; - - ClickableLabel* label_; - - Track* track_; - - olive::timeline::Alignment alignment_; -private slots: - void RenameTrack(); - void UpdateHeight(int h); -}; - -using TimelineLabelPtr = std::shared_ptr; - -#endif // TIMELINELABEL_H diff --git a/ui/timelineview.cpp b/ui/timelineview.cpp deleted file mode 100644 index 5d3643db4..000000000 --- a/ui/timelineview.cpp +++ /dev/null @@ -1,3398 +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 "timelineview.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "panels/panels.h" -#include "project/projectelements.h" -#include "rendering/audio.h" -#include "global/config.h" -#include "global/timing.h" -#include "ui/sourcetable.h" -#include "ui/sourceiconview.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "ui/viewerwidget.h" -#include "ui/resizablescrollbar.h" -#include "dialogs/newsequencedialog.h" -#include "mainwindow.h" -#include "ui/rectangleselect.h" -#include "rendering/renderfunctions.h" -#include "ui/cursors.h" -#include "ui/menuhelper.h" -#include "ui/menu.h" -#include "ui/focusfilter.h" -#include "dialogs/clippropertiesdialog.h" -#include "global/debug.h" -#include "nodes/oldeffectnode.h" -#include "effects/internal/solideffect.h" -#include "timeline/track.h" -#include "global/math.h" -#include "project/projectfunctions.h" -#include "ui/waveform.h" - -#define MAX_TEXT_WIDTH 20 -#define TRANSITION_BETWEEN_RANGE 40 - -TimelineView::TimelineView(Timeline *parent) : - timeline_(parent), - self_created_sequence(nullptr), - sequence_(nullptr), - type_(olive::kTypeCount), - scroll(0), - alignment_(olive::timeline::kAlignmentTop), - track_resizing(false) -{ - setMouseTracking(true); - - setFocusPolicy(Qt::ClickFocus); - - setAcceptDrops(true); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); - - tooltip_timer.setInterval(500); - connect(&tooltip_timer, SIGNAL(timeout()), this, SLOT(tooltip_timer_timeout())); -} - -void TimelineView::SetAlignment(olive::timeline::Alignment alignment) -{ - alignment_ = alignment; -} - -void TimelineView::SetTrackType(Sequence* s, olive::TrackType type) -{ - sequence_ = s; - type_ = type; - - update(); -} - -void TimelineView::show_context_menu(const QPoint& pos) { - if (sequence() != nullptr) { - // hack because sometimes right clicking doesn't trigger mouse release event - ParentTimeline()->rect_select_init = false; - ParentTimeline()->rect_select_proc = false; - - Menu menu(this); - - QAction* undoAction = menu.addAction(tr("&Undo")); - QAction* redoAction = menu.addAction(tr("&Redo")); - connect(undoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(undo())); - connect(redoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(redo())); - undoAction->setEnabled(olive::undo_stack.canUndo()); - redoAction->setEnabled(olive::undo_stack.canRedo()); - menu.addSeparator(); - - // collect all the selected clips - QVector selected_clips = sequence()->SelectedClips(); - - olive::MenuHelper.make_edit_functions_menu(&menu, !selected_clips.isEmpty()); - - if (selected_clips.isEmpty()) { - // no clips are selected - - // determine if we can perform a ripple empty space - ParentTimeline()->cursor_frame = ParentTimeline()->getTimelineFrameFromScreenPoint(pos.x()); - ParentTimeline()->cursor_track = getTrackFromScreenPoint(pos.y()); - - // check if the space the cursor is currently at is empty - if (ParentTimeline()->cursor_track != nullptr - && ParentTimeline()->cursor_track->GetClipFromPoint(ParentTimeline()->cursor_frame) == nullptr) { - QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete Empty Space")); - connect(ripple_delete_action, SIGNAL(triggered(bool)), ParentTimeline(), SLOT(ripple_delete_empty_space())); - } - - QAction* seq_settings = menu.addAction(tr("Sequence Settings")); - connect(seq_settings, SIGNAL(triggered(bool)), this, SLOT(open_sequence_properties())); - } - - if (!selected_clips.isEmpty()) { - - bool video_clips_are_selected = false; - bool audio_clips_are_selected = false; - - for (int i=0;itype() == olive::kTypeVideo) { - video_clips_are_selected = true; - } else { - audio_clips_are_selected = true; - } - } - - menu.addSeparator(); - - menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog())); - - if (audio_clips_are_selected) { - menu.addAction(tr("Auto-Cut Silence"), olive::Global.get(), SLOT(open_autocut_silence_dialog())); - } - - QAction* autoscaleAction = menu.addAction(tr("Auto-S&cale"), this, SLOT(toggle_autoscale())); - autoscaleAction->setCheckable(true); - // set autoscale to the first selected clip - autoscaleAction->setChecked(selected_clips.at(0)->autoscaled()); - - olive::MenuHelper.make_clip_functions_menu(&menu); - - // check if all selected clips have the same media for a "Reveal In Project" - bool same_media = true; - rc_reveal_media = selected_clips.at(0)->media(); - for (int i=1;imedia() != rc_reveal_media) { - same_media = false; - break; - } - } - - if (same_media) { - QAction* revealInProjectAction = menu.addAction(tr("&Reveal in Project")); - connect(revealInProjectAction, SIGNAL(triggered(bool)), this, SLOT(reveal_media())); - } - - menu.addAction(tr("Properties"), this, SLOT(show_clip_properties())); - } - - menu.exec(mapToGlobal(pos)); - } -} - -void TimelineView::toggle_autoscale() { - QVector selected_clips = sequence()->SelectedClips(); - - if (!selected_clips.isEmpty()) { - SetClipProperty* action = new SetClipProperty(kSetClipPropertyAutoscale); - - for (int i=0;iAddSetting(c, !c->autoscaled()); - } - - olive::undo_stack.push(action); - } -} - -void TimelineView::tooltip_timer_timeout() { - if (tooltip_clip != nullptr) { - QToolTip::showText(QCursor::pos(), - tr("%1\nStart: %2\nEnd: %3\nDuration: %4").arg( - tooltip_clip->name(), - frame_to_timecode(tooltip_clip->timeline_in(), olive::config.timecode_view, sequence()->frame_rate()), - frame_to_timecode(tooltip_clip->timeline_out(), olive::config.timecode_view, sequence()->frame_rate()), - frame_to_timecode(tooltip_clip->length(), olive::config.timecode_view, sequence()->frame_rate()) - )); - } - - tooltip_timer.stop(); -} - -void TimelineView::open_sequence_properties() { - QVector sequence_items = olive::project_model.GetAllSequences(); - - for (int i=0;ito_sequence().get() == sequence()) { - NewSequenceDialog nsd(this, sequence_items.at(i)); - nsd.exec(); - return; - } - } - - QMessageBox::critical(this, tr("Error"), tr("Couldn't locate media wrapper for sequence.")); -} - -void TimelineView::show_clip_properties() -{ - // get list of selected clips - QVector selected_clips = sequence()->SelectedClips(); - - // if clips are selected, open the clip properties dialog - if (!selected_clips.isEmpty()) { - ClipPropertiesDialog cpd(this, selected_clips); - cpd.exec(); - } -} - -void TimelineView::dragEnterEvent(QDragEnterEvent *event) { - bool import_init = false; - - QVector media_list; - ParentTimeline()->importing_files = false; - - for (int i=0;iIsProjectWidget(event->source())) { - - QModelIndexList items = panel_project.at(i)->get_current_selected(); - - media_list.resize(items.size()); - for (int i=0;iitem_to_media(items.at(i)); - } - import_init = true; - - break; - - } - } - - if (event->source() == panel_footage_viewer) { - if (panel_footage_viewer->seq.get() != sequence()) { // don't allow nesting the same sequence - - media_list.append(olive::timeline::MediaImportData(panel_footage_viewer->media, - static_cast(event->mimeData()->text().toInt()))); - import_init = true; - - } - } - - if (olive::config.enable_drag_files_to_timeline && event->mimeData()->hasUrls()) { - QList urls = event->mimeData()->urls(); - if (!urls.isEmpty()) { - QStringList file_list; - - for (int i=0;i last_imported_media = olive::project_model.GetLastImportedMedia(); - for (int i=0;ito_footage(); - - // waits for media to have a duration - // TODO would be much nicer if this was multithreaded - f->ready_lock.lock(); - f->ready_lock.unlock(); - - if (f->ready) { - media_list.append(last_imported_media.at(i)); - } - } - - if (media_list.isEmpty()) { - olive::undo_stack.undo(); - } else { - import_init = true; - ParentTimeline()->importing_files = true; - } - } - } - - if (import_init) { - event->acceptProposedAction(); - - long entry_point; - Sequence* seq = sequence(); - - if (seq == nullptr) { - // if no sequence, we're going to create a new one using the clips as a reference - entry_point = 0; - - self_created_sequence = olive::project::CreateSequenceFromMedia(media_list); - seq = self_created_sequence.get(); - } else { - entry_point = ParentTimeline()->getTimelineFrameFromScreenPoint(event->pos().x()); - ParentTimeline()->drag_frame_start = entry_point + getFrameFromScreenPoint(ParentTimeline()->zoom, 50); - ParentTimeline()->drag_track_start = sequence_->FirstTrack(type_); - } - - ParentTimeline()->ghosts = olive::timeline::CreateGhostsFromMedia(seq, entry_point, media_list); - - ParentTimeline()->importing = true; - } -} - -void TimelineView::dragMoveEvent(QDragMoveEvent *event) { - if (ParentTimeline()->importing) { - event->acceptProposedAction(); - - if (sequence() != nullptr) { - QPoint pos = event->pos(); - ParentTimeline()->scroll_to_frame(ParentTimeline()->getTimelineFrameFromScreenPoint(event->pos().x())); - update_ghosts(pos, event->keyboardModifiers() & Qt::ShiftModifier); - ParentTimeline()->move_insert = ((event->keyboardModifiers() & Qt::ControlModifier) && (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER || ParentTimeline()->importing)); - update_ui(false); - } - } -} - -void TimelineView::wheelEvent(QWheelEvent *event) { - static_cast(parent())->wheelEvent(event); -} - -void TimelineView::dragLeaveEvent(QDragLeaveEvent* event) { - event->accept(); - if (ParentTimeline()->importing) { - if (ParentTimeline()->importing_files) { - olive::undo_stack.undo(); - } - ParentTimeline()->importing_files = false; - ParentTimeline()->ghosts.clear(); - ParentTimeline()->importing = false; - update_ui(false); - } - if (self_created_sequence != nullptr) { - self_created_sequence.reset(); - self_created_sequence = nullptr; - } -} - -void TimelineView::delete_area_under_ghosts(ComboAction* ca, Sequence* s) { - // delete areas before adding - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - delete_areas.append(ParentTimeline()->ghosts.at(i).ToSelection()); - } - s->DeleteAreas(ca, delete_areas, false); -} - -void TimelineView::insert_clips(ComboAction* ca, Sequence* s) { - bool ripple_old_point = true; - - long earliest_old_point = LONG_MAX; - long latest_old_point = LONG_MIN; - - long earliest_new_point = LONG_MAX; - long latest_new_point = LONG_MIN; - - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - - earliest_old_point = qMin(earliest_old_point, g.old_in); - latest_old_point = qMax(latest_old_point, g.old_out); - earliest_new_point = qMin(earliest_new_point, g.in); - latest_new_point = qMax(latest_new_point, g.out); - - if (g.clip != nullptr) { - ignore_clips.append(g.clip); - } else { - // don't try to close old gap if importing - ripple_old_point = false; - } - } - - QVector sequence_clips = s->GetAllClips(); - for (int i=0;ighosts.size();j++) { - if (ParentTimeline()->ghosts.at(j).clip == c) { - found = true; - break; - } - } - if (!found) { - if (c->timeline_in() < earliest_new_point && c->timeline_out() > earliest_new_point) { - s->SplitClipAtPositions(ca, c, {earliest_new_point}, true); - } - - // determine if we should close the gap the old clips left behind - if (ripple_old_point - && !((c->timeline_in() < earliest_old_point && c->timeline_out() <= earliest_old_point) || (c->timeline_in() >= latest_old_point && c->timeline_out() > latest_old_point)) - && !ignore_clips.contains(c)) { - ripple_old_point = false; - } - } - } - - long ripple_length = (latest_new_point - earliest_new_point); - - s->Ripple(ca, earliest_new_point, ripple_length, ignore_clips); - - if (ripple_old_point) { - // works for moving later clips earlier but not earlier to later - long second_ripple_length = (earliest_old_point - latest_old_point); - - s->Ripple(ca, latest_old_point, second_ripple_length, ignore_clips); - - if (earliest_old_point < earliest_new_point) { - for (int i=0;ighosts.size();i++) { - Ghost& g = ParentTimeline()->ghosts[i]; - g.in += second_ripple_length; - g.out += second_ripple_length; - } - - QVector sequence_selections = s->Selections(); - for (int i=0;iSetSelections(sequence_selections); - } - } -} - -void TimelineView::dropEvent(QDropEvent* event) { - if (ParentTimeline()->importing && ParentTimeline()->ghosts.size() > 0) { - event->acceptProposedAction(); - - ComboAction* ca = new ComboAction(); - - Sequence* s = sequence(); - - // if we're dropping into nothing, create a new sequences based on the clip being dragged - if (s == nullptr) { - s = self_created_sequence.get(); - olive::project_model.CreateSequence(ca, self_created_sequence, true, nullptr); - self_created_sequence = nullptr; - } else if (event->keyboardModifiers() & Qt::ControlModifier) { - insert_clips(ca, s); - } else { - delete_area_under_ghosts(ca, s); - } - - s->AddClipsFromGhosts(ca, ParentTimeline()->ghosts); - - ParentTimeline()->ghosts.clear(); - - ParentTimeline()->importing = false; - - olive::undo_stack.push(ca); - - setFocus(); - - update_ui(true); - } -} - -void TimelineView::mouseDoubleClickEvent(QMouseEvent *event) { - if (sequence() != nullptr) { - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_EDIT) { - Clip* clip = GetClipAtCursor(); - if (clip != nullptr) { - if (!(event->modifiers() & Qt::ShiftModifier)) { - sequence()->ClearSelections(); - } - clip->track()->SelectClip(clip); - update_ui(false); - } - } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER) { - Clip* c = GetClipAtCursor(); - if (c != nullptr) { - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - Timeline::OpenSequence(c->media()->to_sequence()); - } - } - } - } -} - -bool TimelineView::current_tool_shows_cursor() { - return (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_EDIT - || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RAZOR - || ParentTimeline()->creating); -} - -Clip *TimelineView::GetClipAtCursor() -{ - if (ParentTimeline()->cursor_track == nullptr) { - return nullptr; - } - - return ParentTimeline()->cursor_track->GetClipFromPoint(ParentTimeline()->cursor_frame); -} - -QVector TimelineView::GetSplitTracksFromMouseCoords(bool also_split_links, long frame, int top, int bottom) -{ - // Convert top and bottom coords to global coordinates used by GetTracksInRectangle() - int global_top = mapToGlobal(QPoint(0, top)).y(); - int global_bottom = mapToGlobal(QPoint(0, bottom)).y(); - - // Get the current tracks in this mouse range - QVector split_tracks = ParentTimeline()->GetTracksInRectangle(global_top, global_bottom); - - // If we're also splitting links, loop through each track and search for clips that will be split at this point - if (also_split_links) { - - // Cache array size because we'll be adding to it and don't want to cause an infinite loop - int split_track_size = split_tracks.size(); - for (int i=0;iClipCount();j++) { - Clip* c = track->GetClip(j).get(); - - // Check if this clip is going to be split at this frame - if (c->timeline_in() < frame && c->timeline_out() > frame) { - - // Loop through clip's links for more tracks to split - for (int k=0;klinked.size();k++) { - Track* link_track = c->linked.at(k)->track(); - if (!split_tracks.contains(link_track)) { - split_tracks.append(link_track); - } - } - - // Break because there will only be one clip active at this frame per track - break; - } - } - } - } - - return split_tracks; -} - -void TimelineView::mousePressEvent(QMouseEvent *event) { - if (sequence() != nullptr) { - - int effective_tool = olive::timeline::current_tool; - - // some user actions will override which tool we'll be using - if (event->button() == Qt::MiddleButton) { - effective_tool = olive::timeline::TIMELINE_TOOL_HAND; - ParentTimeline()->creating = false; - } else if (event->button() == Qt::RightButton) { - effective_tool = olive::timeline::TIMELINE_TOOL_MENU; - ParentTimeline()->creating = false; - } - - // ensure cursor_frame and cursor_track are up to date - mouseMoveEvent(event); - - // store current cursor positions - ParentTimeline()->drag_x_start = event->pos().x(); - ParentTimeline()->drag_y_start = event->pos().y(); - - // store current frame/tracks as the values to start dragging from - ParentTimeline()->drag_frame_start = ParentTimeline()->cursor_frame; - ParentTimeline()->drag_track_start = ParentTimeline()->cursor_track; - - // get the clip the user is currently hovering over, priority to trim_target set from mouseMoveEvent - Clip* hovered_clip = ParentTimeline()->trim_target == nullptr ? - GetClipAtCursor() - : ParentTimeline()->trim_target; - - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool alt = (event->modifiers() & Qt::AltModifier); - - // Normal behavior is to reset selections to zero when clicking, but if Shift is held, we add selections - // to the existing selections. `selection_offset` is the index to change selections from (and we don't touch - // any prior to that) - if (shift) { - ParentTimeline()->selection_cache = sequence()->Selections(); - } else { - ParentTimeline()->selection_cache.clear(); - } - - // if the user is creating an object - if (ParentTimeline()->creating) { - olive::TrackType create_type = olive::kTypeVideo; - switch (ParentTimeline()->creating_object) { - case olive::timeline::ADD_OBJ_TITLE: - case olive::timeline::ADD_OBJ_SOLID: - case olive::timeline::ADD_OBJ_BARS: - break; - case olive::timeline::ADD_OBJ_TONE: - case olive::timeline::ADD_OBJ_NOISE: - case olive::timeline::ADD_OBJ_AUDIO: - create_type = olive::kTypeAudio; - break; - } - - // if the track the user clicked is correct for the type of object we're adding - if (type_ == create_type) { - Ghost g; - g.in = g.old_in = g.out = g.old_out = ParentTimeline()->drag_frame_start; - - g.track = ParentTimeline()->drag_track_start; - if (g.track == nullptr) { - QVector track_list = sequence_->GetTrackList(type_); - g.track = track_list.last(); - ParentTimeline()->drag_track_start = track_list.last(); - g.track_movement = getTrackIndexFromScreenPoint(event->pos().y()) - g.track->Index(); - } - - g.trim_type = olive::timeline::TRIM_OUT; - ParentTimeline()->ghosts.append(g); - - ParentTimeline()->moving_init = true; - ParentTimeline()->moving_proc = true; - } - } else { - - // pass through tools to determine what action we'll be starting - switch (effective_tool) { - - // many tools share pointer-esque behavior - case olive::timeline::TIMELINE_TOOL_POINTER: - case olive::timeline::TIMELINE_TOOL_RIPPLE: - case olive::timeline::TIMELINE_TOOL_SLIP: - case olive::timeline::TIMELINE_TOOL_ROLLING: - case olive::timeline::TIMELINE_TOOL_SLIDE: - case olive::timeline::TIMELINE_TOOL_MENU: - { - if (track_resizing && effective_tool != olive::timeline::TIMELINE_TOOL_MENU) { - - // if the cursor is currently hovering over a track, init track resizing - ParentTimeline()->moving_init = true; - - } else { - - // check if we're currently hovering over a clip or not - if (hovered_clip != nullptr) { - - if (hovered_clip->IsSelected()) { - - if (shift) { - - // if the user clicks a selected clip while holding shift, deselect the clip - hovered_clip->track()->DeselectArea(hovered_clip->timeline_in(), hovered_clip->timeline_out()); - - // if the user isn't holding alt, also deselect all of its links as well - if (!alt) { - for (int i=0;ilinked.size();i++) { - Clip* link = hovered_clip->linked.at(i); - link->track()->DeselectArea(link->timeline_in(), link->timeline_out()); - } - } - - } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER - && ParentTimeline()->transition_select != kTransitionNone) { - - // if the clip was selected by then the user clicked a transition, de-select the clip and its links - // and select the transition only - - hovered_clip->track()->DeselectArea(hovered_clip->timeline_in(), hovered_clip->timeline_out()); - - for (int i=0;ilinked.size();i++) { - Clip* link = hovered_clip->linked.at(i); - link->track()->DeselectArea(link->timeline_in(), link->timeline_out()); - } - - long s_in = 0; - long s_out = 0; - - // select the transition only - if (ParentTimeline()->transition_select == kTransitionOpening - && hovered_clip->opening_transition != nullptr) { - s_in = hovered_clip->timeline_in(); - - if (hovered_clip->opening_transition->secondary_clip != nullptr) { - s_in -= hovered_clip->opening_transition->get_true_length(); - } - - s_out = hovered_clip->timeline_in() + hovered_clip->opening_transition->get_true_length(); - - } else if (ParentTimeline()->transition_select == kTransitionClosing - && hovered_clip->closing_transition != nullptr) { - - s_in = hovered_clip->timeline_out() - hovered_clip->closing_transition->get_true_length(); - s_out = hovered_clip->timeline_out(); - - if (hovered_clip->closing_transition->secondary_clip != nullptr) { - s_out += hovered_clip->closing_transition->get_true_length(); - } - } - hovered_clip->track()->SelectArea(s_in, s_out); - } - - } else { - - // if the clip is not already selected - - // if shift is NOT down, we change clear all current selections - if (!shift) { - sequence()->ClearSelections(); - } - - long s_in = hovered_clip->timeline_in(); - long s_out = hovered_clip->timeline_out(); - - // if user is using the pointer tool, they may be trying to select a transition - // check if the use is hovering over a transition - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER) { - if (ParentTimeline()->transition_select == kTransitionOpening) { - // move the selection to only select the transitoin - s_out = hovered_clip->timeline_in() + hovered_clip->opening_transition->get_true_length(); - - // if the transition is a "shared" transition, adjust the selection to select both sides - if (hovered_clip->opening_transition->secondary_clip != nullptr) { - s_in -= hovered_clip->opening_transition->get_true_length(); - } - } else if (ParentTimeline()->transition_select == kTransitionClosing) { - // move the selection to only select the transitoin - s_in = hovered_clip->timeline_out() - hovered_clip->closing_transition->get_true_length(); - - // if the transition is a "shared" transition, adjust the selection to select both sides - if (hovered_clip->closing_transition->secondary_clip != nullptr) { - s_out += hovered_clip->closing_transition->get_true_length(); - } - } - } - - // add the selection to the array - hovered_clip->track()->SelectArea(s_in, s_out); - - // if the config is set to also seek with selections, do so now - if (olive::config.select_also_seeks) { - panel_sequence_viewer->seek(hovered_clip->timeline_in()); - } - - // if alt is not down, select links (provided we're not selecting transitions) - if (!alt && ParentTimeline()->transition_select == kTransitionNone) { - - for (int i=0;ilinked.size();i++) { - - Clip* link = hovered_clip->linked.at(i); - - // check if the clip is already selected - if (!link->IsSelected()) { - link->track()->SelectClip(link); - } - - } - - } - } - - // authorize the starting of a move action if the mouse moves after this - if (effective_tool != olive::timeline::TIMELINE_TOOL_MENU) { - ParentTimeline()->moving_init = true; - } - - } else { - - // if the user did not click a clip at all, we start a rectangle selection - - if (!shift) { - sequence()->ClearSelections(); - } - - ParentTimeline()->rect_select_init = true; - } - - // update everything - update_ui(false); - } - } - break; - case olive::timeline::TIMELINE_TOOL_HAND: - - // initiate moving with the hand tool - ParentTimeline()->hand_moving = true; - - break; - case olive::timeline::TIMELINE_TOOL_EDIT: - - // if the config is set to seek with the edit tool, do so now - if (olive::config.edit_tool_also_seeks) { - panel_sequence_viewer->seek(ParentTimeline()->drag_frame_start); - } - - // initiate selecting - ParentTimeline()->selecting = true; - - break; - case olive::timeline::TIMELINE_TOOL_RAZOR: - { - - // initiate razor tool - ParentTimeline()->splitting = true; - - ParentTimeline()->split_tracks = GetSplitTracksFromMouseCoords(!alt, - ParentTimeline()->drag_frame_start, - event->pos().y(), - event->pos().y()); - - update_ui(false); - } - break; - case olive::timeline::TIMELINE_TOOL_TRANSITION: - { - - // if there is a clip to run the transition tool on, initiate the transition tool - if (ParentTimeline()->transition_tool_open_clip != nullptr - || ParentTimeline()->transition_tool_close_clip != nullptr) { - ParentTimeline()->transition_tool_init = true; - } - - } - break; - } - } - } -} - -void make_room_for_transition(ComboAction* ca, - Clip* c, - int type, - long transition_start, - long transition_end, - bool delete_old_transitions, - long timeline_in = -1, - long timeline_out = -1) { - // it's possible to specify other in/out points for the clip, but default behavior is to use the ones existing - if (timeline_in < 0) { - timeline_in = c->timeline_in(); - } - if (timeline_out < 0) { - timeline_out = c->timeline_out(); - } - - // make room for transition - if (type == kTransitionOpening) { - if (delete_old_transitions && c->opening_transition != nullptr) { - ca->append(new DeleteTransitionCommand(c->opening_transition)); - } - if (c->closing_transition != nullptr) { - if (transition_end >= c->timeline_out()) { - ca->append(new DeleteTransitionCommand(c->closing_transition)); - } else if (transition_end > c->timeline_out() - c->closing_transition->get_true_length()) { - ca->append(new ModifyTransitionCommand(c->closing_transition, c->timeline_out() - transition_end)); - } - } - } else { - if (delete_old_transitions && c->closing_transition != nullptr) { - ca->append(new DeleteTransitionCommand(c->closing_transition)); - } - if (c->opening_transition != nullptr) { - if (transition_start <= c->timeline_in()) { - ca->append(new DeleteTransitionCommand(c->opening_transition)); - } else if (transition_start < c->timeline_in() + c->opening_transition->get_true_length()) { - ca->append(new ModifyTransitionCommand(c->opening_transition, transition_start - c->timeline_in())); - } - } - } -} - -void TimelineView::VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, long transition_start, long transition_end) { - // in case the user made the transition larger than the clips, we're going to delete everything under - // the transition ghost and extend the clips to the transition's coordinates as necessary - - if (open == nullptr && close == nullptr) { - qWarning() << "VerifyTransitionsAfterCreating() called with two null clips"; - return; - } - - // determine whether this is a "shared" transition between to clips or not - bool shared_transition = (open != nullptr && close != nullptr); - - Track* track = nullptr; - - // first we set the clips to "undeletable" so they aren't affected by delete_areas_and_relink() - if (open != nullptr) { - open->undeletable = true; - track = open->track(); - } - if (close != nullptr) { - close->undeletable = true; - track = close->track(); - } - - // set the area to delete to the transition's coordinates and clear it - QVector areas; - areas.append(Selection(transition_start, transition_end, track)); - sequence()->DeleteAreas(ca, areas, false); - - // set the clips back to undeletable now that we're done - if (open != nullptr) { - open->undeletable = false; - } - if (close != nullptr) { - close->undeletable = false; - } - - // loop through both kinds of transition - for (int t=kTransitionOpening;t<=kTransitionClosing;t++) { - - Clip* clip_ref = (t == kTransitionOpening) ? open : close; - - // if we have an opening transition: - if (clip_ref != nullptr) { - - // make_room_for_transition will adjust the opposite transition to make space for this one, - // for example if the user makes an opening transition that overlaps the closing transition, it'll resize - // or even delete the closing transition if necessary (and vice versa) - - make_room_for_transition(ca, clip_ref, t, transition_start, transition_end, true); - - // check if the transition coordinates require the clip to be resized - if (transition_start < clip_ref->timeline_in() || transition_end > clip_ref->timeline_out()) { - - long new_in, new_out; - - if (t == kTransitionOpening) { - - // if the transition is shared, it doesn't matter if the transition extend beyond the in point since - // that'll be "absorbed" by the other clip - new_in = (shared_transition) ? open->timeline_in() : qMin(transition_start, open->timeline_in()); - - new_out = qMax(transition_end, open->timeline_out()); - - } else { - - new_in = qMin(transition_start, close->timeline_in()); - - // if the transition is shared, it doesn't matter if the transition extend beyond the out point since - // that'll be "absorbed" by the other clip - new_out = (shared_transition) ? close->timeline_out() : qMax(transition_end, close->timeline_out()); - - } - - - - clip_ref->Move(ca, - new_in, - new_out, - clip_ref->clip_in() - (clip_ref->timeline_in() - new_in), - clip_ref->track()); - } - } - } -} - -int TimelineView::GetTotalAreaHeight() -{ - // start by adding a track height worth of padding - int panel_height = olive::timeline::kTrackDefaultHeight; - - QVector track_list = sequence_->GetTrackList(type_); - for (int i=0;iheight(); - } - - return panel_height; -} - -void TimelineView::mouseReleaseEvent(QMouseEvent *event) { - QToolTip::hideText(); - if (sequence() != nullptr) { - bool alt = (event->modifiers() & Qt::AltModifier); - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool ctrl = (event->modifiers() & Qt::ControlModifier); - - if (event->button() == Qt::LeftButton) { - ComboAction* ca = new ComboAction(); - bool push_undo = false; - - if (ParentTimeline()->creating) { - if (ParentTimeline()->ghosts.size() > 0) { - const Ghost& g = ParentTimeline()->ghosts.at(0); - - if (ParentTimeline()->creating_object == olive::timeline::ADD_OBJ_AUDIO) { - olive::MainWindow->statusBar()->clearMessage(); - panel_sequence_viewer->cue_recording(qMin(g.in, g.out), qMax(g.in, g.out), g.track); - ParentTimeline()->creating = false; - } else if (g.in != g.out) { - ClipPtr c = std::make_shared(g.track->Sibling(g.track_movement)); - c->set_media(nullptr, 0); - c->set_timeline_in(qMin(g.in, g.out)); - c->set_timeline_out(qMax(g.in, g.out)); - c->set_clip_in(0); - c->set_color(192, 192, 64); - - if (ctrl) { - insert_clips(ca, sequence()); - } else { - sequence()->DeleteAreas(ca, {c->ToSelection()}, false); - } - - QVector add; - add.append(c); - ca->append(new AddClipCommand(add)); - - if (c->type() == olive::kTypeVideo && olive::config.add_default_effects_to_clips) { - // default video effects (before custom effects) - c->effects.append(olive::node_library[kTransformEffect]->Create(c.get())); - } - - switch (ParentTimeline()->creating_object) { - case olive::timeline::ADD_OBJ_TITLE: - c->set_name(tr("Title")); - c->effects.append(olive::node_library[kRichTextInput]->Create(c.get())); - break; - case olive::timeline::ADD_OBJ_SOLID: - c->set_name(tr("Solid Color")); - c->effects.append(olive::node_library[kSolidInput]->Create(c.get())); - break; - case olive::timeline::ADD_OBJ_BARS: - { - c->set_name(tr("Bars")); - OldEffectNodePtr e = olive::node_library[kSolidInput]->Create(c.get()); - - // Auto-select bars - SolidEffect* solid_effect = static_cast(e.get()); - solid_effect->SetType(SolidEffect::SOLID_TYPE_BARS); - - c->effects.append(e); - } - break; - case olive::timeline::ADD_OBJ_TONE: - c->set_name(tr("Tone")); - c->effects.append(olive::node_library[kToneInput]->Create(c.get())); - break; - case olive::timeline::ADD_OBJ_NOISE: - c->set_name(tr("Noise")); - c->effects.append(olive::node_library[kNoiseInput]->Create(c.get())); - break; - default: - break; - } - - if (c->type() == olive::kTypeAudio && olive::config.add_default_effects_to_clips) { - // default audio effects (after custom effects) - c->effects.append(olive::node_library[kVolumeEffect]->Create(c.get())); - c->effects.append(olive::node_library[kPanEffect]->Create(c.get())); - } - - push_undo = true; - - if (!shift) { - ParentTimeline()->creating = false; - } - } - } - } else if (ParentTimeline()->moving_proc) { - - // see if any clips actually moved, otherwise we don't need to do any processing - // (perhaps this could be moved further up to cover more actions?) - - bool process_moving = false; - - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - if (g.in != g.old_in - || g.out != g.old_out - || g.clip_in != g.old_clip_in - || g.track_movement != 0) { - process_moving = true; - break; - } - } - - if (process_moving) { - - const Ghost& first_ghost = ParentTimeline()->ghosts.at(0); - - // start a ripple movement - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE) { - - // ripple_length becomes the length/number of frames we trimmed - // ripple_point is the "axis" around which we move all the clips, any clips after it get moved - long ripple_length; - long ripple_point = LONG_MAX; - - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { - - // it's assumed that all the ghosts rippled by the same length, so we just take the difference of the - // first ghost here - ripple_length = first_ghost.old_in - first_ghost.in; - - // for in trimming movements we also move the selections forward (unnecessary for out trimming since - // the selected clips more or less stay in the same place) - /* - for (int i=0;iselections.size();i++) { - sequence()->selections[i].in += ripple_length; - sequence()->selections[i].out += ripple_length; - } - */ - } else { - - // use the out points for length if the user trimmed the out point - ripple_length = first_ghost.old_out - ParentTimeline()->ghosts.at(0).out; - - } - - // build a list of "ignore clips" that won't get affected by ripple_clips() below - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - - // for the same reason that we pushed selections forward above, for in trimming, - // we push the ghosts forward here - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { - ignore_clips.append(g.clip); - ParentTimeline()->ghosts[i].in += ripple_length; - ParentTimeline()->ghosts[i].out += ripple_length; - } - - // find the earliest ripple point - long comp_point = (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) ? g.old_in : g.old_out; - ripple_point = qMin(ripple_point, comp_point); - } - - // if this was out trimming, flip the direction of the ripple - if (ParentTimeline()->trim_type == olive::timeline::TRIM_OUT) ripple_length = -ripple_length; - - // finally, ripple everything - sequence()->Ripple(ca, ripple_point, ripple_length, ignore_clips); - } - - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER - && (event->modifiers() & Qt::AltModifier) - && ParentTimeline()->trim_target == nullptr) { - - // if the user was holding alt (and not trimming), we duplicate clips rather than move them - QVector old_clips; - QVector new_clips; - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - if (g.old_in != g.in || g.old_out != g.out || g.track_movement != 0 || g.clip_in != g.old_clip_in) { - - // create copy of clip - ClipPtr c = g.clip->copy(g.track->Sibling(g.track_movement)); - - c->set_timeline_in(g.in); - c->set_timeline_out(g.out); - - delete_areas.append(g.ToSelection()); - - old_clips.append(g.clip); - new_clips.append(c); - - } - } - - if (new_clips.size() > 0) { - - // delete anything under the new clips - sequence()->DeleteAreas(ca, delete_areas, false); - - // relink duplicated clips - olive::timeline::RelinkClips(old_clips, new_clips); - - // add them - ca->append(new AddClipCommand(new_clips)); - - } - - } else { - - // if we're not holding alt, this will just be a move - - // if the user is holding ctrl, perform an insert rather than an overwrite - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER && ctrl) { - - insert_clips(ca, sequence()); - - } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIDE) { - - // if the user is not holding ctrl, we start standard clip movement - - // delete everything under the new clips - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) - const Ghost& g = ParentTimeline()->ghosts.at(i); - - // set clip to undeletable so it's unaffected by delete_areas_and_relink() below - g.clip->undeletable = true; - - // if the user was moving a transition make sure they're undeletable too - if (g.transition != nullptr) { - g.transition->parent_clip->undeletable = true; - if (g.transition->secondary_clip != nullptr) { - g.transition->secondary_clip->undeletable = true; - } - } - - // set area to delete - delete_areas.append(g.ToSelection()); - } - - sequence()->DeleteAreas(ca, delete_areas, false); - - // clean up, i.e. make everything not undeletable again - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - g.clip->undeletable = false; - - if (g.transition != nullptr) { - g.transition->parent_clip->undeletable = false; - if (g.transition->secondary_clip != nullptr) { - g.transition->secondary_clip->undeletable = false; - } - } - } - } - - // finally, perform actual movement of clips - for (int i=0;ighosts.size();i++) { - Ghost& g = ParentTimeline()->ghosts[i]; - - Clip* c = g.clip; - - if (g.transition == nullptr) { - - // if this was a clip rather than a transition - - c->Move(ca, - (g.in - g.old_in), - (g.out - g.old_out), - (g.clip_in - g.old_clip_in), - g.track->Sibling(g.track_movement), - false, - true); - - } else { - - // if the user was moving a transition - - bool is_opening_transition = (g.transition == c->opening_transition); - long new_transition_length = g.out - g.in; - if (g.transition->secondary_clip != nullptr) new_transition_length >>= 1; - ca->append( - new ModifyTransitionCommand(is_opening_transition ? c->opening_transition : c->closing_transition, - new_transition_length) - ); - - long clip_length = c->length(); - - if (g.transition->secondary_clip != nullptr) { - - // if this is a shared transition - if (g.in != g.old_in && g.trim_type == olive::timeline::TRIM_NONE) { - long movement = g.in - g.old_in; - - // check if the transition is going to extend the out point (opening clip) - long timeline_out_movement = 0; - if (g.out > g.transition->parent_clip->timeline_out()) { - timeline_out_movement = g.out - g.transition->parent_clip->timeline_out(); - } - - // check if the transition is going to extend the in point (closing clip) - long timeline_in_movement = 0; - if (g.in < g.transition->secondary_clip->timeline_in()) { - timeline_in_movement = g.in - g.transition->secondary_clip->timeline_in(); - } - - g.transition->parent_clip->Move(ca, movement, timeline_out_movement, movement, g.transition->parent_clip->track(), false, true); - g.transition->secondary_clip->Move(ca, timeline_in_movement, movement, timeline_in_movement, g.transition->secondary_clip->track(), false, true); - - make_room_for_transition(ca, g.transition->parent_clip, kTransitionOpening, g.in, g.out, false); - make_room_for_transition(ca, g.transition->secondary_clip, kTransitionClosing, g.in, g.out, false); - - } - - } else if (is_opening_transition) { - - if (g.in != g.old_in) { - // if transition is going to make the clip bigger, make the clip bigger - - // check if the transition is going to extend the out point - long timeline_out_movement = 0; - if (g.out > g.transition->parent_clip->timeline_out()) { - timeline_out_movement = g.out - g.transition->parent_clip->timeline_out(); - } - - c->Move(ca, - (g.in - g.old_in), - timeline_out_movement, - (g.clip_in - g.old_clip_in), - g.track, - false, - true); - clip_length -= (g.in - g.old_in); - } - - make_room_for_transition(ca, c, kTransitionOpening, g.in, g.out, false); - - } else { - - if (g.out != g.old_out) { - - // check if the transition is going to extend the in point - long timeline_in_movement = 0; - if (g.in < g.transition->parent_clip->timeline_in()) { - timeline_in_movement = g.in - g.transition->parent_clip->timeline_in(); - } - - // if transition is going to make the clip bigger, make the clip bigger - c->Move(ca, timeline_in_movement, (g.out - g.old_out), timeline_in_movement, c->track(), false, true); - clip_length += (g.out - g.old_out); - } - - make_room_for_transition(ca, c, kTransitionClosing, g.in, g.out, false); - - } - } - } - - // time to verify the transitions of moved clips - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - - // only applies to moving clips, transitions are verified above instead - if (g.transition == nullptr) { - Clip* c = g.clip; - - long new_clip_length = g.out - g.in; - - // using a for loop between constants to repeat the same steps for the opening and closing transitions - for (int t=kTransitionOpening;t<=kTransitionClosing;t++) { - - TransitionPtr transition = (t == kTransitionOpening) ? c->opening_transition : c->closing_transition; - - // check the whether the clip has a transition here - if (transition != nullptr) { - - // if the new clip size exceeds the opening transition's length, resize the transition - if (new_clip_length < transition->get_true_length()) { - ca->append(new ModifyTransitionCommand(transition, new_clip_length)); - } - - // check if the transition is a shared transition (it'll never have a secondary clip if it isn't) - if (transition->secondary_clip != nullptr) { - - // check if the transition's "edge" is going to move - if ((t == kTransitionOpening && g.in != g.old_in) - || (t == kTransitionClosing && g.out != g.old_out) - || (g.track_movement != 0)) { - - // if we're here, this clip shares its opening transition as the closing transition of another - // clip (or vice versa), and the in point is moving, so we may have to account for this - - // the other clip sharing this transition may be moving as well, meaning we don't have to do - // anything - - bool split = true; - - // loop through ghosts to find out - - // for a shared transition, the secondary_clip will always be the closing transition side and - // the parent_clip will always be the opening transition side - Clip* search_clip = (t == kTransitionOpening) - ? transition->secondary_clip : transition->parent_clip; - - for (int j=0;jghosts.size();j++) { - const Ghost& other_clip_ghost = ParentTimeline()->ghosts.at(j); - - if (other_clip_ghost.clip == search_clip) { - - // we found the other clip in the current ghosts/selections - - // see if it's destination edge will be equal to this ghost's edge (in which case the - // transition doesn't need to change) - // - // also only do this if j is less than i, because it only needs to happen once and chances are - // the other clip already - - bool edges_still_touch = (other_clip_ghost.track_movement == g.track_movement); - - if (edges_still_touch) { - if (t == kTransitionOpening) { - edges_still_touch = (other_clip_ghost.out == g.in); - } else { - edges_still_touch = (other_clip_ghost.in == g.out); - } - } - - if (edges_still_touch || j < i) { - split = false; - } - - break; - } - } - - if (split) { - // separate shared transition into one transition for each clip - - if (t == kTransitionOpening) { - - // set transition to single-clip mode - ca->append(new SetPointer(reinterpret_cast(&transition->secondary_clip), - nullptr)); - - // create duplicate transition for other clip - ca->append(new AddTransitionCommand(nullptr, - transition->secondary_clip, - transition, - kInvalidNode, - 0)); - - } else { - - // set transition to single-clip mode - ca->append(new SetPointer(reinterpret_cast(&transition->secondary_clip), - nullptr)); - - // that transition will now attach to the other clip, so we duplicate it for this one - - // create duplicate transition for this clip - ca->append(new AddTransitionCommand(nullptr, - transition->secondary_clip, - transition, - kInvalidNode, - 0)); - - } - } - - } - } - } - } - } - } - } - - // move selections to match new ghosts - QVector new_selections; - for (int i=0;ighosts.size();i++) { - new_selections.append(ParentTimeline()->ghosts.at(i).ToSelection()); - } - ca->append(new SetSelectionsCommand(sequence(), sequence()->Selections(), new_selections)); - - push_undo = true; - - } - } else if (ParentTimeline()->selecting || ParentTimeline()->rect_select_proc) { - } else if (ParentTimeline()->transition_tool_proc) { - const Ghost& g = ParentTimeline()->ghosts.at(0); - - // if the transition is greater than 0 length (if it is 0, we make nothing) - if (g.in != g.out) { - - // get transition coordinates on the timeline - long transition_start = qMin(g.in, g.out); - long transition_end = qMax(g.in, g.out); - - // get clip references from tool's cached data - Clip* open = ParentTimeline()->transition_tool_open_clip; - - Clip* close = ParentTimeline()->transition_tool_close_clip; - - - - // if it's shared, the transition length is halved (one half for each clip will result in the full length) - long transition_length = transition_end - transition_start; - if (open != nullptr && close != nullptr) { - transition_length /= 2; - } - - VerifyTransitionsAfterCreating(ca, open, close, transition_start, transition_end); - - // finally, add the transition to these clips - ca->append(new AddTransitionCommand(open, - close, - nullptr, - ParentTimeline()->transition_tool_meta, - transition_length)); - - push_undo = true; - } - } else if (ParentTimeline()->splitting) { - - QVector split_tracks = GetSplitTracksFromMouseCoords(false, - ParentTimeline()->drag_frame_start, - ParentTimeline()->drag_y_start, - event->pos().y()); - - for (int i=0;iGetClipFromPoint(ParentTimeline()->drag_frame_start); - if (split_index != nullptr - && sequence()->SplitClipAtPositions(ca, split_index, {ParentTimeline()->drag_frame_start}, !alt)) { - push_undo = true; - } - } - } - - // remove duplicate selections - sequence()->TidySelections(); - - if (push_undo) { - olive::undo_stack.push(ca); - } else { - delete ca; - } - - // destroy all ghosts - ParentTimeline()->ghosts.clear(); - - // clear split tracks - ParentTimeline()->split_tracks.clear(); - - ParentTimeline()->selecting = false; - ParentTimeline()->moving_proc = false; - ParentTimeline()->moving_init = false; - ParentTimeline()->splitting = false; - olive::timeline::snapped = false; - ParentTimeline()->rect_select_init = false; - ParentTimeline()->rect_select_proc = false; - ParentTimeline()->transition_tool_init = false; - ParentTimeline()->transition_tool_proc = false; - pre_clips.clear(); - post_clips.clear(); - - update_ui(true); - } - ParentTimeline()->hand_moving = false; - } -} - -void TimelineView::init_ghosts() { - for (int i=0;ighosts.size();i++) { - Ghost& g = ParentTimeline()->ghosts[i]; - Clip* c = g.clip; - - g.track = c->track(); - g.clip_in = g.old_clip_in = c->clip_in(); - - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIP) { - g.clip_in = g.old_clip_in = c->clip_in(true); - g.in = g.old_in = c->timeline_in(true); - g.out = g.old_out = c->timeline_out(true); - g.ghost_length = g.old_out - g.old_in; - } else if (g.transition == nullptr) { - // this ghost is for a clip - g.in = g.old_in = c->timeline_in(); - g.out = g.old_out = c->timeline_out(); - g.ghost_length = g.old_out - g.old_in; - } else if (g.transition == c->opening_transition) { - g.in = g.old_in = c->timeline_in(true); - g.ghost_length = c->opening_transition->get_length(); - g.out = g.old_out = g.in + g.ghost_length; - } else if (g.transition == c->closing_transition) { - g.out = g.old_out = c->timeline_out(true); - g.ghost_length = c->closing_transition->get_length(); - g.in = g.old_in = g.out - g.ghost_length; - g.clip_in = g.old_clip_in = c->clip_in() + c->length() - c->closing_transition->get_true_length(); - } - - // used for trim ops - g.media_length = c->media_length(); - } - /* - for (int i=0;iselections.size();i++) { - Selection& s = sequence()->selections[i]; - s.old_in = s.in; - s.old_out = s.out; - s.old_track = s.track; - } - */ -} - -void validate_transitions(Clip* c, int transition_type, long& frame_diff) { - long validator; - - if (transition_type == kTransitionOpening) { - // prevent from going below 0 on the timeline - validator = c->timeline_in() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent from going below 0 for the media - validator = c->clip_in() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent transition from exceeding media length - validator -= c->media_length(); - if (validator > 0) frame_diff -= validator; - } else { - // prevent from going below 0 on the timeline - validator = c->timeline_out() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent from going below 0 for the media - validator = c->clip_in() + c->length() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent transition from exceeding media length - validator -= c->media_length(); - if (validator > 0) frame_diff -= validator; - } -} - -void TimelineView::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { - int effective_tool = olive::timeline::current_tool; - if (ParentTimeline()->importing || ParentTimeline()->creating) effective_tool = olive::timeline::TIMELINE_TOOL_POINTER; - - long frame_diff = (lock_frame) ? 0 : ParentTimeline()->getTimelineFrameFromScreenPoint(mouse_pos.x()) - ParentTimeline()->drag_frame_start; - long validator; - long earliest_in_point = LONG_MAX; - int track_diff = getTrackIndexFromScreenPoint(mouse_pos.y()) - ParentTimeline()->drag_track_start->Index(); - - // first try to snap - long fm; - - if (effective_tool != olive::timeline::TIMELINE_TOOL_SLIP) { - // slipping doesn't move the clips so we don't bother snapping for it - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - - // snap ghost's in point - if ((olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_TRANSITION && ParentTimeline()->trim_target == nullptr) - || g.trim_type == olive::timeline::TRIM_IN - || ParentTimeline()->transition_tool_open_clip != nullptr) { - fm = g.old_in + frame_diff; - if (sequence()->SnapPoint(&fm, ParentTimeline()->zoom, true, true, true)) { - frame_diff = fm - g.old_in; - break; - } - } - - // snap ghost's out point - if ((olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_TRANSITION && ParentTimeline()->trim_target == nullptr) - || g.trim_type == olive::timeline::TRIM_OUT - || ParentTimeline()->transition_tool_close_clip != nullptr) { - fm = g.old_out + frame_diff; - if (sequence()->SnapPoint(&fm, ParentTimeline()->zoom, true, true, true)) { - frame_diff = fm - g.old_out; - break; - } - } - - // if the ghost is attached to a clip, snap its markers too - if (ParentTimeline()->trim_target == nullptr - && g.clip != nullptr - && olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_TRANSITION) { - Clip* c = g.clip; - for (int j=0;jget_markers().size();j++) { - long marker_real_time = c->get_markers().at(j).frame + c->timeline_in() - c->clip_in(); - fm = marker_real_time + frame_diff; - if (sequence()->SnapPoint(&fm, ParentTimeline()->zoom, true, true, true)) { - frame_diff = fm - marker_real_time; - break; - } - } - } - } - } - - bool clips_are_movable = (effective_tool == olive::timeline::TIMELINE_TOOL_POINTER || effective_tool == olive::timeline::TIMELINE_TOOL_SLIDE); - - // validate ghosts - long temp_frame_diff = frame_diff; // cache to see if we change it (thus cancelling any snap) - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - Clip* c = nullptr; - if (g.clip != nullptr) { - c = g.clip; - } - - const FootageStream* ms = nullptr; - if (g.clip != nullptr && c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - ms = c->media_stream(); - } - - // validate ghosts for trimming - if (ParentTimeline()->creating) { - // i feel like we might need something here but we haven't so far? - } else if (effective_tool == olive::timeline::TIMELINE_TOOL_SLIP) { - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - // prevent slip moving a clip below 0 clip_in - validator = g.old_clip_in - frame_diff; - if (validator < 0) frame_diff += validator; - - // prevent slip moving clip beyond media length - validator += g.ghost_length; - if (validator > g.media_length) frame_diff += validator - g.media_length; - } - } else if (g.trim_type != olive::timeline::TRIM_NONE) { - if (g.trim_type == olive::timeline::TRIM_IN) { - // prevent clip/transition length from being less than 1 frame long - validator = g.ghost_length - frame_diff; - if (validator < 1) frame_diff -= (1 - validator); - - // prevent timeline in from going below 0 - if (effective_tool != olive::timeline::TIMELINE_TOOL_RIPPLE) { - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } - - // prevent clip_in from going below 0 - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } - } else { - // prevent clip length from being less than 1 frame long - validator = g.ghost_length + frame_diff; - if (validator < 1) frame_diff += (1 - validator); - - // prevent clip length exceeding media length - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + g.ghost_length + frame_diff; - if (validator > g.media_length) frame_diff -= validator - g.media_length; - } - } - - // prevent dual transition from going below 0 on the primary or media length on the secondary - if (g.transition != nullptr && g.transition->secondary_clip != nullptr) { - Clip* otc = g.transition->parent_clip; - Clip* ctc = g.transition->secondary_clip; - - if (g.trim_type == olive::timeline::TRIM_IN) { - frame_diff -= g.transition->get_true_length(); - } else { - frame_diff += g.transition->get_true_length(); - } - - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - - frame_diff = -frame_diff; - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - frame_diff = -frame_diff; - - if (g.trim_type == olive::timeline::TRIM_IN) { - frame_diff += g.transition->get_true_length(); - } else { - frame_diff -= g.transition->get_true_length(); - } - } - - // ripple ops - if (effective_tool == olive::timeline::TIMELINE_TOOL_RIPPLE) { - for (int j=0;jtrim_type == olive::timeline::TRIM_IN) { - validator = post->timeline_in() - frame_diff; - if (validator < 0) frame_diff += validator; - } - - // prevent any post-clips colliding with pre-clips - for (int k=0;ktrack() == post->track()) { - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { - validator = post->timeline_in() - frame_diff - pre->timeline_out(); - if (validator < 0) frame_diff += validator; - } else { - validator = post->timeline_in() + frame_diff - pre->timeline_out(); - if (validator < 0) frame_diff -= validator; - } - } - } - } - } - } else if (clips_are_movable) { // validate ghosts for moving - // prevent clips from moving below 0 on the timeline - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; - - if (g.transition != nullptr) { - if (g.transition->secondary_clip != nullptr) { - // prevent dual transitions from going below 0 on the primary or above media length on the secondary - - validator = g.transition->parent_clip->clip_in(true) + frame_diff; - if (validator < 0) frame_diff -= validator; - - validator = g.transition->secondary_clip->timeline_out(true) - g.transition->secondary_clip->timeline_in(true) - g.transition->get_length() + g.transition->secondary_clip->clip_in(true) + frame_diff; - if (validator < 0) frame_diff -= validator; - - validator = g.transition->parent_clip->clip_in() + frame_diff - g.transition->parent_clip->media_length() + g.transition->get_true_length(); - if (validator > 0) frame_diff -= validator; - - validator = g.transition->secondary_clip->timeline_out(true) - g.transition->secondary_clip->timeline_in(true) + g.transition->secondary_clip->clip_in(true) + frame_diff - g.transition->secondary_clip->media_length(); - if (validator > 0) frame_diff -= validator; - } else { - // prevent clip_in from going below 0 - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } - - // prevent clip length exceeding media length - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + g.ghost_length + frame_diff; - if (validator > g.media_length) frame_diff -= validator - g.media_length; - } - } - } - - // Prevent any clips from going below the "zeroeth" track - - if (ParentTimeline()->importing || g.track->type() == type_) { - - int track_validator = g.track->Index() + track_diff; - if (track_validator < 0) { - track_diff -= track_validator; - } - - } - - } else if (effective_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { - if (ParentTimeline()->transition_tool_open_clip == nullptr - || ParentTimeline()->transition_tool_close_clip == nullptr) { - validate_transitions(c, g.media_stream, frame_diff); - } else { - // open transition clip - Clip* otc = ParentTimeline()->transition_tool_open_clip; - - // close transition clip - Clip* ctc = ParentTimeline()->transition_tool_close_clip; - - if (g.media_stream == kTransitionClosing) { - // swap - Clip* temp = otc; - otc = ctc; - ctc = temp; - } - - // always gets a positive frame_diff - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - - // always gets a negative frame_diff - frame_diff = -frame_diff; - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - frame_diff = -frame_diff; - } - } - } - - // if the above validation changed the frame movement, it's unlikely we're still snapped - if (temp_frame_diff != frame_diff) { - olive::timeline::snapped = false; - } - - // apply changes to ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = ParentTimeline()->ghosts[i]; - - if (effective_tool == olive::timeline::TIMELINE_TOOL_SLIP) { - g.clip_in = g.old_clip_in - frame_diff; - } else if (g.trim_type != olive::timeline::TRIM_NONE) { - long ghost_diff = frame_diff; - - // prevent trimming clips from overlapping each other - for (int j=0;jghosts.size();j++) { - const Ghost& comp = ParentTimeline()->ghosts.at(j); - if (i != j && g.track == comp.track) { - long validator; - if (g.trim_type == olive::timeline::TRIM_IN && comp.out < g.out) { - validator = (g.old_in + ghost_diff) - comp.out; - if (validator < 0) ghost_diff -= validator; - } else if (comp.in > g.in) { - validator = (g.old_out + ghost_diff) - comp.in; - if (validator > 0) ghost_diff -= validator; - } - } - } - - // apply changes - if (g.transition != nullptr && g.transition->secondary_clip != nullptr) { - if (g.trim_type == olive::timeline::TRIM_IN) ghost_diff = -ghost_diff; - g.in = g.old_in - ghost_diff; - g.out = g.old_out + ghost_diff; - } else if (g.trim_type == olive::timeline::TRIM_IN) { - g.in = g.old_in + ghost_diff; - g.clip_in = g.old_clip_in + ghost_diff; - } else { - g.out = g.old_out + ghost_diff; - } - } else if (clips_are_movable) { - g.in = g.old_in + frame_diff; - g.out = g.old_out + frame_diff; - - if (g.transition != nullptr - && g.transition == g.clip->opening_transition) { - g.clip_in = g.old_clip_in + frame_diff; - } - - if (ParentTimeline()->importing) { - - g.track_movement = getTrackIndexFromScreenPoint(mouse_pos.y()); - - } else if (g.track->type() == type_ && g.transition == nullptr) { - - g.track_movement = track_diff; - - } - } else if (effective_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { - if (ParentTimeline()->transition_tool_open_clip != nullptr - && ParentTimeline()->transition_tool_close_clip != nullptr) { - g.in = g.old_in - frame_diff; - g.out = g.old_out + frame_diff; - } else if (ParentTimeline()->transition_tool_open_clip == g.clip) { - g.out = g.old_out + frame_diff; - } else { - g.in = g.old_in + frame_diff; - } - } - - earliest_in_point = qMin(earliest_in_point, g.in); - } - - // apply changes to selections - /* - if (effective_tool != olive::timeline::TIMELINE_TOOL_SLIP && !ParentTimeline()->importing && !ParentTimeline()->creating) { - for (int i=0;iselections.size();i++) { - Selection& s = sequence()->selections[i]; - if (ParentTimeline()->trim_target > -1) { - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { - s.in = s.old_in + frame_diff; - } else { - s.out = s.old_out + frame_diff; - } - } else if (clips_are_movable) { - for (int i=0;iselections.size();i++) { - Selection& s = sequence()->selections[i]; - s.in = s.old_in + frame_diff; - s.out = s.old_out + frame_diff; - s.track = s.old_track; - - if (ParentTimeline()->importing) { - int abs_track_diff = abs(track_diff); - if (s.old_track < 0) { - s.track -= abs_track_diff; - } else { - s.track += abs_track_diff; - } - } else { - if (same_sign(s.track, ParentTimeline()->drag_track_start)) s.track += track_diff; - } - } - } - } - } - */ - - if (ParentTimeline()->importing) { - QToolTip::showText(mapToGlobal(mouse_pos), frame_to_timecode(earliest_in_point, olive::config.timecode_view, sequence()->frame_rate())); - } else { - QString tip = ((frame_diff < 0) ? "-" : "+") + frame_to_timecode(qAbs(frame_diff), olive::config.timecode_view, sequence()->frame_rate()); - - if (ParentTimeline()->trim_target != nullptr) { - // find which clip is being moved - const Ghost* g = nullptr; - for (int i=0;ighosts.size();i++) { - if (ParentTimeline()->ghosts.at(i).clip == ParentTimeline()->trim_target) { - g = &ParentTimeline()->ghosts.at(i); - break; - } - } - - if (g != nullptr) { - tip += " " + tr("Duration:") + " "; - long len = (g->old_out-g->old_in); - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { - len -= frame_diff; - } else { - len += frame_diff; - } - tip += frame_to_timecode(len, olive::config.timecode_view, sequence()->frame_rate()); - } - } - - QToolTip::showText(mapToGlobal(mouse_pos), tip); - } -} - -void TimelineView::mouseMoveEvent(QMouseEvent *event) { - - // interrupt any potential tooltip about to show - tooltip_timer.stop(); - - if (sequence() != nullptr) { - bool alt = (event->modifiers() & Qt::AltModifier); - - // store current frame/track corresponding to the cursor - ParentTimeline()->cursor_frame = ParentTimeline()->getTimelineFrameFromScreenPoint(event->pos().x()); - ParentTimeline()->cursor_track = getTrackFromScreenPoint(event->pos().y()); - - // if holding the mouse button down, let's scroll to that location - if (event->buttons() != 0 && olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_HAND) { - ParentTimeline()->scroll_to_frame(ParentTimeline()->cursor_frame); - } - - // determine if the action should be "inserting" rather than "overwriting" - // Default behavior is to replace/overwrite clips under any clips we're dropping over them. Inserting will - // split and move existing clips at the drop point to make space for the drop - ParentTimeline()->move_insert = ((event->modifiers() & Qt::ControlModifier) - && (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER - || ParentTimeline()->importing - || ParentTimeline()->creating)); - - // if we're not currently resizing already, default track resizing to false (we'll set it to true later if - // the user is still hovering over a track line) - if (!ParentTimeline()->moving_init) { - track_resizing = false; - } - - // if the current tool uses an on-screen visible cursor, we snap the cursor to the timeline - if (current_tool_shows_cursor()) { - sequence()->SnapPoint(&ParentTimeline()->cursor_frame, - ParentTimeline()->zoom, - - // only snap to the playhead if the edit tool doesn't force the playhead to - // follow it (or if we're not selecting since that means the playhead is - // static at the moment) - !olive::config.edit_tool_also_seeks || !ParentTimeline()->selecting, - - true, - true); - } - - if (ParentTimeline()->selecting) { - - QVector selections = ParentTimeline()->selection_cache; - - if (ParentTimeline()->drag_track_start != nullptr || ParentTimeline()->cursor_track != nullptr) { - - long selection_in = qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - long selection_out = qMax(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - - int selection_top = mapToGlobal(QPoint(0, ParentTimeline()->drag_y_start)).y(); - int selection_bottom = mapToGlobal(event->pos()).y(); - - QVector selected_tracks = ParentTimeline()->GetTracksInRectangle(selection_top, - selection_bottom); - - Track* track; - - foreach (track, selected_tracks) { - - selections.append(Selection(selection_in, selection_out, track)); - - // If the config is set to select links as well with the edit tool - if (olive::config.edit_tool_selects_links) { - - for (int j=0;jClipCount();j++) { - - Clip* c = track->GetClip(j).get(); - - // See if this selection contains this clip - if (!(c->timeline_in() > selection_out || c->timeline_out() < selection_in)) { - - // If so, select its links as well - for (int k=0;klinked.size();k++) { - Clip* link = c->linked.at(k); - - // Make sure there isn't already a selection for this link - bool found = false; - for (int l=0;ltrack()) { - found = true; - break; - } - } - // If not, make one now - if (!found) { - selections.append(Selection(selection_in, selection_out, link->track())); - } - } - } - } - } - } - } - - sequence()->SetSelections(selections); - - /* - // get number of selections based on tracks in selection area - int selection_tool_count = 1 - + qMax(ParentTimeline()->cursor_track->Index(), ParentTimeline()->drag_track_start->Index()) - - qMin(ParentTimeline()->cursor_track->Index(), ParentTimeline()->drag_track_start->Index()); - - // add count to selection offset for the total number of selection objects - // (offset is usually 0, unless the user is holding shift in which case we add to existing selections) - int selection_count = selection_tool_count + ParentTimeline()->selection_offset; - - // resize selection object array to new count - if (sequence()->selections.size() != selection_count) { - sequence()->selections.resize(selection_count); - } - - // loop through tracks in selection area and adjust them accordingly - int minimum_selection_track = qMin(ParentTimeline()->cursor_track, ParentTimeline()->drag_track_start); - int maximum_selection_track = qMax(ParentTimeline()->cursor_track, ParentTimeline()->drag_track_start); - long selection_in = qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - long selection_out = qMax(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - for (int i=ParentTimeline()->selection_offset;iselections[i]; - s.track = minimum_selection_track + i - ParentTimeline()->selection_offset; - s.in = selection_in; - s.out = selection_out; - } - - // If the config is set to select links as well with the edit tool - if (olive::config.edit_tool_selects_links) { - - // find which clips are selected - for (int j=0;jclips.size();j++) { - - Clip* c = sequence()->clips.at(j).get(); - - if (c != nullptr && c->IsSelected(false)) { - - // loop through linked clips - for (int k=0;klinked.size();k++) { - - ClipPtr link = sequence()->clips.at(c->linked.at(k)); - - // see if one of the selections is already covering this track - if (!(link->track() >= minimum_selection_track - && link->track() <= maximum_selection_track)) { - - // clip is not in selectin area, time to select it - Selection link_sel; - link_sel.in = selection_in; - link_sel.out = selection_out; - link_sel.track = link->track(); - sequence()->selections.append(link_sel); - - } - - } - - } - } - } - */ - - // if the config is set to seek with the edit too, do so now - if (olive::config.edit_tool_also_seeks) { - panel_sequence_viewer->seek(qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame)); - } else { - // if not, repaint (seeking will trigger a repaint) - ParentTimeline()->repaint_timeline(); - } - - } else if (ParentTimeline()->hand_moving) { - - // if we're hand moving, we'll be adding values directly to the scrollbars - - // the scrollbars trigger repaints when they scroll, which is unnecessary here so we block them - ParentTimeline()->block_repaints = true; - ParentTimeline()->horizontalScrollBar->setValue(ParentTimeline()->horizontalScrollBar->value() + ParentTimeline()->drag_x_start - event->pos().x()); - emit requestScrollChange(scroll + ParentTimeline()->drag_y_start - event->pos().y()); - ParentTimeline()->block_repaints = false; - - // finally repaint - ParentTimeline()->repaint_timeline(); - - // store current cursor position for next hand move event - ParentTimeline()->drag_x_start = event->pos().x(); - ParentTimeline()->drag_y_start = event->pos().y(); - - } else if (ParentTimeline()->moving_init) { - - if (track_resizing) { - - // get cursor movement - int diff = (event->pos().y() - ParentTimeline()->drag_y_start); - - if (alignment_ == olive::timeline::kAlignmentBottom) { - diff = -diff; - } - - // add it to the current track height - int new_height = track_target->height() + diff; - - // limit track height to track minimum height constant - new_height = qMax(new_height, olive::timeline::kTrackMinHeight); - - // set the track height - track_target->set_height(new_height); - - // store current cursor position for next track resize event - ParentTimeline()->drag_y_start = event->pos().y(); - - update(); - - } else if (ParentTimeline()->moving_proc) { - - // we're currently dragging ghosts - update_ghosts(event->pos(), event->modifiers() & Qt::ShiftModifier); - - } else { - - // Prepare to start moving clips in some capacity. We create Ghost objects to store movement data before we - // actually apply it to the clips (in mouseReleaseEvent) - - // loop through clips for any currently selected - QVector partially_selected_clips = sequence()->SelectedClips(false); - for (int i=0;iIsSelected(); - - if (!add) { - // check if a transition is selected - // (only the pointer tool supports moving transitions) - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER - && (c->opening_transition != nullptr || c->closing_transition != nullptr)) { - - // check if any selections contain a whole transition - if (c->IsTransitionSelected(kTransitionOpening)) { - g.transition = c->opening_transition; - add = true; - } else if (c->IsTransitionSelected(kTransitionClosing)) { - g.transition = c->closing_transition; - add = true; - } - - } - } - - if (add && g.transition != nullptr) { - - // transition may be a shared transition, check if it's already been added elsewhere - for (int j=0;jghosts.size();j++) { - if (ParentTimeline()->ghosts.at(j).transition == g.transition) { - add = false; - break; - } - } - } - - if (add) { - g.clip = c; - g.trim_type = ParentTimeline()->trim_type; - ParentTimeline()->ghosts.append(g); - } - } - } - - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIDE) { - - // for the slide tool, we add the surrounding clips as ghosts that are getting trimmed the opposite way - - // store original array size since we'll be adding to it - int ghost_arr_size = ParentTimeline()->ghosts.size(); - - // loop through clips for any that are "touching" the selected clips - for (int i=0;ighosts.at(i).clip; - - Clip* pre_clip = ghost_clip->track()->GetClipFromPoint(ghost_clip->timeline_in() - 1); - Clip* post_clip = ghost_clip->track()->GetClipFromPoint(ghost_clip->timeline_out() + 1); - - // Check if this clip is already in the ghosts, in which case don't add it - for (int j=0;jghosts.at(j).clip == pre_clip) { - pre_clip = nullptr; - } else if (ParentTimeline()->ghosts.at(j).clip == post_clip) { - post_clip = nullptr; - } - } - - Ghost gh; - gh.transition = nullptr; - - if (pre_clip != nullptr) { - gh.clip = pre_clip; - gh.trim_type = olive::timeline::TRIM_OUT; - ParentTimeline()->ghosts.append(gh); - } - - if (post_clip != nullptr) { - gh.clip = post_clip; - gh.trim_type = olive::timeline::TRIM_IN; - ParentTimeline()->ghosts.append(gh); - } - } - } - - // set up ghost defaults - init_ghosts(); - - // if the ripple tool is selected, prepare to ripple - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE) { - - long axis = LONG_MAX; - - // find the earliest point within the selected clips which is the point we'll ripple around - // also store the currently selected clips so we don't have to do it later - QVector ghost_clips; - ghost_clips.resize(ParentTimeline()->ghosts.size()); - - for (int i=0;ighosts.size();i++) { - Clip* c = ParentTimeline()->ghosts.at(i).clip; - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { - axis = qMin(axis, c->timeline_in()); - } else { - axis = qMin(axis, c->timeline_out()); - } - - // store clip reference - ghost_clips[i] = c; - } - - // loop through clips and cache which are earlier than the axis and which after after - QVector sequence_clips = sequence()->GetAllClips(); - for (int i=0;itimeline_in() >= axis); - - // construct the list of pre and post clips - QVector& clip_list = (clip_is_post) ? post_clips : pre_clips; - - // check if there's already a clip in this list on this track, and if this clip is closer or not - bool found = false; - for (int j=0;jtrack() == c->track()) { - - // if the clip is closer, use this one instead of the current one in the list - if ((!clip_is_post && compare->timeline_out() < c->timeline_out()) - || (clip_is_post && compare->timeline_in() > c->timeline_in())) { - clip_list[j] = c; - } - - found = true; - break; - } - - } - - // if there is no clip on this track in the list, add it - if (!found) { - clip_list.append(c); - } - } - } - } - - // store selections - /* - selection_command = new SetSelectionsCommand(sequence().get()); - selection_command->old_data = sequence()->selections; - */ - - // ready to start moving clips - ParentTimeline()->moving_proc = true; - } - - update_ui(false); - - } else if (ParentTimeline()->splitting) { - - ParentTimeline()->split_tracks = GetSplitTracksFromMouseCoords(!alt, - ParentTimeline()->drag_frame_start, - ParentTimeline()->drag_y_start, - event->pos().y()); - update_ui(false); - - } else if (ParentTimeline()->rect_select_init) { - - // set if the user started dragging at point where there was no clip - - if (ParentTimeline()->rect_select_proc) { - - // we're currently rectangle selecting - - QVector selections = ParentTimeline()->selection_cache; - - // set the right/bottom coords to the current mouse position - // (left/top were set to the starting drag position earlier) - ParentTimeline()->rect_select_rect.setBottomRight(mapToGlobal(event->pos())); - - QVector selected_clips; - - QVector selected_tracks = ParentTimeline()->GetTracksInRectangle(ParentTimeline()->rect_select_rect.top(), - ParentTimeline()->rect_select_rect.bottom()); - - long frame_min = qMin(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - long frame_max = qMax(ParentTimeline()->drag_frame_start, ParentTimeline()->cursor_frame); - - Track* track; - - foreach (track, selected_tracks) { - // Loop through track's clips for clips touching this rectangle - - for (int i=0;iClipCount();i++) { - - Clip* clip = track->GetClip(i).get(); - - if (!(clip->timeline_out() < frame_min || clip->timeline_in() > frame_max) ) { - - // create a group of the clip (and its links if alt is not pressed) - QVector session_clips; - session_clips.append(clip); - - if (!alt) { - session_clips.append(clip->linked); - } - - // for each of these clips, see if clip has already been added - - // this can easily happen due to adding linked clips - for (int j=0;jToSelection()); - } - - sequence()->SetSelections(selections); - - ParentTimeline()->repaint_timeline(); - } else { - - // set up rectangle selecting - ParentTimeline()->rect_select_rect.setTopLeft(mapToGlobal(event->pos())); - ParentTimeline()->rect_select_rect.setSize(QSize(0, 0)); - - ParentTimeline()->rect_select_proc = true; - - } - } else if (current_tool_shows_cursor()) { - - // we're not currently performing an action (click is not pressed), but redraw because we have an on-screen cursor - ParentTimeline()->repaint_timeline(); - - } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER || - olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE || - olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_ROLLING) { - - // hide any tooltip that may be currently showing - QToolTip::hideText(); - - // cache cursor position - QPoint pos = event->pos(); - - // - // check to see if the cursor is on a clip edge - // - - // threshold around a trim point that the cursor can be within and still considered "trimming" - int lim = 10; // FIXME Magic number for the clip trimming threshold - int mouse_frame_lower = pos.x() - lim; - int mouse_frame_upper = pos.x() + lim; - - // used to determine whether we the cursor found a trim point or not - bool found = false; - - // used to determine how close the cursor is to a trim point - // (and more specifically, whether another point is closer or not) - long closeness = LONG_MAX; - - // we default to selecting no transition, but set this accordingly if the cursor is on a transition - ParentTimeline()->transition_select = kTransitionNone; - - // we also default to no trimming which may be changed later in this function - ParentTimeline()->trim_type = olive::timeline::TRIM_NONE; - - // set currently trimming clip to -1 (aka null) - ParentTimeline()->trim_target = nullptr; - - // loop through current clips in the sequence - QVector sequence_clips = sequence()->GetAllClips(); - for (int i=0;itrack() == ParentTimeline()->cursor_track) { - - // if this cursor is inside the boundaries of this clip (hovering over the clip) - if (ParentTimeline()->cursor_frame >= c->timeline_in() && - ParentTimeline()->cursor_frame <= c->timeline_out()) { - - // start a timer to show a tooltip about this clip - tooltip_timer.start(); - tooltip_clip = c; - - // check if the cursor is specifically hovering over one of the clip's transitions - if (c->opening_transition != nullptr - && ParentTimeline()->cursor_frame <= c->timeline_in() + c->opening_transition->get_true_length()) { - - ParentTimeline()->transition_select = kTransitionOpening; - - } else if (c->closing_transition != nullptr - && ParentTimeline()->cursor_frame >= c->timeline_out() - c->closing_transition->get_true_length()) { - - ParentTimeline()->transition_select = kTransitionClosing; - - } - } - - int visual_in_point = ParentTimeline()->getTimelineScreenPointFromFrame(c->timeline_in()); - int visual_out_point = ParentTimeline()->getTimelineScreenPointFromFrame(c->timeline_out()); - - // is the cursor hovering around the clip's IN point? - if (visual_in_point > mouse_frame_lower && visual_in_point < mouse_frame_upper) { - - // test how close this IN point is to the cursor - int nc = qAbs(visual_in_point + 1 - pos.x()); - - // and test whether it's closer than the last in/out point we found - if (nc < closeness) { - - // if so, this is the point we'll make active for now (unless we find a closer one later) - ParentTimeline()->trim_target = c; - ParentTimeline()->trim_type = olive::timeline::TRIM_IN; - closeness = nc; - found = true; - - } - } - - // is the cursor hovering around the clip's OUT point? - if (visual_out_point > mouse_frame_lower && visual_out_point < mouse_frame_upper) { - - // test how close this OUT point is to the cursor - int nc = qAbs(visual_out_point - 1 - pos.x()); - - // and test whether it's closer than the last in/out point we found - if (nc < closeness) { - - // if so, this is the point we'll make active for now (unless we find a closer one later) - ParentTimeline()->trim_target = c; - ParentTimeline()->trim_type = olive::timeline::TRIM_OUT; - closeness = nc; - found = true; - - } - } - - // the pointer can be used to resize/trim transitions, here we test if the - // cursor is within the trim point of one of the clip's transitions - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_POINTER) { - - // if the clip has an opening transition - if (c->opening_transition != nullptr) { - - // cache the timeline frame where the transition ends - int transition_point = ParentTimeline()->getTimelineScreenPointFromFrame(c->timeline_in() - + c->opening_transition->get_true_length()); - - // check if the cursor is hovering around it (within the threshold) - if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { - - // similar to above, test how close it is and if it's closer, make this active - int nc = qAbs(transition_point - 1 - pos.x()); - if (nc < closeness) { - ParentTimeline()->trim_target = c; - ParentTimeline()->trim_type = olive::timeline::TRIM_OUT; - ParentTimeline()->transition_select = kTransitionOpening; - closeness = nc; - found = true; - } - } - } - - // if the clip has a closing transition - if (c->closing_transition != nullptr) { - - // cache the timeline frame where the transition starts - int transition_point = ParentTimeline()->getTimelineScreenPointFromFrame(c->timeline_out() - - c->closing_transition->get_true_length()); - - // check if the cursor is hovering around it (within the threshold) - if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { - - // similar to above, test how close it is and if it's closer, make this active - int nc = qAbs(transition_point + 1 - pos.x()); - if (nc < closeness) { - ParentTimeline()->trim_target = c; - ParentTimeline()->trim_type = olive::timeline::TRIM_IN; - ParentTimeline()->transition_select = kTransitionClosing; - closeness = nc; - found = true; - } - } - } - } - } - } - - // if the cursor is indeed on a clip edge, we set the cursor accordingly - if (found) { - - if (ParentTimeline()->trim_type == olive::timeline::TRIM_IN) { // if we're trimming an IN point - setCursor(olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE ? olive::cursor::LeftRipple : olive::cursor::LeftTrim); - } else { // if we're trimming an OUT point - setCursor(olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_RIPPLE ? olive::cursor::RightRipple : olive::cursor::RightTrim); - } - - } else { - QVector track_list = sequence_->GetTrackList(type_); - - // we didn't find a trim target, so we must be doing something else - // (e.g. dragging a clip or resizing the track heights) - - unsetCursor(); - - // check to see if we're resizing a track height - int mouse_pos = event->pos().y(); - - // cursor range for resizing a track - int test_range = 10; // FIXME magic number - - for (int i=0;i resize_point - test_range - && mouse_pos < resize_point + test_range) { - track_resizing = true; - track_target = track; - setCursor(Qt::SizeVerCursor); - break; - } - } - - } - } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_SLIP) { - - // we're not currently performing any slipping, all we do here is set the cursor if mouse is hovering over a - // cursor - if (GetClipAtCursor() != nullptr) { - setCursor(olive::cursor::Slip); - } else { - unsetCursor(); - } - - } else if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { - - if (ParentTimeline()->transition_tool_init) { - - // the transition tool has started - - if (ParentTimeline()->transition_tool_proc) { - - // ghosts have been set up, so just run update - update_ghosts(event->pos(), event->modifiers() & Qt::ShiftModifier); - - } else { - - // transition tool is being used but ghosts haven't been set up yet, set them up now - TransitionType primary_type = kTransitionOpening; - Clip* primary = ParentTimeline()->transition_tool_open_clip; - if (primary == nullptr) { - primary_type = kTransitionClosing; - primary = ParentTimeline()->transition_tool_close_clip; - } - - Ghost g; - - g.in = g.old_in = g.out = g.old_out = (primary_type == kTransitionOpening) ? - primary->timeline_in() - : primary->timeline_out(); - - g.track = primary->track(); - g.clip = primary; - g.media_stream = primary_type; - g.trim_type = olive::timeline::TRIM_NONE; - - ParentTimeline()->ghosts.append(g); - - ParentTimeline()->transition_tool_proc = true; - - } - - } else { - - // transition tool has been selected but is not yet active, so we show screen feedback to the user on - // possible transitions - - Clip* mouse_clip = GetClipAtCursor(); - - // set default transition tool references to no clip - ParentTimeline()->transition_tool_open_clip = nullptr; - ParentTimeline()->transition_tool_close_clip = nullptr; - - if (mouse_clip != nullptr) { - - // cursor is hovering over a clip - - // check if the clip and transition are both the same sign (meaning video/audio are the same) - if (type_ == olive::node_library[ParentTimeline()->transition_tool_meta]->subtype()) { - - // the range within which the transition tool will assume the user wants to make a shared transition - // between two clips rather than just one transition on one clip - long between_range = getFrameFromScreenPoint(ParentTimeline()->zoom, TRANSITION_BETWEEN_RANGE) + 1; - - // set whether the transition is opening or closing based on whether the cursor is on the left half - // or right half of the clip - if (ParentTimeline()->cursor_frame > (mouse_clip->timeline_in() + (mouse_clip->length()/2))) { - ParentTimeline()->transition_tool_close_clip = mouse_clip; - - // if the cursor is within this range, set the post_clip to be the next clip touching - // - // getClipIndexFromCoords() will automatically set to -1 if there's no clip there which means the - // end result will be the same as not setting a clip here at all - if (ParentTimeline()->cursor_frame > mouse_clip->timeline_out() - between_range) { - ParentTimeline()->transition_tool_open_clip = mouse_clip->track()->GetClipFromPoint(mouse_clip->timeline_out()+1); - } - } else { - ParentTimeline()->transition_tool_open_clip = mouse_clip; - - if (ParentTimeline()->cursor_frame < mouse_clip->timeline_in() + between_range) { - ParentTimeline()->transition_tool_close_clip = mouse_clip->track()->GetClipFromPoint(mouse_clip->timeline_in()-1); - } - } - - } - } - } - - ParentTimeline()->repaint_timeline(); - } - } -} - -void TimelineView::leaveEvent(QEvent*) { - tooltip_timer.stop(); -} - -void TimelineView::draw_transition(QPainter& p, Clip* c, const QRect& clip_rect, QRect& text_rect, int transition_type) { - TransitionPtr t = (transition_type == kTransitionOpening) ? c->opening_transition : c->closing_transition; - if (t != nullptr) { - QColor transition_color(255, 0, 0, 16); - int transition_width = getScreenPointFromFrame(ParentTimeline()->zoom, t->get_true_length()); - int transition_height = clip_rect.height(); - int tr_y = clip_rect.y(); - int tr_x = 0; - if (transition_type == kTransitionOpening) { - tr_x = clip_rect.x(); - text_rect.setX(text_rect.x()+transition_width); - } else { - tr_x = clip_rect.right()-transition_width; - text_rect.setWidth(text_rect.width()-transition_width); - } - QRect transition_rect = QRect(tr_x, tr_y, transition_width, transition_height); - p.fillRect(transition_rect, transition_color); - QRect transition_text_rect(transition_rect.x() + olive::timeline::kClipTextPadding, transition_rect.y() + olive::timeline::kClipTextPadding, transition_rect.width() - olive::timeline::kClipTextPadding, transition_rect.height() - olive::timeline::kClipTextPadding); - if (transition_text_rect.width() > MAX_TEXT_WIDTH) { - bool draw_text = true; - - p.setPen(QColor(0, 0, 0, 96)); - if (t->secondary_clip == nullptr) { - if (transition_type == kTransitionOpening) { - p.drawLine(transition_rect.bottomLeft(), transition_rect.topRight()); - } else { - p.drawLine(transition_rect.topLeft(), transition_rect.bottomRight()); - } - } else { - if (transition_type == kTransitionOpening) { - p.drawLine(QPoint(transition_rect.left(), transition_rect.center().y()), transition_rect.topRight()); - p.drawLine(QPoint(transition_rect.left(), transition_rect.center().y()), transition_rect.bottomRight()); - draw_text = false; - } else { - p.drawLine(QPoint(transition_rect.right(), transition_rect.center().y()), transition_rect.topLeft()); - p.drawLine(QPoint(transition_rect.right(), transition_rect.center().y()), transition_rect.bottomLeft()); - } - } - - if (draw_text) { - p.setPen(Qt::white); - p.drawText(transition_text_rect, 0, t->name(), &transition_text_rect); - } - } - p.setPen(Qt::black); - p.drawRect(transition_rect); - } - -} - -void TimelineView::paintEvent(QPaintEvent*) { - // Draw clips - if (sequence_ != nullptr) { - QPainter p(this); - - // get widget width and height - emit setScrollMaximum(GetTotalAreaHeight()); - - QVector track_list = sequence_->GetTrackList(type_); - for (int i=0;iheight(); - - if (track_bottom > 0 && track_top < height()) { - for (int j=0;jClipCount();j++) { - - Clip* clip = track->GetClip(j).get(); - - QRect clip_rect(ParentTimeline()->getTimelineScreenPointFromFrame(clip->timeline_in()), - track_top, - getScreenPointFromFrame(ParentTimeline()->zoom, clip->length()), - track->height()); - - if (alignment_ == olive::timeline::kAlignmentTop) { - clip_rect.setHeight(track->height() - 1); - } else if (alignment_ == olive::timeline::kAlignmentBottom) { - clip_rect.setTop(track_top + 1); - } - - QRect text_rect(clip_rect.left() + olive::timeline::kClipTextPadding, - clip_rect.top() + olive::timeline::kClipTextPadding, - clip_rect.width() - olive::timeline::kClipTextPadding - 1, - clip_rect.height() - olive::timeline::kClipTextPadding - 1); - if (clip_rect.left() < width() && clip_rect.right() >= 0 && clip_rect.top() < height() && clip_rect.bottom() >= 0) { - QRect actual_clip_rect = clip_rect; - if (actual_clip_rect.x() < 0) actual_clip_rect.setX(0); - if (actual_clip_rect.right() > width()) actual_clip_rect.setRight(width()); - if (actual_clip_rect.y() < 0) actual_clip_rect.setY(0); - if (actual_clip_rect.bottom() > height()) actual_clip_rect.setBottom(height()); - p.fillRect(actual_clip_rect, (clip->enabled()) ? clip->color() : QColor(96, 96, 96)); - - int thumb_x = clip_rect.x() + 1; - - if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - bool draw_checkerboard = false; - QRect checkerboard_rect(clip_rect); - FootageStream* ms = clip->media_stream(); - if (ms == nullptr) { - draw_checkerboard = true; - } else if (ms->preview_done) { - // draw top and tail triangles - int triangle_size = olive::timeline::kTrackMinHeight >> 2; - if (!ms->infinite_length && clip_rect.width() > triangle_size) { - p.setPen(Qt::NoPen); - p.setBrush(QColor(80, 80, 80)); - if (clip->clip_in() == 0 - && clip_rect.x() + triangle_size > 0 - && clip_rect.y() + triangle_size > 0 - && clip_rect.x() < width() - && clip_rect.y() < height()) { - const QPoint points[3] = { - QPoint(clip_rect.x(), clip_rect.y()), - QPoint(clip_rect.x() + triangle_size, clip_rect.y()), - QPoint(clip_rect.x(), clip_rect.y() + triangle_size) - }; - p.drawPolygon(points, 3); - text_rect.setLeft(text_rect.left() + (triangle_size >> 2)); - } - if (clip->timeline_out() - clip->timeline_in() + clip->clip_in() == clip->media_length() - && clip_rect.right() - triangle_size < width() - && clip_rect.y() + triangle_size > 0 - && clip_rect.right() > 0 - && clip_rect.y() < height()) { - const QPoint points[3] = { - QPoint(clip_rect.right(), clip_rect.y()), - QPoint(clip_rect.right() - triangle_size, clip_rect.y()), - QPoint(clip_rect.right(), clip_rect.y() + triangle_size) - }; - p.drawPolygon(points, 3); - text_rect.setRight(text_rect.right() - (triangle_size >> 2)); - } - } - - p.setBrush(Qt::NoBrush); - - // draw thumbnail/waveform - long media_length = clip->media_length(); - - if (clip->type() == olive::kTypeVideo) { - // draw thumbnail - int thumb_y = p.fontMetrics().height()+olive::timeline::kClipTextPadding+olive::timeline::kClipTextPadding; - if (thumb_x < width() && thumb_y < height()) { - int space_for_thumb = clip_rect.width()-1; - if (clip->opening_transition != nullptr) { - int ot_width = getScreenPointFromFrame(ParentTimeline()->zoom, clip->opening_transition->get_true_length()); - thumb_x += ot_width; - space_for_thumb -= ot_width; - } - if (clip->closing_transition != nullptr) { - space_for_thumb -= getScreenPointFromFrame(ParentTimeline()->zoom, clip->closing_transition->get_true_length()); - } - int thumb_height = clip_rect.height()-thumb_y; - int thumb_width = qRound(thumb_height*(double(ms->video_preview.width())/double(ms->video_preview.height()))); - if (thumb_x + thumb_width >= 0 - && thumb_height > thumb_y - && thumb_y + thumb_height >= 0 - && space_for_thumb > MAX_TEXT_WIDTH) { - int thumb_clip_width = qMin(thumb_width, space_for_thumb); - p.drawImage(QRect(thumb_x, - clip_rect.y()+thumb_y, - thumb_clip_width, - thumb_height), - ms->video_preview, - QRect(0, - 0, - qRound(thumb_clip_width*(double(ms->video_preview.width())/double(thumb_width))), - ms->video_preview.height() - ) - ); - } - } - if (clip->timeline_out() - clip->timeline_in() + clip->clip_in() > clip->media_length()) { - draw_checkerboard = true; - checkerboard_rect.setLeft(ParentTimeline()->getTimelineScreenPointFromFrame(clip->media_length() + clip->timeline_in() - clip->clip_in())); - } - } else if (clip_rect.height() > olive::timeline::kTrackMinHeight) { - // draw waveform - p.setPen(QColor(80, 80, 80)); - - int waveform_start = -qMin(clip_rect.x(), 0); - int waveform_limit = qMin(clip_rect.width(), getScreenPointFromFrame(ParentTimeline()->zoom, media_length - clip->clip_in())); - - if ((clip_rect.x() + waveform_limit) > width()) { - waveform_limit -= (clip_rect.x() + waveform_limit - width()); - } else if (waveform_limit < clip_rect.width()) { - draw_checkerboard = true; - if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); - } - - olive::ui::DrawWaveform(clip, ms, media_length, &p, clip_rect, waveform_start, waveform_limit, ParentTimeline()->zoom); - } - } - if (draw_checkerboard) { - checkerboard_rect.setLeft(qMax(checkerboard_rect.left(), 0)); - checkerboard_rect.setRight(qMin(checkerboard_rect.right(), width())); - checkerboard_rect.setTop(qMax(checkerboard_rect.top(), 0)); - checkerboard_rect.setBottom(qMin(checkerboard_rect.bottom(), height())); - - if (checkerboard_rect.left() < width() - && checkerboard_rect.right() >= 0 - && checkerboard_rect.top() < height() - && checkerboard_rect.bottom() >= 0) { - // draw "error lines" if media stream is missing - p.setPen(QPen(QColor(64, 64, 64), 2)); - int limit = checkerboard_rect.width(); - int clip_height = checkerboard_rect.height(); - for (int j=-clip_height;j checkerboard_rect.right()) { - lines_end_y -= (checkerboard_rect.right() - lines_end_x); - lines_end_x = checkerboard_rect.right(); - } - p.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y); - } - } - } - } - - // draw clip markers - for (int j=0;jget_markers().size();j++) { - const Marker& m = clip->get_markers().at(j); - - // convert marker time (in clip time) to sequence time - long marker_time = m.frame + clip->timeline_in() - clip->clip_in(); - int marker_x = ParentTimeline()->getTimelineScreenPointFromFrame(marker_time); - if (marker_x > clip_rect.x() && marker_x < clip_rect.right()) { - Marker::Draw(p, marker_x, clip_rect.bottom()-p.fontMetrics().height(), clip_rect.bottom(), false); - } - } - p.setBrush(Qt::NoBrush); - - // draw clip transitions - draw_transition(p, clip, clip_rect, text_rect, kTransitionOpening); - draw_transition(p, clip, clip_rect, text_rect, kTransitionClosing); - - // top left bevel - p.setPen(Qt::white); - if (clip_rect.x() >= 0 && clip_rect.x() < width()) p.drawLine(clip_rect.bottomLeft(), clip_rect.topLeft()); - if (clip_rect.y() >= 0 && clip_rect.y() < height()) p.drawLine(QPoint(qMax(0, clip_rect.left()), clip_rect.top()), QPoint(qMin(width(), clip_rect.right()), clip_rect.top())); - - // draw text - if (text_rect.width() > MAX_TEXT_WIDTH && text_rect.right() > 0 && text_rect.left() < width()) { - if (!clip->enabled()) { - p.setPen(Qt::gray); - } else if (clip->color().lightness() > 160) { - // set to black if color is bright - p.setPen(Qt::black); - } - if (clip->linked.size() > 0) { - int underline_y = olive::timeline::kClipTextPadding + p.fontMetrics().height() + clip_rect.top(); - int underline_width = qMin(text_rect.width() - 1, p.fontMetrics().width(clip->name())); - p.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); - } - QString name = clip->name(); - if (clip->speed().value != 1.0 || clip->reversed()) { - name += " ("; - if (clip->reversed()) name += "-"; - name += QString::number(clip->speed().value*100) + "%)"; - } - p.drawText(text_rect, 0, name, &text_rect); - } - - // bottom right gray - p.setPen(QColor(0, 0, 0, 128)); - if (clip_rect.right() >= 0 && clip_rect.right() < width()) p.drawLine(clip_rect.bottomRight(), clip_rect.topRight()); - if (clip_rect.bottom() >= 0 && clip_rect.bottom() < height()) p.drawLine(QPoint(qMax(0, clip_rect.left()), clip_rect.bottom()), QPoint(qMin(width(), clip_rect.right()), clip_rect.bottom())); - - // draw transition tool - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_TRANSITION) { - - bool shared_transition = (ParentTimeline()->transition_tool_open_clip != nullptr - && ParentTimeline()->transition_tool_close_clip != nullptr); - - QRect transition_tool_rect = clip_rect; - bool draw_transition_tool_rect = false; - - if (ParentTimeline()->transition_tool_open_clip == clip) { - if (shared_transition) { - transition_tool_rect.setWidth(TRANSITION_BETWEEN_RANGE); - } else { - transition_tool_rect.setWidth(transition_tool_rect.width()>>2); - } - draw_transition_tool_rect = true; - } else if (ParentTimeline()->transition_tool_close_clip == clip) { - if (shared_transition) { - transition_tool_rect.setLeft(transition_tool_rect.right() - TRANSITION_BETWEEN_RANGE); - } else { - transition_tool_rect.setLeft(transition_tool_rect.left() + (3*(transition_tool_rect.width()>>2))); - } - draw_transition_tool_rect = true; - } - - if (draw_transition_tool_rect - && transition_tool_rect.left() < width() - && transition_tool_rect.right() > 0) { - if (transition_tool_rect.left() < 0) { - transition_tool_rect.setLeft(0); - } - if (transition_tool_rect.right() > width()) { - transition_tool_rect.setRight(width()); - } - p.fillRect(transition_tool_rect, QColor(0, 0, 0, 128)); - } - } - } - } - - // Draw recording clip if recording if valid - if (panel_sequence_viewer->is_recording_cued() && panel_sequence_viewer->recording_track == track) { - int rec_track_x = ParentTimeline()->getTimelineScreenPointFromFrame(panel_sequence_viewer->recording_start); - int rec_track_y = getScreenPointFromTrack(panel_sequence_viewer->recording_track); - int rec_track_height = track->height(); - if (panel_sequence_viewer->recording_start != panel_sequence_viewer->recording_end) { - QRect rec_rect( - rec_track_x, - rec_track_y, - getScreenPointFromFrame(ParentTimeline()->zoom, panel_sequence_viewer->recording_end - panel_sequence_viewer->recording_start), - rec_track_height - ); - p.setPen(QPen(QColor(96, 96, 96), 2)); - p.fillRect(rec_rect, QColor(192, 192, 192)); - p.drawRect(rec_rect); - } - QRect active_rec_rect( - rec_track_x, - rec_track_y, - getScreenPointFromFrame(ParentTimeline()->zoom, panel_sequence_viewer->seq->playhead - panel_sequence_viewer->recording_start), - rec_track_height - ); - p.setPen(QPen(QColor(192, 0, 0), 2)); - p.fillRect(active_rec_rect, QColor(255, 96, 96)); - p.drawRect(active_rec_rect); - - p.setPen(Qt::NoPen); - - if (!panel_sequence_viewer->playing) { - int rec_marker_size = 6; - int rec_track_midY = rec_track_y + (rec_track_height >> 1); - p.setBrush(Qt::white); - QPoint cue_marker[3] = { - QPoint(rec_track_x, rec_track_midY - rec_marker_size), - QPoint(rec_track_x + rec_marker_size, rec_track_midY), - QPoint(rec_track_x, rec_track_midY + rec_marker_size) - }; - p.drawPolygon(cue_marker, 3); - } - } - - // Draw selections - QVector selections = track->Selections(); - for (int j=0;jgetTimelineScreenPointFromFrame(s.in()); - p.setPen(Qt::NoPen); - p.setBrush(Qt::NoBrush); - p.fillRect(selection_x, - track_top, - ParentTimeline()->getTimelineScreenPointFromFrame(s.out()) - selection_x, - track->height(), - QColor(0, 0, 0, 64)); - } - - // Draw splitting cursor - if (ParentTimeline()->splitting && ParentTimeline()->split_tracks.contains(track)) { - int cursor_x = ParentTimeline()->getTimelineScreenPointFromFrame(ParentTimeline()->drag_frame_start); - - p.setPen(QColor(64, 64, 64)); - p.drawLine(cursor_x, - track_top, - cursor_x, - track_top + track->height()); - } - - // Draw edit cursor - if (current_tool_shows_cursor() && ParentTimeline()->cursor_track == track) { - int cursor_x = ParentTimeline()->getTimelineScreenPointFromFrame(ParentTimeline()->cursor_frame); - - p.setPen(Qt::gray); - p.drawLine(cursor_x, - track_top, - cursor_x, - track_top + track->height()); - } - - // Draw track line - p.setPen(QColor(0, 0, 0, 96)); - if (alignment_ == olive::timeline::kAlignmentTop) { - p.drawLine(0, track_bottom, rect().width(), track_bottom); - } else if (alignment_ == olive::timeline::kAlignmentBottom) { - p.drawLine(0, track_top, rect().width(), track_top); - } - } - } - - // draw rectangle select - if (ParentTimeline()->rect_select_proc) { - QRect relative_rect = QRect(mapFromGlobal(ParentTimeline()->rect_select_rect.topLeft()), - mapFromGlobal(ParentTimeline()->rect_select_rect.bottomRight())); - - olive::ui::DrawSelectionRectangle(p, relative_rect); - } - - // Draw ghosts - if (!ParentTimeline()->ghosts.isEmpty()) { - QVector insert_points; - long first_ghost = LONG_MAX; - for (int i=0;ighosts.size();i++) { - const Ghost& g = ParentTimeline()->ghosts.at(i); - first_ghost = qMin(first_ghost, g.in); - if (g.track->type() == type_) { - - int ghost_x = ParentTimeline()->getTimelineScreenPointFromFrame(g.in); - int ghost_y = getScreenPointFromTrackIndex(g.track->Index() + g.track_movement); - int ghost_width = ParentTimeline()->getTimelineScreenPointFromFrame(g.out) - ghost_x - 1; - int ghost_height = getTrackHeightFromTrackIndex(g.track->Index() + g.track_movement) - 1; - - insert_points.append(ghost_y + (ghost_height>>1)); - - p.setPen(QColor(255, 255, 0)); - for (int j=0;jmove_insert && !insert_points.isEmpty()) { - p.setBrush(Qt::white); - p.setPen(Qt::NoPen); - int insert_x = ParentTimeline()->getTimelineScreenPointFromFrame(first_ghost); - int tri_size = olive::timeline::kTrackMinHeight>>2; - - for (int i=0;igetTimelineScreenPointFromFrame(sequence()->playhead); - p.drawLine(playhead_x, rect().top(), playhead_x, rect().bottom()); - - // Draw single frame highlight - int playhead_frame_width = ParentTimeline()->getTimelineScreenPointFromFrame(sequence()->playhead+1) - playhead_x; - if (playhead_frame_width > 5){ //hardcoded for now, maybe better way to do this? - QRectF singleFrameRect(playhead_x, rect().top(), playhead_frame_width, rect().bottom()); - p.fillRect(singleFrameRect, QColor(255,255,255,15)); - } - - // draw border - /* - p.setPen(QColor(0, 0, 0, 64)); - int edge_y = 0; - p.drawLine(0, edge_y, rect().width(), edge_y); - edge_y = rect().height()-1; - p.drawLine(0, edge_y, rect().width(), edge_y); - */ - - // draw snap point - if (olive::timeline::snapped) { - p.setPen(Qt::white); - int snap_x = ParentTimeline()->getTimelineScreenPointFromFrame(olive::timeline::snap_point); - p.drawLine(snap_x, 0, snap_x, height()); - } - } -} - -// ************************************** -// screen point <-> frame/track functions -// ************************************** - -Track *TimelineView::getTrackFromScreenPoint(int y) { - - int index = getTrackIndexFromScreenPoint(y); - - QVector track_list = sequence_->GetTrackList(type_); - - if (index < track_list.size()) { - return track_list.at(index); - } - - return nullptr; - -} - -int TimelineView::getScreenPointFromTrack(Track *track) { - return getScreenPointFromTrackIndex(track->Index()); -} - -int TimelineView::getTrackIndexFromScreenPoint(int y) -{ - if (alignment_ == olive::timeline::kAlignmentSingle) { - return 0; - } - - if (alignment_ == olive::timeline::kAlignmentBottom) { - y = -(y + 1 + scroll - qMax(height(), GetTotalAreaHeight())); - } else { - y += scroll; - } - - if (y < 0) { - return 0; - } - - int heights = 0; - - int i = 0; - - QVector track_list = sequence_->GetTrackList(type_); - - while (true) { - - int new_heights = heights; - - if (i < track_list.size()) { - new_heights += track_list.at(i)->height(); - } else { - new_heights += olive::timeline::kTrackDefaultHeight; - } - - if (y >= heights && y < new_heights) { - return i; - } - - heights = new_heights; - - i++; - } - -} - -int TimelineView::getScreenPointFromTrackIndex(int track) -{ - if (alignment_ == olive::timeline::kAlignmentSingle) { - return 0; - } - - int point = 0; - - int loop_start = 0; - int loop_end = track; - if (alignment_ == olive::timeline::kAlignmentBottom) { - loop_start++; - loop_end++; - } - for (int i=loop_start;iFirstTrack(type_)->height() - 1; - } - - return point - scroll; -} - -int TimelineView::getTrackHeightFromTrackIndex(int track) -{ - if (track < sequence_->TrackCount(type_)) { - return sequence_->TrackAt(type_, track)->height(); - } else { - return olive::timeline::kTrackDefaultHeight; - } -} - -Timeline *TimelineView::ParentTimeline() -{ - return timeline_; -} - -Sequence *TimelineView::sequence() -{ - return sequence_; -} - -void TimelineView::setScroll(int s) { - scroll = s; - update(); -} - -void TimelineView::reveal_media() { - panel_project.first()->reveal_media(rc_reveal_media); -} diff --git a/ui/timelineview.h b/ui/timelineview.h deleted file mode 100644 index 91a2bdb03..000000000 --- a/ui/timelineview.h +++ /dev/null @@ -1,128 +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 TIMELINEWIDGET_H -#define TIMELINEWIDGET_H - -#include -#include -#include -#include -#include -#include - -#include "timeline/sequence.h" -#include "timeline/clip.h" -#include "timeline/timelinetools.h" -#include "timeline/timelinefunctions.h" -#include "project/footage.h" -#include "project/media.h" -#include "undo/undo.h" - -class Timeline; - -class TimelineView : public QWidget { - Q_OBJECT -public: - explicit TimelineView(Timeline *parent); - - void SetAlignment(olive::timeline::Alignment alignment); - void SetTrackType(Sequence* s, olive::TrackType type); - - Track* getTrackFromScreenPoint(int y); - int getScreenPointFromTrack(Track* track); - - int getTrackIndexFromScreenPoint(int y); - int getScreenPointFromTrackIndex(int track); - - int getTrackHeightFromTrackIndex(int track); - -protected: - void paintEvent(QPaintEvent*); - - void mouseDoubleClickEvent(QMouseEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void leaveEvent(QEvent *event); - - void dragEnterEvent(QDragEnterEvent *event); - void dragLeaveEvent(QDragLeaveEvent *event); - void dropEvent(QDropEvent* event); - void dragMoveEvent(QDragMoveEvent *event); - - void wheelEvent(QWheelEvent *event); -private: - void init_ghosts(); - void update_ghosts(const QPoint& mouse_pos, bool lock_frame); - - Timeline* ParentTimeline(); - Sequence* sequence(); - void delete_area_under_ghosts(ComboAction* ca, Sequence *s); - void insert_clips(ComboAction* ca, Sequence *s); - bool current_tool_shows_cursor(); - void draw_transition(QPainter& p, Clip *c, const QRect& clip_rect, QRect& text_rect, int transition_type); - Clip* GetClipAtCursor(); - - QVector GetSplitTracksFromMouseCoords(bool also_split_links, long frame, int top, int bottom); - - void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, long transition_start, long transition_end); - void VerifyTransitionHelper(); - - int GetTotalAreaHeight(); - - Timeline* timeline_; - - olive::timeline::Alignment alignment_; - Sequence* sequence_; - olive::TrackType type_; - - bool track_resizing; - Track* track_target; - - QVector pre_clips; - QVector post_clips; - - Media* rc_reveal_media; - - SequencePtr self_created_sequence; - - QTimer tooltip_timer; - Clip* tooltip_clip; - - int scroll; - -signals: - void setScrollMaximum(int); - void requestScrollChange(int); - -public slots: - void setScroll(int); - -private slots: - void reveal_media(); - void show_context_menu(const QPoint& pos); - void toggle_autoscale(); - void tooltip_timer_timeout(); - void open_sequence_properties(); - void show_clip_properties(); -}; - -#endif // TIMELINEWIDGET_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp deleted file mode 100644 index 588cee783..000000000 --- a/ui/timelinewidget.cpp +++ /dev/null @@ -1,3451 +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 "timelinewidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "global/global.h" -#include "panels/panels.h" -#include "project/projectelements.h" -#include "rendering/audio.h" -#include "global/config.h" -#include "ui/sourcetable.h" -#include "ui/sourceiconview.h" -#include "undo/undo.h" -#include "undo/undostack.h" -#include "ui/viewerwidget.h" -#include "ui/resizablescrollbar.h" -#include "dialogs/newsequencedialog.h" -#include "mainwindow.h" -#include "ui/rectangleselect.h" -#include "rendering/renderfunctions.h" -#include "ui/cursors.h" -#include "ui/menuhelper.h" -#include "ui/menu.h" -#include "ui/focusfilter.h" -#include "dialogs/clippropertiesdialog.h" -#include "global/debug.h" -#include "effects/effect.h" -#include "effects/internal/solideffect.h" - -#define MAX_TEXT_WIDTH 20 -#define TRANSITION_BETWEEN_RANGE 40 - -TimelineWidget::TimelineWidget(QWidget *parent) : QWidget(parent) { - selection_command = nullptr; - self_created_sequence = nullptr; - scroll = 0; - - bottom_align = false; - track_resizing = false; - setMouseTracking(true); - - setAcceptDrops(true); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); - - tooltip_timer.setInterval(500); - connect(&tooltip_timer, SIGNAL(timeout()), this, SLOT(tooltip_timer_timeout())); -} - -void TimelineWidget::show_context_menu(const QPoint& pos) { - if (olive::ActiveSequence != nullptr) { - // hack because sometimes right clicking doesn't trigger mouse release event - panel_timeline->rect_select_init = false; - panel_timeline->rect_select_proc = false; - - Menu menu(this); - - QAction* undoAction = menu.addAction(tr("&Undo")); - QAction* redoAction = menu.addAction(tr("&Redo")); - connect(undoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(undo())); - connect(redoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(redo())); - undoAction->setEnabled(olive::UndoStack.canUndo()); - redoAction->setEnabled(olive::UndoStack.canRedo()); - menu.addSeparator(); - - // collect all the selected clips - QVector selected_clips = olive::ActiveSequence->SelectedClips(); - - olive::MenuHelper.make_edit_functions_menu(&menu, !selected_clips.isEmpty()); - - if (selected_clips.isEmpty()) { - // no clips are selected - - // determine if we can perform a ripple empty space - panel_timeline->cursor_frame = panel_timeline->getTimelineFrameFromScreenPoint(pos.x()); - panel_timeline->cursor_track = getTrackFromScreenPoint(pos.y()); - - if (panel_timeline->can_ripple_empty_space(panel_timeline->cursor_frame, panel_timeline->cursor_track)) { - QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete Empty Space")); - connect(ripple_delete_action, SIGNAL(triggered(bool)), panel_timeline, SLOT(ripple_delete_empty_space())); - } - - QAction* seq_settings = menu.addAction(tr("Sequence Settings")); - connect(seq_settings, SIGNAL(triggered(bool)), this, SLOT(open_sequence_properties())); - } - - if (!selected_clips.isEmpty()) { - - bool video_clips_are_selected = false; - bool audio_clips_are_selected = false; - - for (int i=0;itrack() < 0) { - video_clips_are_selected = true; - } else { - audio_clips_are_selected = true; - } - } - - menu.addSeparator(); - - menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog())); - - if (audio_clips_are_selected) { - menu.addAction(tr("Auto-Cut Silence"), olive::Global.get(), SLOT(open_autocut_silence_dialog())); - } - - QAction* autoscaleAction = menu.addAction(tr("Auto-S&cale"), this, SLOT(toggle_autoscale())); - autoscaleAction->setCheckable(true); - // set autoscale to the first selected clip - autoscaleAction->setChecked(selected_clips.at(0)->autoscaled()); - - olive::MenuHelper.make_clip_functions_menu(&menu); - - // stabilizer option - /*int video_clip_count = 0; - bool all_video_is_footage = true; - for (int i=0;itrack() < 0) { - video_clip_count++; - if (selected_clips.at(i)->media() == nullptr - || selected_clips.at(i)->media()->get_type() != MEDIA_TYPE_FOOTAGE) { - all_video_is_footage = false; - } - } - } - if (video_clip_count == 1 && all_video_is_footage) { - QAction* stabilizerAction = menu.addAction("S&tabilizer"); - connect(stabilizerAction, SIGNAL(triggered(bool)), this, SLOT(show_stabilizer_diag())); - }*/ - - // check if all selected clips have the same media for a "Reveal In Project" - bool same_media = true; - rc_reveal_media = selected_clips.at(0)->media(); - for (int i=1;imedia() != rc_reveal_media) { - same_media = false; - break; - } - } - - if (same_media) { - QAction* revealInProjectAction = menu.addAction(tr("&Reveal in Project")); - connect(revealInProjectAction, SIGNAL(triggered(bool)), this, SLOT(reveal_media())); - } - - menu.addAction(tr("Properties"), this, SLOT(show_clip_properties())); - } - - menu.exec(mapToGlobal(pos)); - } -} - -void TimelineWidget::toggle_autoscale() { - QVector selected_clips = olive::ActiveSequence->SelectedClips(); - - if (!selected_clips.isEmpty()) { - SetClipProperty* action = new SetClipProperty(kSetClipPropertyAutoscale); - - for (int i=0;iAddSetting(c, !c->autoscaled()); - } - - olive::UndoStack.push(action); - } -} - -void TimelineWidget::tooltip_timer_timeout() { - if (olive::ActiveSequence != nullptr) { - if (tooltip_clip < olive::ActiveSequence->clips.size()) { - ClipPtr c = olive::ActiveSequence->clips.at(tooltip_clip); - if (c != nullptr) { - QToolTip::showText(QCursor::pos(), - tr("%1\nStart: %2\nEnd: %3\nDuration: %4").arg( - c->name(), - frame_to_timecode(c->timeline_in(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate), - frame_to_timecode(c->timeline_out(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate), - frame_to_timecode(c->length(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate) - )); - } - } - } - tooltip_timer.stop(); -} - -void TimelineWidget::open_sequence_properties() { - QList sequence_items; - QList all_top_level_items; - for (int i=0;iget_all_media_from_table(all_top_level_items, sequence_items, MEDIA_TYPE_SEQUENCE); // find all sequences in project - for (int i=0;ito_sequence() == olive::ActiveSequence) { - NewSequenceDialog nsd(this, sequence_items.at(i)); - nsd.exec(); - return; - } - } - QMessageBox::critical(this, tr("Error"), tr("Couldn't locate media wrapper for sequence.")); -} - -void TimelineWidget::show_clip_properties() -{ - // get list of selected clips - QVector selected_clips = olive::ActiveSequence->SelectedClips(); - - // if clips are selected, open the clip properties dialog - if (!selected_clips.isEmpty()) { - ClipPropertiesDialog cpd(this, selected_clips); - cpd.exec(); - } -} - -bool same_sign(int a, int b) { - return (a < 0) == (b < 0); -} - -void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { - bool import_init = false; - - QVector media_list; - panel_timeline->importing_files = false; - - if (panel_project->IsProjectWidget(event->source())) { - QModelIndexList items = panel_project->get_current_selected(); - media_list.resize(items.size()); - for (int i=0;iitem_to_media(items.at(i)); - } - import_init = true; - } - - if (event->source() == panel_footage_viewer) { - if (panel_footage_viewer->seq != olive::ActiveSequence) { // don't allow nesting the same sequence - - media_list.append(olive::timeline::MediaImportData(panel_footage_viewer->media, - static_cast(event->mimeData()->text().toInt()))); - import_init = true; - - } - } - - if (olive::CurrentConfig.enable_drag_files_to_timeline && event->mimeData()->hasUrls()) { - QList urls = event->mimeData()->urls(); - if (!urls.isEmpty()) { - QStringList file_list; - - for (int i=0;iprocess_file_list(file_list); - - for (int i=0;ilast_imported_media.size();i++) { - Footage* f = panel_project->last_imported_media.at(i)->to_footage(); - - // waits for media to have a duration - // TODO would be much nicer if this was multithreaded - f->ready_lock.lock(); - f->ready_lock.unlock(); - - if (f->ready) { - media_list.append(panel_project->last_imported_media.at(i)); - } - } - - if (media_list.isEmpty()) { - olive::UndoStack.undo(); - } else { - import_init = true; - panel_timeline->importing_files = true; - } - } - } - - if (import_init) { - event->acceptProposedAction(); - - long entry_point; - Sequence* seq = olive::ActiveSequence.get(); - - if (seq == nullptr) { - // if no sequence, we're going to create a new one using the clips as a reference - entry_point = 0; - - self_created_sequence = create_sequence_from_media(media_list); - seq = self_created_sequence.get(); - } else { - entry_point = panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x()); - panel_timeline->drag_frame_start = entry_point + getFrameFromScreenPoint(panel_timeline->zoom, 50); - panel_timeline->drag_track_start = (bottom_align) ? -1 : 0; - } - - panel_timeline->create_ghosts_from_media(seq, entry_point, media_list); - - panel_timeline->importing = true; - } -} - -void TimelineWidget::dragMoveEvent(QDragMoveEvent *event) { - if (panel_timeline->importing) { - event->acceptProposedAction(); - - if (olive::ActiveSequence != nullptr) { - QPoint pos = event->pos(); - panel_timeline->scroll_to_frame(panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x())); - update_ghosts(pos, event->keyboardModifiers() & Qt::ShiftModifier); - panel_timeline->move_insert = ((event->keyboardModifiers() & Qt::ControlModifier) && (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->importing)); - update_ui(false); - } - } -} - -void TimelineWidget::wheelEvent(QWheelEvent *event) { - - // TODO: implement pixel scrolling - - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool ctrl = (event->modifiers() & Qt::ControlModifier); - bool alt = (event->modifiers() & Qt::AltModifier); - - // "Scroll Zooms" false + Control up : not zooming - // "Scroll Zooms" false + Control down: zooming - // "Scroll Zooms" true + Control up : zooming - // "Scroll Zooms" true + Control down: not zooming - bool zooming = (olive::CurrentConfig.scroll_zooms != ctrl); - - // Allow shift for axis swap, but don't swap on zoom... Unless - // we need to override Qt's axis swap via Alt - bool swap_hv = ((shift != olive::CurrentConfig.invert_timeline_scroll_axes) & - !zooming) | (alt & !shift & zooming); - - int delta_h = swap_hv ? event->angleDelta().y() : event->angleDelta().x(); - int delta_v = swap_hv ? event->angleDelta().x() : event->angleDelta().y(); - - if (zooming) { - - // Zoom only uses vertical scrolling, to avoid glitches on touchpads. - // Don't do anything if not scrolling vertically. - - if (delta_v != 0) { - - // delta_v == 120 for one click of a mousewheel. Less or more for a - // touchpad gesture. Calculate speed to compensate. - // 120 = ratio of 4/3 (1.33), -120 = ratio of 3/4 (.75) - - double zoom_ratio = 1.0 + (abs(delta_v) * 0.33 / 120); - - if (delta_v < 0) { - zoom_ratio = 1.0 / zoom_ratio; - } - - panel_timeline->multiply_zoom(zoom_ratio); - } - - } else { - - // Use the Timeline's main scrollbar for horizontal scrolling, and this - // widget's scrollbar for vertical scrolling. - - QScrollBar* bar_v = scrollBar; - QScrollBar* bar_h = panel_timeline->horizontalScrollBar; - - // Match the wheel events to the size of a step as per - // https://doc.qt.io/qt-5/qwheelevent.html#angleDelta - - int step_h = bar_h->singleStep() * delta_h / -120; - int step_v = bar_v->singleStep() * delta_v / -120; - - // Apply to appropriate scrollbars - - bar_h->setValue(bar_h->value() + step_h); - bar_v->setValue(bar_v->value() + step_v); - } -} - -void TimelineWidget::dragLeaveEvent(QDragLeaveEvent* event) { - event->accept(); - if (panel_timeline->importing) { - if (panel_timeline->importing_files) { - olive::UndoStack.undo(); - } - panel_timeline->importing_files = false; - panel_timeline->ghosts.clear(); - panel_timeline->importing = false; - update_ui(false); - } - if (self_created_sequence != nullptr) { - self_created_sequence.reset(); - self_created_sequence = nullptr; - } -} - -void delete_area_under_ghosts(ComboAction* ca) { - // delete areas before adding - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - Selection sel; - sel.in = g.in; - sel.out = g.out; - sel.track = g.track; - delete_areas.append(sel); - } - panel_timeline->delete_areas_and_relink(ca, delete_areas, false); -} - -void insert_clips(ComboAction* ca) { - bool ripple_old_point = true; - - long earliest_old_point = LONG_MAX; - long latest_old_point = LONG_MIN; - - long earliest_new_point = LONG_MAX; - long latest_new_point = LONG_MIN; - - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - - earliest_old_point = qMin(earliest_old_point, g.old_in); - latest_old_point = qMax(latest_old_point, g.old_out); - earliest_new_point = qMin(earliest_new_point, g.in); - latest_new_point = qMax(latest_new_point, g.out); - - if (g.clip >= 0) { - ignore_clips.append(g.clip); - } else { - // don't try to close old gap if importing - ripple_old_point = false; - } - } - - panel_timeline->split_cache.clear(); - - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr) { - // don't split any clips that are moving - bool found = false; - for (int j=0;jghosts.size();j++) { - if (panel_timeline->ghosts.at(j).clip == i) { - found = true; - break; - } - } - if (!found) { - if (c->timeline_in() < earliest_new_point && c->timeline_out() > earliest_new_point) { - panel_timeline->split_clip_and_relink(ca, i, earliest_new_point, true); - } - - // determine if we should close the gap the old clips left behind - if (ripple_old_point - && !((c->timeline_in() < earliest_old_point && c->timeline_out() <= earliest_old_point) || (c->timeline_in() >= latest_old_point && c->timeline_out() > latest_old_point)) - && !ignore_clips.contains(i)) { - ripple_old_point = false; - } - } - } - } - - long ripple_length = (latest_new_point - earliest_new_point); - - ripple_clips(ca, olive::ActiveSequence.get(), earliest_new_point, ripple_length, ignore_clips); - - if (ripple_old_point) { - // works for moving later clips earlier but not earlier to later - long second_ripple_length = (earliest_old_point - latest_old_point); - - ripple_clips(ca, olive::ActiveSequence.get(), latest_old_point, second_ripple_length, ignore_clips); - - if (earliest_old_point < earliest_new_point) { - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - g.in += second_ripple_length; - g.out += second_ripple_length; - } - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; - s.in += second_ripple_length; - s.out += second_ripple_length; - } - } - } -} - -void TimelineWidget::dropEvent(QDropEvent* event) { - if (panel_timeline->importing && panel_timeline->ghosts.size() > 0) { - event->acceptProposedAction(); - - ComboAction* ca = new ComboAction(); - - Sequence* s = olive::ActiveSequence.get(); - - // if we're dropping into nothing, create a new sequences based on the clip being dragged - if (s == nullptr) { - s = self_created_sequence.get(); - panel_project->create_sequence_internal(ca, self_created_sequence, true, nullptr); - self_created_sequence = nullptr; - } else if (event->keyboardModifiers() & Qt::ControlModifier) { - insert_clips(ca); - } else { - delete_area_under_ghosts(ca); - } - - panel_timeline->add_clips_from_ghosts(ca, s); - - olive::UndoStack.push(ca); - - setFocus(); - - update_ui(true); - } -} - -void TimelineWidget::mouseDoubleClickEvent(QMouseEvent *event) { - if (olive::ActiveSequence != nullptr) { - if (panel_timeline->tool == TIMELINE_TOOL_EDIT) { - int clip_index = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); - if (clip_index >= 0) { - ClipPtr clip = olive::ActiveSequence->clips.at(clip_index); - if (!(event->modifiers() & Qt::ShiftModifier)) olive::ActiveSequence->selections.clear(); - Selection s; - s.in = clip->timeline_in(); - s.out = clip->timeline_out(); - s.track = clip->track(); - olive::ActiveSequence->selections.append(s); - update_ui(false); - } - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - int clip_index = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); - if (clip_index >= 0) { - ClipPtr c = olive::ActiveSequence->clips.at(clip_index); - if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) { - olive::Global->set_sequence(c->media()->to_sequence()); - } - } - } - } -} - -bool current_tool_shows_cursor() { - return (panel_timeline->tool == TIMELINE_TOOL_EDIT || panel_timeline->tool == TIMELINE_TOOL_RAZOR || panel_timeline->creating); -} - -void TimelineWidget::mousePressEvent(QMouseEvent *event) { - if (olive::ActiveSequence != nullptr) { - - int effective_tool = panel_timeline->tool; - - // some user actions will override which tool we'll be using - if (event->button() == Qt::MiddleButton) { - effective_tool = TIMELINE_TOOL_HAND; - panel_timeline->creating = false; - } else if (event->button() == Qt::RightButton) { - effective_tool = TIMELINE_TOOL_MENU; - panel_timeline->creating = false; - } - - // ensure cursor_frame and cursor_track are up to date - mouseMoveEvent(event); - - // store current cursor positions - panel_timeline->drag_x_start = event->pos().x(); - panel_timeline->drag_y_start = event->pos().y(); - - // store current frame/tracks as the values to start dragging from - panel_timeline->drag_frame_start = panel_timeline->cursor_frame; - panel_timeline->drag_track_start = panel_timeline->cursor_track; - - // get the clip the user is currently hovering over, priority to trim_target set from mouseMoveEvent - int hovered_clip = panel_timeline->trim_target == -1 ? - getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track) - : panel_timeline->trim_target; - - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool alt = (event->modifiers() & Qt::AltModifier); - - // Normal behavior is to reset selections to zero when clicking, but if Shift is held, we add selections - // to the existing selections. `selection_offset` is the index to change selections from (and we don't touch - // any prior to that) - if (shift) { - panel_timeline->selection_offset = olive::ActiveSequence->selections.size(); - } else { - panel_timeline->selection_offset = 0; - } - - // if the user is creating an object - if (panel_timeline->creating) { - int comp = 0; - switch (panel_timeline->creating_object) { - case ADD_OBJ_TITLE: - case ADD_OBJ_SOLID: - case ADD_OBJ_BARS: - comp = -1; - break; - case ADD_OBJ_TONE: - case ADD_OBJ_NOISE: - case ADD_OBJ_AUDIO: - comp = 1; - break; - } - - // if the track the user clicked is correct for the type of object we're adding - - if ((panel_timeline->drag_track_start < 0) == (comp < 0)) { - Ghost g; - g.in = g.old_in = g.out = g.old_out = panel_timeline->drag_frame_start; - g.track = g.old_track = panel_timeline->drag_track_start; - g.transition = nullptr; - g.clip = -1; - g.trim_type = TRIM_OUT; - panel_timeline->ghosts.append(g); - - panel_timeline->moving_init = true; - panel_timeline->moving_proc = true; - } - } else { - - // pass through tools to determine what action we'll be starting - switch (effective_tool) { - - // many tools share pointer-esque behavior - case TIMELINE_TOOL_POINTER: - case TIMELINE_TOOL_RIPPLE: - case TIMELINE_TOOL_SLIP: - case TIMELINE_TOOL_ROLLING: - case TIMELINE_TOOL_SLIDE: - case TIMELINE_TOOL_MENU: - { - if (track_resizing && effective_tool != TIMELINE_TOOL_MENU) { - - // if the cursor is currently hovering over a track, init track resizing - panel_timeline->moving_init = true; - - } else { - - // check if we're currently hovering over a clip or not - if (hovered_clip >= 0) { - Clip* clip = olive::ActiveSequence->clips.at(hovered_clip).get(); - - if (clip->IsSelected()) { - - if (shift) { - - // if the user clicks a selected clip while holding shift, deselect the clip - panel_timeline->deselect_area(clip->timeline_in(), clip->timeline_out(), clip->track()); - - // if the user isn't holding alt, also deselect all of its links as well - if (!alt) { - for (int i=0;ilinked.size();i++) { - ClipPtr link = olive::ActiveSequence->clips.at(clip->linked.at(i)); - panel_timeline->deselect_area(link->timeline_in(), link->timeline_out(), link->track()); - } - } - - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER - && panel_timeline->transition_select != kTransitionNone) { - - // if the clip was selected by then the user clicked a transition, de-select the clip and its links - // and select the transition only - - panel_timeline->deselect_area(clip->timeline_in(), clip->timeline_out(), clip->track()); - - for (int i=0;ilinked.size();i++) { - ClipPtr link = olive::ActiveSequence->clips.at(clip->linked.at(i)); - panel_timeline->deselect_area(link->timeline_in(), link->timeline_out(), link->track()); - } - - Selection s; - s.track = clip->track(); - - // select the transition only - if (panel_timeline->transition_select == kTransitionOpening && clip->opening_transition != nullptr) { - s.in = clip->timeline_in(); - - if (clip->opening_transition->secondary_clip != nullptr) { - s.in -= clip->opening_transition->get_true_length(); - } - - s.out = clip->timeline_in() + clip->opening_transition->get_true_length(); - } else if (panel_timeline->transition_select == kTransitionClosing && clip->closing_transition != nullptr) { - s.in = clip->timeline_out() - clip->closing_transition->get_true_length(); - s.out = clip->timeline_out(); - - if (clip->closing_transition->secondary_clip != nullptr) { - s.out += clip->closing_transition->get_true_length(); - } - } - olive::ActiveSequence->selections.append(s); - } - } else { - - // if the clip is not already selected - - // if shift is NOT down, we change clear all current selections - if (!shift) { - olive::ActiveSequence->selections.clear(); - } - - Selection s; - - s.in = clip->timeline_in(); - s.out = clip->timeline_out(); - s.track = clip->track(); - - // if user is using the pointer tool, they may be trying to select a transition - // check if the use is hovering over a transition - if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - if (panel_timeline->transition_select == kTransitionOpening) { - // move the selection to only select the transitoin - s.out = clip->timeline_in() + clip->opening_transition->get_true_length(); - - // if the transition is a "shared" transition, adjust the selection to select both sides - if (clip->opening_transition->secondary_clip != nullptr) { - s.in -= clip->opening_transition->get_true_length(); - } - } else if (panel_timeline->transition_select == kTransitionClosing) { - // move the selection to only select the transitoin - s.in = clip->timeline_out() - clip->closing_transition->get_true_length(); - - // if the transition is a "shared" transition, adjust the selection to select both sides - if (clip->closing_transition->secondary_clip != nullptr) { - s.out += clip->closing_transition->get_true_length(); - } - } - } - - // add the selection to the array - olive::ActiveSequence->selections.append(s); - - // if the config is set to also seek with selections, do so now - if (olive::CurrentConfig.select_also_seeks) { - panel_sequence_viewer->seek(clip->timeline_in()); - } - - // if alt is not down, select links (provided we're not selecting transitions) - if (!alt && panel_timeline->transition_select == kTransitionNone) { - - for (int i=0;ilinked.size();i++) { - - Clip* link = olive::ActiveSequence->clips.at(clip->linked.at(i)).get(); - - // check if the clip is already selected - if (!link->IsSelected()) { - Selection ss; - ss.in = link->timeline_in(); - ss.out = link->timeline_out(); - ss.track = link->track(); - olive::ActiveSequence->selections.append(ss); - } - - } - - } - } - - // authorize the starting of a move action if the mouse moves after this - if (effective_tool != TIMELINE_TOOL_MENU) { - panel_timeline->moving_init = true; - } - - } else { - - // if the user did not click a clip at all, we start a rectangle selection - - if (!shift) { - olive::ActiveSequence->selections.clear(); - } - - panel_timeline->rect_select_init = true; - } - - // update everything - update_ui(false); - } - } - break; - case TIMELINE_TOOL_HAND: - - // initiate moving with the hand tool - panel_timeline->hand_moving = true; - - break; - case TIMELINE_TOOL_EDIT: - - // if the config is set to seek with the edit tool, do so now - if (olive::CurrentConfig.edit_tool_also_seeks) { - panel_sequence_viewer->seek(panel_timeline->drag_frame_start); - } - - // initiate selecting - panel_timeline->selecting = true; - - break; - case TIMELINE_TOOL_RAZOR: - { - - // initiate razor tool - panel_timeline->splitting = true; - - // add this track as a track being split by the razor - panel_timeline->split_tracks.append(panel_timeline->drag_track_start); - - update_ui(false); - } - break; - case TIMELINE_TOOL_TRANSITION: - { - - // if there is a clip to run the transition tool on, initiate the transition tool - if (panel_timeline->transition_tool_open_clip > -1 - || panel_timeline->transition_tool_close_clip > -1) { - panel_timeline->transition_tool_init = true; - } - - } - break; - } - } - } -} - -void make_room_for_transition(ComboAction* ca, - Clip* c, - int type, - long transition_start, - long transition_end, - bool delete_old_transitions, - long timeline_in = -1, - long timeline_out = -1) { - // it's possible to specify other in/out points for the clip, but default behavior is to use the ones existing - if (timeline_in < 0) { - timeline_in = c->timeline_in(); - } - if (timeline_out < 0) { - timeline_out = c->timeline_out(); - } - - // make room for transition - if (type == kTransitionOpening) { - if (delete_old_transitions && c->opening_transition != nullptr) { - ca->append(new DeleteTransitionCommand(c->opening_transition)); - } - if (c->closing_transition != nullptr) { - if (transition_end >= c->timeline_out()) { - ca->append(new DeleteTransitionCommand(c->closing_transition)); - } else if (transition_end > c->timeline_out() - c->closing_transition->get_true_length()) { - ca->append(new ModifyTransitionCommand(c->closing_transition, c->timeline_out() - transition_end)); - } - } - } else { - if (delete_old_transitions && c->closing_transition != nullptr) { - ca->append(new DeleteTransitionCommand(c->closing_transition)); - } - if (c->opening_transition != nullptr) { - if (transition_start <= c->timeline_in()) { - ca->append(new DeleteTransitionCommand(c->opening_transition)); - } else if (transition_start < c->timeline_in() + c->opening_transition->get_true_length()) { - ca->append(new ModifyTransitionCommand(c->opening_transition, transition_start - c->timeline_in())); - } - } - } -} - -void VerifyTransitionsAfterCreating(ComboAction* ca, Clip* open, Clip* close, long transition_start, long transition_end) { - // in case the user made the transition larger than the clips, we're going to delete everything under - // the transition ghost and extend the clips to the transition's coordinates as necessary - - if (open == nullptr && close == nullptr) { - qWarning() << "VerifyTransitionsAfterCreating() called with two null clips"; - return; - } - - // determine whether this is a "shared" transition between to clips or not - bool shared_transition = (open != nullptr && close != nullptr); - - int track = 0; - - // first we set the clips to "undeletable" so they aren't affected by delete_areas_and_relink() - if (open != nullptr) { - open->undeletable = true; - track = open->track(); - } - if (close != nullptr) { - close->undeletable = true; - track = close->track(); - } - - // set the area to delete to the transition's coordinates and clear it - QVector areas; - Selection s; - s.in = transition_start; - s.out = transition_end; - s.track = track; - areas.append(s); - panel_timeline->delete_areas_and_relink(ca, areas, false); - - // set the clips back to undeletable now that we're done - if (open != nullptr) { - open->undeletable = false; - } - if (close != nullptr) { - close->undeletable = false; - } - - // loop through both kinds of transition - for (int t=kTransitionOpening;t<=kTransitionClosing;t++) { - - Clip* clip_ref = (t == kTransitionOpening) ? open : close; - - // if we have an opening transition: - if (clip_ref != nullptr) { - - // make_room_for_transition will adjust the opposite transition to make space for this one, - // for example if the user makes an opening transition that overlaps the closing transition, it'll resize - // or even delete the closing transition if necessary (and vice versa) - - make_room_for_transition(ca, clip_ref, t, transition_start, transition_end, true); - - // check if the transition coordinates require the clip to be resized - if (transition_start < clip_ref->timeline_in() || transition_end > clip_ref->timeline_out()) { - - long new_in, new_out; - - if (t == kTransitionOpening) { - - // if the transition is shared, it doesn't matter if the transition extend beyond the in point since - // that'll be "absorbed" by the other clip - new_in = (shared_transition) ? open->timeline_in() : qMin(transition_start, open->timeline_in()); - - new_out = qMax(transition_end, open->timeline_out()); - - } else { - - new_in = qMin(transition_start, close->timeline_in()); - - // if the transition is shared, it doesn't matter if the transition extend beyond the out point since - // that'll be "absorbed" by the other clip - new_out = (shared_transition) ? close->timeline_out() : qMax(transition_end, close->timeline_out()); - - } - - - - clip_ref->move(ca, - new_in, - new_out, - clip_ref->clip_in() - (clip_ref->timeline_in() - new_in), - clip_ref->track()); - } - } - } -} - -void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { - QToolTip::hideText(); - if (olive::ActiveSequence != nullptr) { - bool alt = (event->modifiers() & Qt::AltModifier); - bool shift = (event->modifiers() & Qt::ShiftModifier); - bool ctrl = (event->modifiers() & Qt::ControlModifier); - - if (event->button() == Qt::LeftButton) { - ComboAction* ca = new ComboAction(); - bool push_undo = false; - - if (panel_timeline->creating) { - if (panel_timeline->ghosts.size() > 0) { - const Ghost& g = panel_timeline->ghosts.at(0); - - if (panel_timeline->creating_object == ADD_OBJ_AUDIO) { - olive::MainWindow->statusBar()->clearMessage(); - panel_sequence_viewer->cue_recording(qMin(g.in, g.out), qMax(g.in, g.out), g.track); - panel_timeline->creating = false; - } else if (g.in != g.out) { - ClipPtr c = std::make_shared(olive::ActiveSequence.get()); - c->set_media(nullptr, 0); - c->set_timeline_in(qMin(g.in, g.out)); - c->set_timeline_out(qMax(g.in, g.out)); - c->set_clip_in(0); - c->set_color(192, 192, 64); - c->set_track(g.track); - - if (ctrl) { - insert_clips(ca); - } else { - Selection s; - s.in = c->timeline_in(); - s.out = c->timeline_out(); - s.track = c->track(); - QVector areas; - areas.append(s); - panel_timeline->delete_areas_and_relink(ca, areas, false); - } - - QVector add; - add.append(c); - ca->append(new AddClipCommand(olive::ActiveSequence.get(), add)); - - if (c->track() < 0 && olive::CurrentConfig.add_default_effects_to_clips) { - // default video effects (before custom effects) - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT))); - } - - switch (panel_timeline->creating_object) { - case ADD_OBJ_TITLE: - c->set_name(tr("Title")); - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_RICHTEXT, EFFECT_TYPE_EFFECT))); - break; - case ADD_OBJ_SOLID: - c->set_name(tr("Solid Color")); - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT))); - break; - case ADD_OBJ_BARS: - { - c->set_name(tr("Bars")); - EffectPtr e = Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT)); - - // Auto-select bars - SolidEffect* solid_effect = static_cast(e.get()); - solid_effect->SetType(SolidEffect::SOLID_TYPE_BARS); - - c->effects.append(e); - } - break; - case ADD_OBJ_TONE: - c->set_name(tr("Tone")); - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_TONE, EFFECT_TYPE_EFFECT))); - break; - case ADD_OBJ_NOISE: - c->set_name(tr("Noise")); - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_NOISE, EFFECT_TYPE_EFFECT))); - break; - } - - if (c->track() >= 0 && olive::CurrentConfig.add_default_effects_to_clips) { - // default audio effects (after custom effects) - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT))); - c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT))); - } - - push_undo = true; - - if (!shift) { - panel_timeline->creating = false; - } - } - } - } else if (panel_timeline->moving_proc) { - - // see if any clips actually moved, otherwise we don't need to do any processing - // (perhaps this could be moved further up to cover more actions?) - - bool process_moving = false; - - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - if (g.in != g.old_in - || g.out != g.old_out - || g.clip_in != g.old_clip_in - || g.track != g.old_track) { - process_moving = true; - break; - } - } - - if (process_moving) { - const Ghost& first_ghost = panel_timeline->ghosts.at(0); - - // start a ripple movement - if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { - - // ripple_length becomes the length/number of frames we trimmed - // ripple_point is the "axis" around which we move all the clips, any clips after it get moved - long ripple_length; - long ripple_point = LONG_MAX; - - if (panel_timeline->trim_type == TRIM_IN) { - - // it's assumed that all the ghosts rippled by the same length, so we just take the difference of the - // first ghost here - ripple_length = first_ghost.old_in - first_ghost.in; - - // for in trimming movements we also move the selections forward (unnecessary for out trimming since - // the selected clips more or less stay in the same place) - for (int i=0;iselections.size();i++) { - olive::ActiveSequence->selections[i].in += ripple_length; - olive::ActiveSequence->selections[i].out += ripple_length; - } - } else { - - // use the out points for length if the user trimmed the out point - ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out; - - } - - // build a list of "ignore clips" that won't get affected by ripple_clips() below - QVector ignore_clips; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - - // for the same reason that we pushed selections forward above, for in trimming, - // we push the ghosts forward here - if (panel_timeline->trim_type == TRIM_IN) { - ignore_clips.append(g.clip); - panel_timeline->ghosts[i].in += ripple_length; - panel_timeline->ghosts[i].out += ripple_length; - } - - // find the earliest ripple point - long comp_point = (panel_timeline->trim_type == TRIM_IN) ? g.old_in : g.old_out; - ripple_point = qMin(ripple_point, comp_point); - } - - // if this was out trimming, flip the direction of the ripple - if (panel_timeline->trim_type == TRIM_OUT) ripple_length = -ripple_length; - - // finally, ripple everything - ripple_clips(ca, olive::ActiveSequence.get(), ripple_point, ripple_length, ignore_clips); - } - - if (panel_timeline->tool == TIMELINE_TOOL_POINTER - && (event->modifiers() & Qt::AltModifier) - && panel_timeline->trim_target == -1) { - - // if the user was holding alt (and not trimming), we duplicate clips rather than move them - QVector old_clips; - QVector new_clips; - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { - - // create copy of clip - ClipPtr c = olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence.get()); - - c->set_timeline_in(g.in); - c->set_timeline_out(g.out); - c->set_track(g.track); - - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); - - old_clips.append(g.clip); - new_clips.append(c); - - } - } - - if (new_clips.size() > 0) { - - // delete anything under the new clips - panel_timeline->delete_areas_and_relink(ca, delete_areas, false); - - // relink duplicated clips - panel_timeline->relink_clips_using_ids(old_clips, new_clips); - - // add them - ca->append(new AddClipCommand(olive::ActiveSequence.get(), new_clips)); - - } - - } else { - - // if we're not holding alt, this will just be a move - - // if the user is holding ctrl, perform an insert rather than an overwrite - if (panel_timeline->tool == TIMELINE_TOOL_POINTER && ctrl) { - - insert_clips(ca); - - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_SLIDE) { - - // if the user is not holding ctrl, we start standard clip movement - - // delete everything under the new clips - QVector delete_areas; - for (int i=0;ighosts.size();i++) { - // step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them) - const Ghost& g = panel_timeline->ghosts.at(i); - - // set clip to undeletable so it's unaffected by delete_areas_and_relink() below - olive::ActiveSequence->clips.at(g.clip)->undeletable = true; - - // if the user was moving a transition make sure they're undeletable too - if (g.transition != nullptr) { - g.transition->parent_clip->undeletable = true; - if (g.transition->secondary_clip != nullptr) { - g.transition->secondary_clip->undeletable = true; - } - } - - // set area to delete - Selection s; - s.in = g.in; - s.out = g.out; - s.track = g.track; - delete_areas.append(s); - } - - panel_timeline->delete_areas_and_relink(ca, delete_areas, false); - - // clean up, i.e. make everything not undeletable again - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - olive::ActiveSequence->clips.at(g.clip)->undeletable = false; - - if (g.transition != nullptr) { - g.transition->parent_clip->undeletable = false; - if (g.transition->secondary_clip != nullptr) { - g.transition->secondary_clip->undeletable = false; - } - } - } - } - - // finally, perform actual movement of clips - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - - Clip* c = olive::ActiveSequence->clips.at(g.clip).get(); - - if (g.transition == nullptr) { - - // if this was a clip rather than a transition - - c->move(ca, (g.in - g.old_in), (g.out - g.old_out), (g.clip_in - g.old_clip_in), (g.track - g.old_track), false, true); - - } else { - - // if the user was moving a transition - - bool is_opening_transition = (g.transition == c->opening_transition); - long new_transition_length = g.out - g.in; - if (g.transition->secondary_clip != nullptr) new_transition_length >>= 1; - ca->append( - new ModifyTransitionCommand(is_opening_transition ? c->opening_transition : c->closing_transition, - new_transition_length) - ); - - long clip_length = c->length(); - - if (g.transition->secondary_clip != nullptr) { - - // if this is a shared transition - if (g.in != g.old_in && g.trim_type == TRIM_NONE) { - long movement = g.in - g.old_in; - - // check if the transition is going to extend the out point (opening clip) - long timeline_out_movement = 0; - if (g.out > g.transition->parent_clip->timeline_out()) { - timeline_out_movement = g.out - g.transition->parent_clip->timeline_out(); - } - - // check if the transition is going to extend the in point (closing clip) - long timeline_in_movement = 0; - if (g.in < g.transition->secondary_clip->timeline_in()) { - timeline_in_movement = g.in - g.transition->secondary_clip->timeline_in(); - } - - g.transition->parent_clip->move(ca, movement, timeline_out_movement, movement, 0, false, true); - g.transition->secondary_clip->move(ca, timeline_in_movement, movement, timeline_in_movement, 0, false, true); - - make_room_for_transition(ca, g.transition->parent_clip, kTransitionOpening, g.in, g.out, false); - make_room_for_transition(ca, g.transition->secondary_clip, kTransitionClosing, g.in, g.out, false); - - } - - } else if (is_opening_transition) { - - if (g.in != g.old_in) { - // if transition is going to make the clip bigger, make the clip bigger - - // check if the transition is going to extend the out point - long timeline_out_movement = 0; - if (g.out > g.transition->parent_clip->timeline_out()) { - timeline_out_movement = g.out - g.transition->parent_clip->timeline_out(); - } - - c->move(ca, (g.in - g.old_in), timeline_out_movement, (g.clip_in - g.old_clip_in), 0, false, true); - clip_length -= (g.in - g.old_in); - } - - make_room_for_transition(ca, c, kTransitionOpening, g.in, g.out, false); - - } else { - - if (g.out != g.old_out) { - - // check if the transition is going to extend the in point - long timeline_in_movement = 0; - if (g.in < g.transition->parent_clip->timeline_in()) { - timeline_in_movement = g.in - g.transition->parent_clip->timeline_in(); - } - - // if transition is going to make the clip bigger, make the clip bigger - c->move(ca, timeline_in_movement, (g.out - g.old_out), timeline_in_movement, 0, false, true); - clip_length += (g.out - g.old_out); - } - - make_room_for_transition(ca, c, kTransitionClosing, g.in, g.out, false); - - } - } - } - - // time to verify the transitions of moved clips - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - - // only applies to moving clips, transitions are verified above instead - if (g.transition == nullptr) { - ClipPtr c = olive::ActiveSequence->clips.at(g.clip); - - long new_clip_length = g.out - g.in; - - // using a for loop between constants to repeat the same steps for the opening and closing transitions - for (int t=kTransitionOpening;t<=kTransitionClosing;t++) { - - TransitionPtr transition = (t == kTransitionOpening) ? c->opening_transition : c->closing_transition; - - // check the whether the clip has a transition here - if (transition != nullptr) { - - // if the new clip size exceeds the opening transition's length, resize the transition - if (new_clip_length < transition->get_true_length()) { - ca->append(new ModifyTransitionCommand(transition, new_clip_length)); - } - - // check if the transition is a shared transition (it'll never have a secondary clip if it isn't) - if (transition->secondary_clip != nullptr) { - - // check if the transition's "edge" is going to move - if ((t == kTransitionOpening && g.in != g.old_in) - || (t == kTransitionClosing && g.out != g.old_out)) { - - // if we're here, this clip shares its opening transition as the closing transition of another - // clip (or vice versa), and the in point is moving, so we may have to account for this - - // the other clip sharing this transition may be moving as well, meaning we don't have to do - // anything - - bool split = true; - - // loop through ghosts to find out - - // for a shared transition, the secondary_clip will always be the closing transition side and - // the parent_clip will always be the opening transition side - Clip* search_clip = (t == kTransitionOpening) - ? transition->secondary_clip : transition->parent_clip; - - for (int j=0;jghosts.size();j++) { - const Ghost& other_clip_ghost = panel_timeline->ghosts.at(j); - - if (olive::ActiveSequence->clips.at(other_clip_ghost.clip).get() == search_clip) { - - // we found the other clip in the current ghosts/selections - - // see if it's destination edge will be equal to this ghost's edge (in which case the - // transition doesn't need to change) - // - // also only do this if j is less than i, because it only needs to happen once and chances are - // the other clip already - - bool edges_still_touch; - if (t == kTransitionOpening) { - edges_still_touch = (other_clip_ghost.out == g.in); - } else { - edges_still_touch = (other_clip_ghost.in == g.out); - } - - if (edges_still_touch || j < i) { - split = false; - } - - break; - } - } - - if (split) { - // separate shared transition into one transition for each clip - - if (t == kTransitionOpening) { - - // set transition to single-clip mode - ca->append(new SetPointer(reinterpret_cast(&transition->secondary_clip), - nullptr)); - - // create duplicate transition for other clip - ca->append(new AddTransitionCommand(nullptr, - transition->secondary_clip, - transition, - nullptr, - 0)); - - } else { - - // set transition to single-clip mode - ca->append(new SetPointer(reinterpret_cast(&transition->secondary_clip), - nullptr)); - - // that transition will now attach to the other clip, so we duplicate it for this one - - // create duplicate transition for this clip - ca->append(new AddTransitionCommand(nullptr, - transition->secondary_clip, - transition, - nullptr, - 0)); - - } - } - - } - } - } - } - } - } - } - push_undo = true; - } - } else if (panel_timeline->selecting || panel_timeline->rect_select_proc) { - } else if (panel_timeline->transition_tool_proc) { - const Ghost& g = panel_timeline->ghosts.at(0); - - // if the transition is greater than 0 length (if it is 0, we make nothing) - if (g.in != g.out) { - - // get transition coordinates on the timeline - long transition_start = qMin(g.in, g.out); - long transition_end = qMax(g.in, g.out); - - // get clip references from tool's cached data - Clip* open = (panel_timeline->transition_tool_open_clip > -1) - ? olive::ActiveSequence->clips.at(panel_timeline->transition_tool_open_clip).get() - : nullptr; - - Clip* close = (panel_timeline->transition_tool_close_clip > -1) - ? olive::ActiveSequence->clips.at(panel_timeline->transition_tool_close_clip).get() - : nullptr; - - - - // if it's shared, the transition length is halved (one half for each clip will result in the full length) - long transition_length = transition_end - transition_start; - if (open != nullptr && close != nullptr) { - transition_length /= 2; - } - - VerifyTransitionsAfterCreating(ca, open, close, transition_start, transition_end); - - // finally, add the transition to these clips - ca->append(new AddTransitionCommand(open, - close, - nullptr, - panel_timeline->transition_tool_meta, - transition_length)); - - push_undo = true; - } - } else if (panel_timeline->splitting) { - bool split = false; - for (int i=0;isplit_tracks.size();i++) { - int split_index = getClipIndexFromCoords(panel_timeline->drag_frame_start, panel_timeline->split_tracks.at(i)); - if (split_index > -1 && panel_timeline->split_clip_and_relink(ca, split_index, panel_timeline->drag_frame_start, !alt)) { - split = true; - } - } - if (split) { - push_undo = true; - } - panel_timeline->split_cache.clear(); - } - - // remove duplicate selections - panel_timeline->clean_up_selections(olive::ActiveSequence->selections); - - if (selection_command != nullptr) { - selection_command->new_data = olive::ActiveSequence->selections; - ca->append(selection_command); - selection_command = nullptr; - push_undo = true; - } - - if (push_undo) { - olive::UndoStack.push(ca); - } else { - delete ca; - } - - // destroy all ghosts - panel_timeline->ghosts.clear(); - - // clear split tracks - panel_timeline->split_tracks.clear(); - - panel_timeline->selecting = false; - panel_timeline->moving_proc = false; - panel_timeline->moving_init = false; - panel_timeline->splitting = false; - panel_timeline->snapped = false; - panel_timeline->rect_select_init = false; - panel_timeline->rect_select_proc = false; - panel_timeline->transition_tool_init = false; - panel_timeline->transition_tool_proc = false; - pre_clips.clear(); - post_clips.clear(); - - update_ui(true); - } - panel_timeline->hand_moving = false; - } -} - -void TimelineWidget::init_ghosts() { - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - ClipPtr c = olive::ActiveSequence->clips.at(g.clip); - - g.track = g.old_track = c->track(); - g.clip_in = g.old_clip_in = c->clip_in(); - - if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { - g.clip_in = g.old_clip_in = c->clip_in(true); - g.in = g.old_in = c->timeline_in(true); - g.out = g.old_out = c->timeline_out(true); - g.ghost_length = g.old_out - g.old_in; - } else if (g.transition == nullptr) { - // this ghost is for a clip - g.in = g.old_in = c->timeline_in(); - g.out = g.old_out = c->timeline_out(); - g.ghost_length = g.old_out - g.old_in; - } else if (g.transition == c->opening_transition) { - g.in = g.old_in = c->timeline_in(true); - g.ghost_length = c->opening_transition->get_length(); - g.out = g.old_out = g.in + g.ghost_length; - } else if (g.transition == c->closing_transition) { - g.out = g.old_out = c->timeline_out(true); - g.ghost_length = c->closing_transition->get_length(); - g.in = g.old_in = g.out - g.ghost_length; - g.clip_in = g.old_clip_in = c->clip_in() + c->length() - c->closing_transition->get_true_length(); - } - - // used for trim ops - g.media_length = c->media_length(); - } - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; - s.old_in = s.in; - s.old_out = s.out; - s.old_track = s.track; - } -} - -void validate_transitions(Clip* c, int transition_type, long& frame_diff) { - long validator; - - if (transition_type == kTransitionOpening) { - // prevent from going below 0 on the timeline - validator = c->timeline_in() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent from going below 0 for the media - validator = c->clip_in() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent transition from exceeding media length - validator -= c->media_length(); - if (validator > 0) frame_diff -= validator; - } else { - // prevent from going below 0 on the timeline - validator = c->timeline_out() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent from going below 0 for the media - validator = c->clip_in() + c->length() + frame_diff; - if (validator < 0) frame_diff -= validator; - - // prevent transition from exceeding media length - validator -= c->media_length(); - if (validator > 0) frame_diff -= validator; - } -} - -void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { - int effective_tool = panel_timeline->tool; - if (panel_timeline->importing || panel_timeline->creating) effective_tool = TIMELINE_TOOL_POINTER; - - int mouse_track = getTrackFromScreenPoint(mouse_pos.y()); - long frame_diff = (lock_frame) ? 0 : panel_timeline->getTimelineFrameFromScreenPoint(mouse_pos.x()) - panel_timeline->drag_frame_start; - int track_diff = ((effective_tool == TIMELINE_TOOL_SLIDE || panel_timeline->transition_select != kTransitionNone) && !panel_timeline->importing) ? 0 : mouse_track - panel_timeline->drag_track_start; - long validator; - long earliest_in_point = LONG_MAX; - - // first try to snap - long fm; - - if (effective_tool != TIMELINE_TOOL_SLIP) { - // slipping doesn't move the clips so we don't bother snapping for it - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - - // snap ghost's in point - if ((panel_timeline->tool != TIMELINE_TOOL_TRANSITION && panel_timeline->trim_target == -1) - || g.trim_type == TRIM_IN - || panel_timeline->transition_tool_open_clip > -1) { - fm = g.old_in + frame_diff; - if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { - frame_diff = fm - g.old_in; - break; - } - } - - // snap ghost's out point - if ((panel_timeline->tool != TIMELINE_TOOL_TRANSITION && panel_timeline->trim_target == -1) - || g.trim_type == TRIM_OUT - || panel_timeline->transition_tool_close_clip > -1) { - fm = g.old_out + frame_diff; - if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { - frame_diff = fm - g.old_out; - break; - } - } - - // if the ghost is attached to a clip, snap its markers too - if (panel_timeline->trim_target == -1 && g.clip >= 0 && panel_timeline->tool != TIMELINE_TOOL_TRANSITION) { - ClipPtr c = olive::ActiveSequence->clips.at(g.clip); - for (int j=0;jget_markers().size();j++) { - long marker_real_time = c->get_markers().at(j).frame + c->timeline_in() - c->clip_in(); - fm = marker_real_time + frame_diff; - if (panel_timeline->snap_to_timeline(&fm, true, true, true)) { - frame_diff = fm - marker_real_time; - break; - } - } - } - } - } - - bool clips_are_movable = (effective_tool == TIMELINE_TOOL_POINTER || effective_tool == TIMELINE_TOOL_SLIDE); - - // validate ghosts - long temp_frame_diff = frame_diff; // cache to see if we change it (thus cancelling any snap) - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - Clip* c = nullptr; - if (g.clip != -1) { - c = olive::ActiveSequence->clips.at(g.clip).get(); - } - - const FootageStream* ms = nullptr; - if (g.clip != -1 && c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - ms = c->media_stream(); - } - - // validate ghosts for trimming - if (panel_timeline->creating) { - // i feel like we might need something here but we haven't so far? - } else if (effective_tool == TIMELINE_TOOL_SLIP) { - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - // prevent slip moving a clip below 0 clip_in - validator = g.old_clip_in - frame_diff; - if (validator < 0) frame_diff += validator; - - // prevent slip moving clip beyond media length - validator += g.ghost_length; - if (validator > g.media_length) frame_diff += validator - g.media_length; - } - } else if (g.trim_type != TRIM_NONE) { - if (g.trim_type == TRIM_IN) { - // prevent clip/transition length from being less than 1 frame long - validator = g.ghost_length - frame_diff; - if (validator < 1) frame_diff -= (1 - validator); - - // prevent timeline in from going below 0 - if (effective_tool != TIMELINE_TOOL_RIPPLE) { - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } - - // prevent clip_in from going below 0 - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } - } else { - // prevent clip length from being less than 1 frame long - validator = g.ghost_length + frame_diff; - if (validator < 1) frame_diff += (1 - validator); - - // prevent clip length exceeding media length - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + g.ghost_length + frame_diff; - if (validator > g.media_length) frame_diff -= validator - g.media_length; - } - } - - // prevent dual transition from going below 0 on the primary or media length on the secondary - if (g.transition != nullptr && g.transition->secondary_clip != nullptr) { - Clip* otc = g.transition->parent_clip; - Clip* ctc = g.transition->secondary_clip; - - if (g.trim_type == TRIM_IN) { - frame_diff -= g.transition->get_true_length(); - } else { - frame_diff += g.transition->get_true_length(); - } - - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - - frame_diff = -frame_diff; - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - frame_diff = -frame_diff; - - if (g.trim_type == TRIM_IN) { - frame_diff += g.transition->get_true_length(); - } else { - frame_diff -= g.transition->get_true_length(); - } - } - - // ripple ops - if (effective_tool == TIMELINE_TOOL_RIPPLE) { - for (int j=0;jtrim_type == TRIM_IN) { - validator = post->timeline_in() - frame_diff; - if (validator < 0) frame_diff += validator; - } - - // prevent any post-clips colliding with pre-clips - for (int k=0;ktrack() == post->track()) { - if (panel_timeline->trim_type == TRIM_IN) { - validator = post->timeline_in() - frame_diff - pre->timeline_out(); - if (validator < 0) frame_diff += validator; - } else { - validator = post->timeline_in() + frame_diff - pre->timeline_out(); - if (validator < 0) frame_diff -= validator; - } - } - } - } - } - } else if (clips_are_movable) { // validate ghosts for moving - // prevent clips from moving below 0 on the timeline - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; - - if (g.transition != nullptr) { - if (g.transition->secondary_clip != nullptr) { - // prevent dual transitions from going below 0 on the primary or above media length on the secondary - - validator = g.transition->parent_clip->clip_in(true) + frame_diff; - if (validator < 0) frame_diff -= validator; - - validator = g.transition->secondary_clip->timeline_out(true) - g.transition->secondary_clip->timeline_in(true) - g.transition->get_length() + g.transition->secondary_clip->clip_in(true) + frame_diff; - if (validator < 0) frame_diff -= validator; - - validator = g.transition->parent_clip->clip_in() + frame_diff - g.transition->parent_clip->media_length() + g.transition->get_true_length(); - if (validator > 0) frame_diff -= validator; - - validator = g.transition->secondary_clip->timeline_out(true) - g.transition->secondary_clip->timeline_in(true) + g.transition->secondary_clip->clip_in(true) + frame_diff - g.transition->secondary_clip->media_length(); - if (validator > 0) frame_diff -= validator; - } else { - // prevent clip_in from going below 0 - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } - - // prevent clip length exceeding media length - if ((c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) - || (ms != nullptr && !ms->infinite_length)) { - validator = g.old_clip_in + g.ghost_length + frame_diff; - if (validator > g.media_length) frame_diff -= validator - g.media_length; - } - } - } - - // prevent clips from crossing tracks - if (same_sign(g.old_track, panel_timeline->drag_track_start)) { - while (!same_sign(g.old_track, g.old_track + track_diff)) { - if (g.old_track < 0) { - track_diff--; - } else { - track_diff++; - } - } - } - } else if (effective_tool == TIMELINE_TOOL_TRANSITION) { - if (panel_timeline->transition_tool_open_clip == -1 - || panel_timeline->transition_tool_close_clip == -1) { - validate_transitions(c, g.media_stream, frame_diff); - } else { - // open transition clip - Clip* otc = olive::ActiveSequence->clips.at(panel_timeline->transition_tool_open_clip).get(); - - // close transition clip - Clip* ctc = olive::ActiveSequence->clips.at(panel_timeline->transition_tool_close_clip).get(); - - if (g.media_stream == kTransitionClosing) { - // swap - Clip* temp = otc; - otc = ctc; - ctc = temp; - } - - // always gets a positive frame_diff - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - - // always gets a negative frame_diff - frame_diff = -frame_diff; - validate_transitions(otc, kTransitionOpening, frame_diff); - validate_transitions(ctc, kTransitionClosing, frame_diff); - frame_diff = -frame_diff; - } - } - } - - // if the above validation changed the frame movement, it's unlikely we're still snapped - if (temp_frame_diff != frame_diff) { - panel_timeline->snapped = false; - } - - // apply changes to ghosts - for (int i=0;ighosts.size();i++) { - Ghost& g = panel_timeline->ghosts[i]; - - if (effective_tool == TIMELINE_TOOL_SLIP) { - g.clip_in = g.old_clip_in - frame_diff; - } else if (g.trim_type != TRIM_NONE) { - long ghost_diff = frame_diff; - - // prevent trimming clips from overlapping each other - for (int j=0;jghosts.size();j++) { - const Ghost& comp = panel_timeline->ghosts.at(j); - if (i != j && g.track == comp.track) { - long validator; - if (g.trim_type == TRIM_IN && comp.out < g.out) { - validator = (g.old_in + ghost_diff) - comp.out; - if (validator < 0) ghost_diff -= validator; - } else if (comp.in > g.in) { - validator = (g.old_out + ghost_diff) - comp.in; - if (validator > 0) ghost_diff -= validator; - } - } - } - - // apply changes - if (g.transition != nullptr && g.transition->secondary_clip != nullptr) { - if (g.trim_type == TRIM_IN) ghost_diff = -ghost_diff; - g.in = g.old_in - ghost_diff; - g.out = g.old_out + ghost_diff; - } else if (g.trim_type == TRIM_IN) { - g.in = g.old_in + ghost_diff; - g.clip_in = g.old_clip_in + ghost_diff; - } else { - g.out = g.old_out + ghost_diff; - } - } else if (clips_are_movable) { - g.track = g.old_track; - g.in = g.old_in + frame_diff; - g.out = g.old_out + frame_diff; - - if (g.transition != nullptr - && g.transition == olive::ActiveSequence->clips.at(g.clip)->opening_transition) { - g.clip_in = g.old_clip_in + frame_diff; - } - - if (panel_timeline->importing) { - if ((panel_timeline->video_ghosts && mouse_track < 0) - || (panel_timeline->audio_ghosts && mouse_track >= 0)) { - int abs_track_diff = abs(track_diff); - if (g.old_track < 0) { // clip is video - g.track -= abs_track_diff; - } else { // clip is audio - g.track += abs_track_diff; - } - } - } else if (same_sign(g.old_track, panel_timeline->drag_track_start)) { - g.track += track_diff; - } - } else if (effective_tool == TIMELINE_TOOL_TRANSITION) { - if (panel_timeline->transition_tool_open_clip > -1 - && panel_timeline->transition_tool_close_clip > -1) { - g.in = g.old_in - frame_diff; - g.out = g.old_out + frame_diff; - } else if (panel_timeline->transition_tool_open_clip == g.clip) { - g.out = g.old_out + frame_diff; - } else { - g.in = g.old_in + frame_diff; - } - } - - earliest_in_point = qMin(earliest_in_point, g.in); - } - - // apply changes to selections - if (effective_tool != TIMELINE_TOOL_SLIP && !panel_timeline->importing && !panel_timeline->creating) { - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; - if (panel_timeline->trim_target > -1) { - if (panel_timeline->trim_type == TRIM_IN) { - s.in = s.old_in + frame_diff; - } else { - s.out = s.old_out + frame_diff; - } - } else if (clips_are_movable) { - for (int i=0;iselections.size();i++) { - Selection& s = olive::ActiveSequence->selections[i]; - s.in = s.old_in + frame_diff; - s.out = s.old_out + frame_diff; - s.track = s.old_track; - - if (panel_timeline->importing) { - int abs_track_diff = abs(track_diff); - if (s.old_track < 0) { - s.track -= abs_track_diff; - } else { - s.track += abs_track_diff; - } - } else { - if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff; - } - } - } - } - } - - if (panel_timeline->importing) { - QToolTip::showText(mapToGlobal(mouse_pos), frame_to_timecode(earliest_in_point, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate)); - } else { - QString tip = ((frame_diff < 0) ? "-" : "+") + frame_to_timecode(qAbs(frame_diff), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate); - if (panel_timeline->trim_target > -1) { - // find which clip is being moved - const Ghost* g = nullptr; - for (int i=0;ighosts.size();i++) { - if (panel_timeline->ghosts.at(i).clip == panel_timeline->trim_target) { - g = &panel_timeline->ghosts.at(i); - break; - } - } - - if (g != nullptr) { - tip += " " + tr("Duration:") + " "; - long len = (g->old_out-g->old_in); - if (panel_timeline->trim_type == TRIM_IN) { - len -= frame_diff; - } else { - len += frame_diff; - } - tip += frame_to_timecode(len, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate); - } - } - QToolTip::showText(mapToGlobal(mouse_pos), tip); - } -} - -void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { - // interrupt any potential tooltip about to show - tooltip_timer.stop(); - - if (olive::ActiveSequence != nullptr) { - bool alt = (event->modifiers() & Qt::AltModifier); - - // store current frame/track corresponding to the cursor - panel_timeline->cursor_frame = panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x()); - panel_timeline->cursor_track = getTrackFromScreenPoint(event->pos().y()); - - // if holding the mouse button down, let's scroll to that location - if (event->buttons() != 0 && panel_timeline->tool != TIMELINE_TOOL_HAND) { - panel_timeline->scroll_to_frame(panel_timeline->cursor_frame); - } - - // determine if the action should be "inserting" rather than "overwriting" - // Default behavior is to replace/overwrite clips under any clips we're dropping over them. Inserting will - // split and move existing clips at the drop point to make space for the drop - panel_timeline->move_insert = ((event->modifiers() & Qt::ControlModifier) - && (panel_timeline->tool == TIMELINE_TOOL_POINTER - || panel_timeline->importing - || panel_timeline->creating)); - - // if we're not currently resizing already, default track resizing to false (we'll set it to true later if - // the user is still hovering over a track line) - if (!panel_timeline->moving_init) { - track_resizing = false; - } - - // if the current tool uses an on-screen visible cursor, we snap the cursor to the timeline - if (current_tool_shows_cursor()) { - panel_timeline->snap_to_timeline(&panel_timeline->cursor_frame, - - // only snap to the playhead if the edit tool doesn't force the playhead to - // follow it (or if we're not selecting since that means the playhead is - // static at the moment) - !olive::CurrentConfig.edit_tool_also_seeks || !panel_timeline->selecting, - - true, - true); - } - - if (panel_timeline->selecting) { - - // get number of selections based on tracks in selection area - int selection_tool_count = 1 + qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start) - qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); - - // add count to selection offset for the total number of selection objects - // (offset is usually 0, unless the user is holding shift in which case we add to existing selections) - int selection_count = selection_tool_count + panel_timeline->selection_offset; - - // resize selection object array to new count - if (olive::ActiveSequence->selections.size() != selection_count) { - olive::ActiveSequence->selections.resize(selection_count); - } - - // loop through tracks in selection area and adjust them accordingly - int minimum_selection_track = qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); - int maximum_selection_track = qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start); - long selection_in = qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - long selection_out = qMax(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - for (int i=panel_timeline->selection_offset;iselections[i]; - s.track = minimum_selection_track + i - panel_timeline->selection_offset; - s.in = selection_in; - s.out = selection_out; - } - - // If the config is set to select links as well with the edit tool - if (olive::CurrentConfig.edit_tool_selects_links) { - - // find which clips are selected - for (int j=0;jclips.size();j++) { - - Clip* c = olive::ActiveSequence->clips.at(j).get(); - - if (c != nullptr && c->IsSelected(false)) { - - // loop through linked clips - for (int k=0;klinked.size();k++) { - - ClipPtr link = olive::ActiveSequence->clips.at(c->linked.at(k)); - - // see if one of the selections is already covering this track - if (!(link->track() >= minimum_selection_track - && link->track() <= maximum_selection_track)) { - - // clip is not in selection area, time to select it - Selection link_sel; - link_sel.in = selection_in; - link_sel.out = selection_out; - link_sel.track = link->track(); - olive::ActiveSequence->selections.append(link_sel); - - } - - } - - } - } - } - - // if the config is set to seek with the edit too, do so now - if (olive::CurrentConfig.edit_tool_also_seeks) { - panel_sequence_viewer->seek(qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame)); - } else { - // if not, repaint (seeking will trigger a repaint) - panel_timeline->repaint_timeline(); - } - - } else if (panel_timeline->hand_moving) { - - // if we're hand moving, we'll be adding values directly to the scrollbars - - // the scrollbars trigger repaints when they scroll, which is unnecessary here so we block them - panel_timeline->block_repaints = true; - panel_timeline->horizontalScrollBar->setValue(panel_timeline->horizontalScrollBar->value() + panel_timeline->drag_x_start - event->pos().x()); - scrollBar->setValue(scrollBar->value() + panel_timeline->drag_y_start - event->pos().y()); - panel_timeline->block_repaints = false; - - // finally repaint - panel_timeline->repaint_timeline(); - - // store current cursor position for next hand move event - panel_timeline->drag_x_start = event->pos().x(); - panel_timeline->drag_y_start = event->pos().y(); - - } else if (panel_timeline->moving_init) { - - if (track_resizing) { - - // get cursor movement - int diff = (event->pos().y() - panel_timeline->drag_y_start); - - // add it to the current track height - int new_height = panel_timeline->GetTrackHeight(track_target); - if (bottom_align) { - new_height -= diff; - } else { - new_height += diff; - } - - // limit track height to track minimum height constant - new_height = qMax(new_height, olive::timeline::kTrackMinHeight); - - // set the track height - panel_timeline->SetTrackHeight(track_target, new_height); - - // store current cursor position for next track resize event - panel_timeline->drag_y_start = event->pos().y(); - - update(); - } else if (panel_timeline->moving_proc) { - - // we're currently dragging ghosts - update_ghosts(event->pos(), event->modifiers() & Qt::ShiftModifier); - - } else { - - // Prepare to start moving clips in some capacity. We create Ghost objects to store movement data before we - // actually apply it to the clips (in mouseReleaseEvent) - - // loop through clips for any currently selected - for (int i=0;iclips.size();i++) { - - Clip* c = olive::ActiveSequence->clips.at(i).get(); - - if (c != nullptr) { - Ghost g; - g.transition = nullptr; - - // check if whole clip is added - bool add = false; - - // check if a transition is selected (prioritize transition selection) - // (only the pointer tool supports moving transitions) - if (panel_timeline->tool == TIMELINE_TOOL_POINTER - && (c->opening_transition != nullptr || c->closing_transition != nullptr)) { - - // check if any selections contain a whole transition - for (int j=0;jselections.size();j++) { - - const Selection& s = olive::ActiveSequence->selections.at(j); - - if (s.track == c->track()) { - if (selection_contains_transition(s, c, kTransitionOpening)) { - - g.transition = c->opening_transition; - add = true; - break; - - } else if (selection_contains_transition(s, c, kTransitionClosing)) { - - g.transition = c->closing_transition; - add = true; - break; - - } - } - - } - - } - - // if a transition isn't selected, check if the whole clip is - if (!add) { - add = c->IsSelected(); - } - - if (add) { - - if (g.transition != nullptr) { - - // transition may be a dual transition, check if it's already been added elsewhere - for (int j=0;jghosts.size();j++) { - if (panel_timeline->ghosts.at(j).transition == g.transition) { - add = false; - break; - } - } - - } - - if (add) { - g.clip = i; - g.trim_type = panel_timeline->trim_type; - panel_timeline->ghosts.append(g); - } - - } - } - } - - if (panel_timeline->tool == TIMELINE_TOOL_SLIDE) { - - // for the slide tool, we add the surrounding clips as ghosts that are getting trimmed the opposite way - - // store original array size since we'll be adding to it - int ghost_arr_size = panel_timeline->ghosts.size(); - - // loop through clips for any that are "touching" the selected clips - for (int j=0;jclips.size();j++) { - - ClipPtr c = olive::ActiveSequence->clips.at(j); - if (c != nullptr) { - - for (int i=0;ighosts[i]; - g.trim_type = TRIM_NONE; // the selected clips will be moving, not trimming - - ClipPtr ghost_clip = olive::ActiveSequence->clips.at(g.clip); - - if (c->track() == ghost_clip->track()) { - - // see if this clip is currently selected, if so we won't add it as a "touching" clip - bool found = false; - for (int k=0;kghosts.at(k).clip == j) { - found = true; - break; - } - } - - if (!found) { // the clip is not currently selected - - // check if this clip is indeed touching - bool is_in = (c->timeline_in() == ghost_clip->timeline_out()); - if (is_in || c->timeline_out() == ghost_clip->timeline_in()) { - Ghost gh; - gh.transition = nullptr; - gh.clip = j; - gh.trim_type = is_in ? TRIM_IN : TRIM_OUT; - panel_timeline->ghosts.append(gh); - } - } - } - } - } - } - } - - // set up ghost defaults - init_ghosts(); - - // if the ripple tool is selected, prepare to ripple - if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) { - - long axis = LONG_MAX; - - // find the earliest point within the selected clips which is the point we'll ripple around - // also store the currently selected clips so we don't have to do it later - QVector ghost_clips; - ghost_clips.resize(panel_timeline->ghosts.size()); - - for (int i=0;ighosts.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(panel_timeline->ghosts.at(i).clip); - if (panel_timeline->trim_type == TRIM_IN) { - axis = qMin(axis, c->timeline_in()); - } else { - axis = qMin(axis, c->timeline_out()); - } - - // store clip reference - ghost_clips[i] = c; - } - - // loop through clips and cache which are earlier than the axis and which after after - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr && !ghost_clips.contains(c)) { - bool clip_is_post = (c->timeline_in() >= axis); - - // construct the list of pre and post clips - QVector& clip_list = (clip_is_post) ? post_clips : pre_clips; - - // check if there's already a clip in this list on this track, and if this clip is closer or not - bool found = false; - for (int j=0;jtrack() == c->track()) { - - // if the clip is closer, use this one instead of the current one in the list - if ((!clip_is_post && compare->timeline_out() < c->timeline_out()) - || (clip_is_post && compare->timeline_in() > c->timeline_in())) { - clip_list[j] = c; - } - - found = true; - break; - } - - } - - // if there is no clip on this track in the list, add it - if (!found) { - clip_list.append(c); - } - } - } - } - - // store selections - selection_command = new SetSelectionsCommand(olive::ActiveSequence.get()); - selection_command->old_data = olive::ActiveSequence->selections; - - // ready to start moving clips - panel_timeline->moving_proc = true; - } - - update_ui(false); - - } else if (panel_timeline->splitting) { - - // get the range of tracks currently dragged - int track_start = qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); - int track_end = qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start); - int track_size = 1 + track_end - track_start; - - // set tracks to be split - panel_timeline->split_tracks.resize(track_size); - for (int i=0;isplit_tracks[i] = track_start + i; - } - - // if alt isn't being held, also add the tracks of the clip's links - if (!alt) { - for (int i=0;idrag_frame_start, panel_timeline->split_tracks[i]); - - if (clip_index > -1) { - ClipPtr clip = olive::ActiveSequence->clips.at(clip_index); - for (int j=0;jlinked.size();j++) { - - ClipPtr link = olive::ActiveSequence->clips.at(clip->linked.at(j)); - - // if this clip isn't already in the list of tracks to split - if (link->track() < track_start || link->track() > track_end) { - panel_timeline->split_tracks.append(link->track()); - } - - } - } - } - } - - update_ui(false); - - } else if (panel_timeline->rect_select_init) { - - // set if the user started dragging at point where there was no clip - - if (panel_timeline->rect_select_proc) { - - // we're currently rectangle selecting - - // set the right/bottom coords to the current mouse position - // (left/top were set to the starting drag position earlier) - panel_timeline->rect_select_rect.setRight(event->pos().x()); - - if (bottom_align) { - panel_timeline->rect_select_rect.setBottom(event->pos().y() - height()); - } else { - panel_timeline->rect_select_rect.setBottom(event->pos().y()); - } - - long frame_min = qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - long frame_max = qMax(panel_timeline->drag_frame_start, panel_timeline->cursor_frame); - - int track_min = qMin(panel_timeline->drag_track_start, panel_timeline->cursor_track); - int track_max = qMax(panel_timeline->drag_track_start, panel_timeline->cursor_track); - - // determine which clips are in this rectangular selection - QVector selected_clips; - for (int i=0;iclips.size();i++) { - ClipPtr clip = olive::ActiveSequence->clips.at(i); - if (clip != nullptr && - clip->track() >= track_min && - clip->track() <= track_max && - !(clip->timeline_in() < frame_min && clip->timeline_out() < frame_min) && - !(clip->timeline_in() > frame_max && clip->timeline_out() > frame_max)) { - - // create a group of the clip (and its links if alt is not pressed) - QVector session_clips; - session_clips.append(clip); - - if (!alt) { - for (int j=0;jlinked.size();j++) { - session_clips.append(olive::ActiveSequence->clips.at(clip->linked.at(j))); - } - } - - // for each of these clips, see if clip has already been added - - // this can easily happen due to adding linked clips - for (int j=0;jselections.resize(selected_clips.size() + panel_timeline->selection_offset); - for (int i=0;iselections[i+panel_timeline->selection_offset]; - ClipPtr clip = selected_clips.at(i); - s.old_in = s.in = clip->timeline_in(); - s.old_out = s.out = clip->timeline_out(); - s.old_track = s.track = clip->track(); - } - - panel_timeline->repaint_timeline(); - } else { - - // set up rectangle selecting - panel_timeline->rect_select_rect.setX(event->pos().x()); - - if (bottom_align) { - // bottom aligned widgets start with 0 at the bottom and go down to a negative number - panel_timeline->rect_select_rect.setY(event->pos().y() - height()); - } else { - panel_timeline->rect_select_rect.setY(event->pos().y()); - } - - panel_timeline->rect_select_rect.setWidth(0); - panel_timeline->rect_select_rect.setHeight(0); - - panel_timeline->rect_select_proc = true; - - } - } else if (current_tool_shows_cursor()) { - - // we're not currently performing an action (click is not pressed), but redraw because we have an on-screen cursor - panel_timeline->repaint_timeline(); - - } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || - panel_timeline->tool == TIMELINE_TOOL_RIPPLE || - panel_timeline->tool == TIMELINE_TOOL_ROLLING) { - - // hide any tooltip that may be currently showing - QToolTip::hideText(); - - // cache cursor position - QPoint pos = event->pos(); - - // - // check to see if the cursor is on a clip edge - // - - // threshold around a trim point that the cursor can be within and still considered "trimming" - int lim = 5; - int mouse_frame_lower = pos.x() - lim; - int mouse_frame_upper = pos.x() + lim; - - // used to determine whether we the cursor found a trim point or not - bool found = false; - - // used to determine whether the cursor is within the rect of a clip - bool cursor_contains_clip = false; - - // used to determine how close the cursor is to a trim point - // (and more specifically, whether another point is closer or not) - int closeness = INT_MAX; - - // while we loop through the clips, we cache the maximum/minimum tracks in this sequence - int min_track = INT_MAX; - int max_track = INT_MIN; - - // we default to selecting no transition, but set this accordingly if the cursor is on a transition - panel_timeline->transition_select = kTransitionNone; - - // we also default to no trimming which may be changed later in this function - panel_timeline->trim_type = TRIM_NONE; - - // set currently trimming clip to -1 (aka null) - panel_timeline->trim_target = -1; - - // loop through current clips in the sequence - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr) { - - // cache track range - min_track = qMin(min_track, c->track()); - max_track = qMax(max_track, c->track()); - - // if this clip is on the same track the mouse is - if (c->track() == panel_timeline->cursor_track) { - - // if this cursor is inside the boundaries of this clip (hovering over the clip) - if (panel_timeline->cursor_frame >= c->timeline_in() && - panel_timeline->cursor_frame <= c->timeline_out()) { - - // acknowledge that we are hovering over a clip - cursor_contains_clip = true; - - // start a timer to show a tooltip about this clip - tooltip_timer.start(); - tooltip_clip = i; - - // check if the cursor is specifically hovering over one of the clip's transitions - if (c->opening_transition != nullptr - && panel_timeline->cursor_frame <= c->timeline_in() + c->opening_transition->get_true_length()) { - - panel_timeline->transition_select = kTransitionOpening; - - } else if (c->closing_transition != nullptr - && panel_timeline->cursor_frame >= c->timeline_out() - c->closing_transition->get_true_length()) { - - panel_timeline->transition_select = kTransitionClosing; - - } - } - - int visual_in_point = panel_timeline->getTimelineScreenPointFromFrame(c->timeline_in()); - int visual_out_point = panel_timeline->getTimelineScreenPointFromFrame(c->timeline_out()); - - // is the cursor hovering around the clip's IN point? - if (visual_in_point > mouse_frame_lower && visual_in_point < mouse_frame_upper) { - - // test how close this IN point is to the cursor - int nc = qAbs(visual_in_point + 1 - pos.x()); - - // and test whether it's closer than the last in/out point we found - if (nc < closeness) { - - // if so, this is the point we'll make active for now (unless we find a closer one later) - panel_timeline->trim_target = i; - panel_timeline->trim_type = TRIM_IN; - closeness = nc; - found = true; - - } - } - - // is the cursor hovering around the clip's OUT point? - if (visual_out_point > mouse_frame_lower && visual_out_point < mouse_frame_upper) { - - // test how close this OUT point is to the cursor - int nc = qAbs(visual_out_point - 1 - pos.x()); - - // and test whether it's closer than the last in/out point we found - if (nc < closeness) { - - // if so, this is the point we'll make active for now (unless we find a closer one later) - panel_timeline->trim_target = i; - panel_timeline->trim_type = TRIM_OUT; - closeness = nc; - found = true; - - } - } - - // the pointer can be used to resize/trim transitions, here we test if the - // cursor is within the trim point of one of the clip's transitions - if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - - // if the clip has an opening transition - if (c->opening_transition != nullptr) { - - // cache the timeline frame where the transition ends - int transition_point = panel_timeline->getTimelineScreenPointFromFrame(c->timeline_in() - + c->opening_transition->get_true_length()); - - // check if the cursor is hovering around it (within the threshold) - if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { - - // similar to above, test how close it is and if it's closer, make this active - int nc = qAbs(transition_point - 1 - pos.x()); - if (nc < closeness) { - panel_timeline->trim_target = i; - panel_timeline->trim_type = TRIM_OUT; - panel_timeline->transition_select = kTransitionOpening; - closeness = nc; - found = true; - } - } - } - - // if the clip has a closing transition - if (c->closing_transition != nullptr) { - - // cache the timeline frame where the transition starts - int transition_point = panel_timeline->getTimelineScreenPointFromFrame(c->timeline_out() - - c->closing_transition->get_true_length()); - - // check if the cursor is hovering around it (within the threshold) - if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { - - // similar to above, test how close it is and if it's closer, make this active - int nc = qAbs(transition_point + 1 - pos.x()); - if (nc < closeness) { - panel_timeline->trim_target = i; - panel_timeline->trim_type = TRIM_IN; - panel_timeline->transition_select = kTransitionClosing; - closeness = nc; - found = true; - } - } - } - } - } - } - } - - // if the cursor is indeed on a clip edge, we set the cursor accordingly - if (found) { - - if (panel_timeline->trim_type == TRIM_IN) { // if we're trimming an IN point - setCursor(panel_timeline->tool == TIMELINE_TOOL_RIPPLE ? olive::cursor::LeftRipple : olive::cursor::LeftTrim); - } else { // if we're trimming an OUT point - setCursor(panel_timeline->tool == TIMELINE_TOOL_RIPPLE ? olive::cursor::RightRipple : olive::cursor::RightTrim); - } - - } else { - // we didn't find a trim target, so we must be doing something else - // (e.g. dragging a clip or resizing the track heights) - - unsetCursor(); - - // check to see if we're resizing a track height - int test_range = 5; - int mouse_pos = event->pos().y(); - int hover_track = getTrackFromScreenPoint(mouse_pos); - int track_y_edge = getScreenPointFromTrack(hover_track); - - if (!bottom_align) { - track_y_edge += panel_timeline->GetTrackHeight(hover_track); - } - - if (mouse_pos > track_y_edge - test_range - && mouse_pos < track_y_edge + test_range) { - if (cursor_contains_clip - || (olive::CurrentConfig.show_track_lines - && panel_timeline->cursor_track >= min_track - && panel_timeline->cursor_track <= max_track)) { - track_resizing = true; - track_target = hover_track; - setCursor(Qt::SizeVerCursor); - } - } - } - } else if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { - - // we're not currently performing any slipping, all we do here is set the cursor if mouse is hovering over a - // cursor - if (getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track) > -1) { - setCursor(olive::cursor::Slip); - } else { - unsetCursor(); - } - - } else if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION) { - - if (panel_timeline->transition_tool_init) { - - // the transition tool has started - - if (panel_timeline->transition_tool_proc) { - - // ghosts have been set up, so just run update - update_ghosts(event->pos(), event->modifiers() & Qt::ShiftModifier); - - } else { - - // transition tool is being used but ghosts haven't been set up yet, set them up now - int primary_type = kTransitionOpening; - int primary = panel_timeline->transition_tool_open_clip; - if (primary == -1) { - primary_type = kTransitionClosing; - primary = panel_timeline->transition_tool_close_clip; - } - - ClipPtr c = olive::ActiveSequence->clips.at(primary); - - Ghost g; - - g.in = g.old_in = g.out = g.old_out = (primary_type == kTransitionOpening) ? - c->timeline_in() - : c->timeline_out(); - - g.track = c->track(); - g.clip = primary; - g.media_stream = primary_type; - g.trim_type = TRIM_NONE; - - panel_timeline->ghosts.append(g); - - panel_timeline->transition_tool_proc = true; - - } - - } else { - - // transition tool has been selected but is not yet active, so we show screen feedback to the user on - // possible transitions - - int mouse_clip = getClipIndexFromCoords(panel_timeline->cursor_frame, panel_timeline->cursor_track); - - // set default transition tool references to no clip - panel_timeline->transition_tool_open_clip = -1; - panel_timeline->transition_tool_close_clip = -1; - - if (mouse_clip > -1) { - - // cursor is hovering over a clip - - ClipPtr c = olive::ActiveSequence->clips.at(mouse_clip); - - // check if the clip and transition are both the same sign (meaning video/audio are the same) - if (same_sign(c->track(), panel_timeline->transition_tool_side)) { - - // the range within which the transition tool will assume the user wants to make a shared transition - // between two clips rather than just one transition on one clip - long between_range = getFrameFromScreenPoint(panel_timeline->zoom, TRANSITION_BETWEEN_RANGE) + 1; - - // set whether the transition is opening or closing based on whether the cursor is on the left half - // or right half of the clip - if (panel_timeline->cursor_frame > (c->timeline_in() + (c->length()/2))) { - panel_timeline->transition_tool_close_clip = mouse_clip; - - // if the cursor is within this range, set the post_clip to be the next clip touching - // - // getClipIndexFromCoords() will automatically set to -1 if there's no clip there which means the - // end result will be the same as not setting a clip here at all - if (panel_timeline->cursor_frame > c->timeline_out() - between_range) { - panel_timeline->transition_tool_open_clip = getClipIndexFromCoords(c->timeline_out()+1, c->track()); - } - } else { - panel_timeline->transition_tool_open_clip = mouse_clip; - - if (panel_timeline->cursor_frame < c->timeline_in() + between_range) { - panel_timeline->transition_tool_close_clip = getClipIndexFromCoords(c->timeline_in()-1, c->track()); - } - } - - } - } - } - - panel_timeline->repaint_timeline(); - } - } -} - -void TimelineWidget::leaveEvent(QEvent*) { - tooltip_timer.stop(); -} - -void draw_waveform(ClipPtr clip, const FootageStream* ms, long media_length, QPainter *p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom) { - // audio channels multiplied by the number of bytes in a 16-bit audio sample - int divider = ms->audio_channels*2; - - int channel_height = clip_rect.height()/ms->audio_channels; - - int last_waveform_index = -1; - - for (int i=waveform_start;iclip_in() + (double(i)/zoom))/media_length) * ms->audio_preview.size())/divider)*divider; - - if (clip->reversed()) { - waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2); - } - - if (last_waveform_index < 0) last_waveform_index = waveform_index; - - for (int j=0;jaudio_channels;j++) { - int mid = (olive::CurrentConfig.rectified_waveforms) ? clip_rect.top()+channel_height*(j+1) : clip_rect.top()+channel_height*j+(channel_height/2); - - int offset_range_start = last_waveform_index+(j*2); - int offset_range_end = waveform_index+(j*2); - int offset_range_min = qMin(offset_range_start, offset_range_end); - int offset_range_max = qMax(offset_range_start, offset_range_end); - - qint8 min = qint8(qRound(double(ms->audio_preview.at(offset_range_min)) / 128.0 * (channel_height/2))); - qint8 max = qint8(qRound(double(ms->audio_preview.at(offset_range_min+1)) / 128.0 * (channel_height/2))); - - if ((offset_range_max + 1) < ms->audio_preview.size()) { - - // for waveform drawings, we get the maximum below 0 and maximum above 0 for this waveform range - for (int k=offset_range_min+2;k<=offset_range_max;k+=2) { - min = qMin(min, qint8(qRound(double(ms->audio_preview.at(k)) / 128.0 * (channel_height/2)))); - max = qMax(max, qint8(qRound(double(ms->audio_preview.at(k+1)) / 128.0 * (channel_height/2)))); - } - - // draw waveforms - if (olive::CurrentConfig.rectified_waveforms) { - - // rectified waveforms start from the bottom and draw upwards - p->drawLine(clip_rect.left()+i, mid, clip_rect.left()+i, mid - (max - min)); - } else { - - // non-rectified waveforms start from the center and draw outwards - p->drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); - - } - } - } - last_waveform_index = waveform_index; - } -} - -void draw_transition(QPainter& p, ClipPtr c, const QRect& clip_rect, QRect& text_rect, int transition_type) { - TransitionPtr t = (transition_type == kTransitionOpening) ? c->opening_transition : c->closing_transition; - if (t != nullptr) { - QColor transition_color(255, 0, 0, 16); - int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->get_true_length()); - int transition_height = clip_rect.height(); - int tr_y = clip_rect.y(); - int tr_x = 0; - if (transition_type == kTransitionOpening) { - tr_x = clip_rect.x(); - text_rect.setX(text_rect.x()+transition_width); - } else { - tr_x = clip_rect.right()-transition_width; - text_rect.setWidth(text_rect.width()-transition_width); - } - QRect transition_rect = QRect(tr_x, tr_y, transition_width, transition_height); - p.fillRect(transition_rect, transition_color); - QRect transition_text_rect(transition_rect.x() + olive::timeline::kClipTextPadding, transition_rect.y() + olive::timeline::kClipTextPadding, transition_rect.width() - olive::timeline::kClipTextPadding, transition_rect.height() - olive::timeline::kClipTextPadding); - if (transition_text_rect.width() > MAX_TEXT_WIDTH) { - bool draw_text = true; - - p.setPen(QColor(0, 0, 0, 96)); - if (t->secondary_clip == nullptr) { - if (transition_type == kTransitionOpening) { - p.drawLine(transition_rect.bottomLeft(), transition_rect.topRight()); - } else { - p.drawLine(transition_rect.topLeft(), transition_rect.bottomRight()); - } - } else { - if (transition_type == kTransitionOpening) { - p.drawLine(QPoint(transition_rect.left(), transition_rect.center().y()), transition_rect.topRight()); - p.drawLine(QPoint(transition_rect.left(), transition_rect.center().y()), transition_rect.bottomRight()); - draw_text = false; - } else { - p.drawLine(QPoint(transition_rect.right(), transition_rect.center().y()), transition_rect.topLeft()); - p.drawLine(QPoint(transition_rect.right(), transition_rect.center().y()), transition_rect.bottomLeft()); - } - } - - if (draw_text) { - p.setPen(Qt::white); - p.drawText(transition_text_rect, 0, t->meta->name, &transition_text_rect); - } - } - p.setPen(Qt::black); - p.drawRect(transition_rect); - } - -} - -void TimelineWidget::paintEvent(QPaintEvent*) { - // Draw clips - if (olive::ActiveSequence != nullptr) { - QPainter p(this); - - // get widget width and height - int video_track_limit = 0; - int audio_track_limit = 0; - for (int i=0;iclips.size();i++) { - ClipPtr clip = olive::ActiveSequence->clips.at(i); - if (clip != nullptr) { - video_track_limit = qMin(video_track_limit, clip->track()); - audio_track_limit = qMax(audio_track_limit, clip->track()); - } - } - - // start by adding a track height worth of padding - int panel_height = olive::timeline::kTrackDefaultHeight; - - // loop through tracks for maximum panel height - if (bottom_align) { - for (int i=-1;i>=video_track_limit;i--) { - panel_height += panel_timeline->GetTrackHeight(i); - } - } else { - for (int i=0;i<=audio_track_limit;i++) { - panel_height += panel_timeline->GetTrackHeight(i); - } - } - if (bottom_align) { - scrollBar->setMinimum(qMin(0, - panel_height + height())); - } else { - scrollBar->setMaximum(qMax(0, panel_height - height())); - } - - for (int i=0;iclips.size();i++) { - ClipPtr clip = olive::ActiveSequence->clips.at(i); - if (clip != nullptr && is_track_visible(clip->track())) { - QRect clip_rect(panel_timeline->getTimelineScreenPointFromFrame(clip->timeline_in()), getScreenPointFromTrack(clip->track()), getScreenPointFromFrame(panel_timeline->zoom, clip->length()), panel_timeline->GetTrackHeight(clip->track())); - QRect text_rect(clip_rect.left() + olive::timeline::kClipTextPadding, clip_rect.top() + olive::timeline::kClipTextPadding, clip_rect.width() - olive::timeline::kClipTextPadding - 1, clip_rect.height() - olive::timeline::kClipTextPadding - 1); - if (clip_rect.left() < width() && clip_rect.right() >= 0 && clip_rect.top() < height() && clip_rect.bottom() >= 0) { - QRect actual_clip_rect = clip_rect; - if (actual_clip_rect.x() < 0) actual_clip_rect.setX(0); - if (actual_clip_rect.right() > width()) actual_clip_rect.setRight(width()); - if (actual_clip_rect.y() < 0) actual_clip_rect.setY(0); - if (actual_clip_rect.bottom() > height()) actual_clip_rect.setBottom(height()); - p.fillRect(actual_clip_rect, (clip->enabled()) ? clip->color() : QColor(96, 96, 96)); - - int thumb_x = clip_rect.x() + 1; - - if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - bool draw_checkerboard = false; - QRect checkerboard_rect(clip_rect); - FootageStream* ms = clip->media_stream(); - if (ms == nullptr) { - draw_checkerboard = true; - } else if (ms->preview_done) { - // draw top and tail triangles - int triangle_size = olive::timeline::kTrackMinHeight >> 2; - if (!ms->infinite_length && clip_rect.width() > triangle_size) { - p.setPen(Qt::NoPen); - p.setBrush(QColor(80, 80, 80)); - if (clip->clip_in() == 0 - && clip_rect.x() + triangle_size > 0 - && clip_rect.y() + triangle_size > 0 - && clip_rect.x() < width() - && clip_rect.y() < height()) { - const QPoint points[3] = { - QPoint(clip_rect.x(), clip_rect.y()), - QPoint(clip_rect.x() + triangle_size, clip_rect.y()), - QPoint(clip_rect.x(), clip_rect.y() + triangle_size) - }; - p.drawPolygon(points, 3); - text_rect.setLeft(text_rect.left() + (triangle_size >> 2)); - } - if (clip->timeline_out() - clip->timeline_in() + clip->clip_in() == clip->media_length() - && clip_rect.right() - triangle_size < width() - && clip_rect.y() + triangle_size > 0 - && clip_rect.right() > 0 - && clip_rect.y() < height()) { - const QPoint points[3] = { - QPoint(clip_rect.right(), clip_rect.y()), - QPoint(clip_rect.right() - triangle_size, clip_rect.y()), - QPoint(clip_rect.right(), clip_rect.y() + triangle_size) - }; - p.drawPolygon(points, 3); - text_rect.setRight(text_rect.right() - (triangle_size >> 2)); - } - } - - p.setBrush(Qt::NoBrush); - - // draw thumbnail/waveform - long media_length = clip->media_length(); - - if (clip->track() < 0) { - // draw thumbnail - int thumb_y = p.fontMetrics().height()+olive::timeline::kClipTextPadding+olive::timeline::kClipTextPadding; - if (thumb_x < width() && thumb_y < height()) { - int space_for_thumb = clip_rect.width()-1; - if (clip->opening_transition != nullptr) { - int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->opening_transition->get_true_length()); - thumb_x += ot_width; - space_for_thumb -= ot_width; - } - if (clip->closing_transition != nullptr) { - space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->closing_transition->get_true_length()); - } - int thumb_height = clip_rect.height()-thumb_y; - int thumb_width = qRound(thumb_height*(double(ms->video_preview.width())/double(ms->video_preview.height()))); - if (thumb_x + thumb_width >= 0 - && thumb_height > thumb_y - && thumb_y + thumb_height >= 0 - && space_for_thumb > MAX_TEXT_WIDTH) { - int thumb_clip_width = qMin(thumb_width, space_for_thumb); - p.drawImage(QRect(thumb_x, - clip_rect.y()+thumb_y, - thumb_clip_width, - thumb_height), - ms->video_preview, - QRect(0, - 0, - qRound(thumb_clip_width*(double(ms->video_preview.width())/double(thumb_width))), - ms->video_preview.height() - ) - ); - } - } - if (clip->timeline_out() - clip->timeline_in() + clip->clip_in() > clip->media_length()) { - draw_checkerboard = true; - checkerboard_rect.setLeft(panel_timeline->getTimelineScreenPointFromFrame(clip->media_length() + clip->timeline_in() - clip->clip_in())); - } - } else if (clip_rect.height() > olive::timeline::kTrackMinHeight) { - // draw waveform - p.setPen(QColor(80, 80, 80)); - - int waveform_start = -qMin(clip_rect.x(), 0); - int waveform_limit = qMin(clip_rect.width(), getScreenPointFromFrame(panel_timeline->zoom, media_length - clip->clip_in())); - - if ((clip_rect.x() + waveform_limit) > width()) { - waveform_limit -= (clip_rect.x() + waveform_limit - width()); - } else if (waveform_limit < clip_rect.width()) { - draw_checkerboard = true; - if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); - } - - draw_waveform(clip, ms, media_length, &p, clip_rect, waveform_start, waveform_limit, panel_timeline->zoom); - } - } - if (draw_checkerboard) { - checkerboard_rect.setLeft(qMax(checkerboard_rect.left(), 0)); - checkerboard_rect.setRight(qMin(checkerboard_rect.right(), width())); - checkerboard_rect.setTop(qMax(checkerboard_rect.top(), 0)); - checkerboard_rect.setBottom(qMin(checkerboard_rect.bottom(), height())); - - if (checkerboard_rect.left() < width() - && checkerboard_rect.right() >= 0 - && checkerboard_rect.top() < height() - && checkerboard_rect.bottom() >= 0) { - // draw "error lines" if media stream is missing - p.setPen(QPen(QColor(64, 64, 64), 2)); - int limit = checkerboard_rect.width(); - int clip_height = checkerboard_rect.height(); - for (int j=-clip_height;j checkerboard_rect.right()) { - lines_end_y -= (checkerboard_rect.right() - lines_end_x); - lines_end_x = checkerboard_rect.right(); - } - p.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y); - } - } - } - } - - // draw clip markers - for (int j=0;jget_markers().size();j++) { - const Marker& m = clip->get_markers().at(j); - - // convert marker time (in clip time) to sequence time - long marker_time = m.frame + clip->timeline_in() - clip->clip_in(); - int marker_x = panel_timeline->getTimelineScreenPointFromFrame(marker_time); - if (marker_x > clip_rect.x() && marker_x < clip_rect.right()) { - draw_marker(p, marker_x, clip_rect.bottom()-p.fontMetrics().height(), clip_rect.bottom(), false); - } - } - p.setBrush(Qt::NoBrush); - - // draw clip transitions - draw_transition(p, clip, clip_rect, text_rect, kTransitionOpening); - draw_transition(p, clip, clip_rect, text_rect, kTransitionClosing); - - // top left bevel - p.setPen(Qt::white); - if (clip_rect.x() >= 0 && clip_rect.x() < width()) p.drawLine(clip_rect.bottomLeft(), clip_rect.topLeft()); - if (clip_rect.y() >= 0 && clip_rect.y() < height()) p.drawLine(QPoint(qMax(0, clip_rect.left()), clip_rect.top()), QPoint(qMin(width(), clip_rect.right()), clip_rect.top())); - - // draw text - if (text_rect.width() > MAX_TEXT_WIDTH && text_rect.right() > 0 && text_rect.left() < width()) { - if (!clip->enabled()) { - p.setPen(Qt::gray); - } else if (clip->color().lightness() > 160) { - // set to black if color is bright - p.setPen(Qt::black); - } - if (clip->linked.size() > 0) { - int underline_y = olive::timeline::kClipTextPadding + p.fontMetrics().height() + clip_rect.top(); - int underline_width = qMin(text_rect.width() - 1, p.fontMetrics().width(clip->name())); - p.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); - } - QString name = clip->name(); - if (clip->speed().value != 1.0 || clip->reversed()) { - name += " ("; - if (clip->reversed()) name += "-"; - name += QString::number(clip->speed().value*100) + "%)"; - } - p.drawText(text_rect, 0, name, &text_rect); - } - - // bottom right gray - p.setPen(QColor(0, 0, 0, 128)); - if (clip_rect.right() >= 0 && clip_rect.right() < width()) p.drawLine(clip_rect.bottomRight(), clip_rect.topRight()); - if (clip_rect.bottom() >= 0 && clip_rect.bottom() < height()) p.drawLine(QPoint(qMax(0, clip_rect.left()), clip_rect.bottom()), QPoint(qMin(width(), clip_rect.right()), clip_rect.bottom())); - - // draw transition tool - if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION) { - - bool shared_transition = (panel_timeline->transition_tool_open_clip > -1 - && panel_timeline->transition_tool_close_clip > -1); - - QRect transition_tool_rect = clip_rect; - bool draw_transition_tool_rect = false; - - if (panel_timeline->transition_tool_open_clip == i) { - if (shared_transition) { - transition_tool_rect.setWidth(TRANSITION_BETWEEN_RANGE); - } else { - transition_tool_rect.setWidth(transition_tool_rect.width()>>2); - } - draw_transition_tool_rect = true; - } else if (panel_timeline->transition_tool_close_clip == i) { - if (shared_transition) { - transition_tool_rect.setLeft(transition_tool_rect.right() - TRANSITION_BETWEEN_RANGE); - } else { - transition_tool_rect.setLeft(transition_tool_rect.left() + (3*(transition_tool_rect.width()>>2))); - } - draw_transition_tool_rect = true; - } - - if (draw_transition_tool_rect - && transition_tool_rect.left() < width() - && transition_tool_rect.right() > 0) { - if (transition_tool_rect.left() < 0) { - transition_tool_rect.setLeft(0); - } - if (transition_tool_rect.right() > width()) { - transition_tool_rect.setRight(width()); - } - p.fillRect(transition_tool_rect, QColor(0, 0, 0, 128)); - } - } - } - } - } - - // Draw recording clip if recording if valid - if (panel_sequence_viewer->is_recording_cued() && is_track_visible(panel_sequence_viewer->recording_track)) { - int rec_track_x = panel_timeline->getTimelineScreenPointFromFrame(panel_sequence_viewer->recording_start); - int rec_track_y = getScreenPointFromTrack(panel_sequence_viewer->recording_track); - int rec_track_height = panel_timeline->GetTrackHeight(panel_sequence_viewer->recording_track); - if (panel_sequence_viewer->recording_start != panel_sequence_viewer->recording_end) { - QRect rec_rect( - rec_track_x, - rec_track_y, - getScreenPointFromFrame(panel_timeline->zoom, panel_sequence_viewer->recording_end - panel_sequence_viewer->recording_start), - rec_track_height - ); - p.setPen(QPen(QColor(96, 96, 96), 2)); - p.fillRect(rec_rect, QColor(192, 192, 192)); - p.drawRect(rec_rect); - } - QRect active_rec_rect( - rec_track_x, - rec_track_y, - getScreenPointFromFrame(panel_timeline->zoom, panel_sequence_viewer->seq->playhead - panel_sequence_viewer->recording_start), - rec_track_height - ); - p.setPen(QPen(QColor(192, 0, 0), 2)); - p.fillRect(active_rec_rect, QColor(255, 96, 96)); - p.drawRect(active_rec_rect); - - p.setPen(Qt::NoPen); - - if (!panel_sequence_viewer->playing) { - int rec_marker_size = 6; - int rec_track_midY = rec_track_y + (rec_track_height >> 1); - p.setBrush(Qt::white); - QPoint cue_marker[3] = { - QPoint(rec_track_x, rec_track_midY - rec_marker_size), - QPoint(rec_track_x + rec_marker_size, rec_track_midY), - QPoint(rec_track_x, rec_track_midY + rec_marker_size) - }; - p.drawPolygon(cue_marker, 3); - } - } - - // Draw track lines - if (olive::CurrentConfig.show_track_lines) { - p.setPen(QColor(0, 0, 0, 96)); - audio_track_limit++; - if (video_track_limit == 0) video_track_limit--; - - if (bottom_align) { - // only draw lines for video tracks - for (int i=video_track_limit;i<0;i++) { - int line_y = getScreenPointFromTrack(i) - 1; - p.drawLine(0, line_y, rect().width(), line_y); - } - } else { - // only draw lines for audio tracks - for (int i=0;iGetTrackHeight(i); - p.drawLine(0, line_y, rect().width(), line_y); - } - } - } - - // Draw selections - for (int i=0;iselections.size();i++) { - const Selection& s = olive::ActiveSequence->selections.at(i); - if (is_track_visible(s.track)) { - int selection_y = getScreenPointFromTrack(s.track); - int selection_x = panel_timeline->getTimelineScreenPointFromFrame(s.in); - p.setPen(Qt::NoPen); - p.setBrush(Qt::NoBrush); - p.fillRect(selection_x, selection_y, panel_timeline->getTimelineScreenPointFromFrame(s.out) - selection_x, panel_timeline->GetTrackHeight(s.track), QColor(0, 0, 0, 64)); - } - } - - // draw rectangle select - if (panel_timeline->rect_select_proc) { - QRect rect_select = panel_timeline->rect_select_rect; - - if (bottom_align) { - rect_select.translate(0, height()); - } - - draw_selection_rectangle(p, rect_select); - } - - // Draw ghosts - if (!panel_timeline->ghosts.isEmpty()) { - QVector insert_points; - long first_ghost = LONG_MAX; - for (int i=0;ighosts.size();i++) { - const Ghost& g = panel_timeline->ghosts.at(i); - first_ghost = qMin(first_ghost, g.in); - if (is_track_visible(g.track)) { - int ghost_x = panel_timeline->getTimelineScreenPointFromFrame(g.in); - int ghost_y = getScreenPointFromTrack(g.track); - int ghost_width = panel_timeline->getTimelineScreenPointFromFrame(g.out) - ghost_x - 1; - int ghost_height = panel_timeline->GetTrackHeight(g.track) - 1; - - insert_points.append(ghost_y + (ghost_height>>1)); - - p.setPen(QColor(255, 255, 0)); - for (int j=0;jmove_insert && !insert_points.isEmpty()) { - p.setBrush(Qt::white); - p.setPen(Qt::NoPen); - int insert_x = panel_timeline->getTimelineScreenPointFromFrame(first_ghost); - int tri_size = olive::timeline::kTrackMinHeight>>2; - - for (int i=0;isplitting) { - for (int i=0;isplit_tracks.size();i++) { - if (is_track_visible(panel_timeline->split_tracks.at(i))) { - int cursor_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->drag_frame_start); - int cursor_y = getScreenPointFromTrack(panel_timeline->split_tracks.at(i)); - - p.setPen(QColor(64, 64, 64)); - p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + panel_timeline->GetTrackHeight(panel_timeline->split_tracks.at(i))); - } - } - } - - // Draw playhead - p.setPen(Qt::red); - int playhead_x = panel_timeline->getTimelineScreenPointFromFrame(olive::ActiveSequence->playhead); - p.drawLine(playhead_x, rect().top(), playhead_x, rect().bottom()); - - // Draw single frame highlight - int playhead_frame_width = panel_timeline->getTimelineScreenPointFromFrame(olive::ActiveSequence->playhead+1) - playhead_x; - if (playhead_frame_width > 5){ //hardcoded for now, maybe better way to do this? - QRectF singleFrameRect(playhead_x, rect().top(), playhead_frame_width, rect().bottom()); - p.fillRect(singleFrameRect, QColor(255,255,255,15)); - } - - // draw border - p.setPen(QColor(0, 0, 0, 64)); - int edge_y = (bottom_align) ? rect().height()-1 : 0; - p.drawLine(0, edge_y, rect().width(), edge_y); - - // draw snap point - if (panel_timeline->snapped) { - p.setPen(Qt::white); - int snap_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->snap_point); - p.drawLine(snap_x, 0, snap_x, height()); - } - - // Draw edit cursor - if (current_tool_shows_cursor() && is_track_visible(panel_timeline->cursor_track)) { - int cursor_x = panel_timeline->getTimelineScreenPointFromFrame(panel_timeline->cursor_frame); - int cursor_y = getScreenPointFromTrack(panel_timeline->cursor_track); - - p.setPen(Qt::gray); - p.drawLine(cursor_x, cursor_y, cursor_x, cursor_y + panel_timeline->GetTrackHeight(panel_timeline->cursor_track)); - } - } -} - -void TimelineWidget::resizeEvent(QResizeEvent *) { - scrollBar->setPageStep(height()); -} - -bool TimelineWidget::is_track_visible(int track) { - return (bottom_align == (track < 0)); -} - -// ************************************** -// screen point <-> frame/track functions -// ************************************** - -int TimelineWidget::getTrackFromScreenPoint(int y) { - int track_candidate = 0; - - y += scroll; - - if (bottom_align) { - y -= height(); - } - - if (y < 0) { - track_candidate--; - } - - int compounded_heights = 0; - - while (true) { - int track_height = panel_timeline->GetTrackHeight(track_candidate); - if (olive::CurrentConfig.show_track_lines) track_height++; - if (y < 0) { - track_height = -track_height; - } - - int next_compounded_height = compounded_heights + track_height; - - - if (y >= qMin(next_compounded_height, compounded_heights) && y < qMax(next_compounded_height, compounded_heights)) { - return track_candidate; - } - - compounded_heights = next_compounded_height; - - if (y < 0) { - track_candidate--; - } else { - track_candidate++; - } - } -} - -int TimelineWidget::getScreenPointFromTrack(int track) { - int point = 0; - - int start = (track < 0) ? -1 : 0; - int interval = (track < 0) ? -1 : 1; - - if (track < 0) track--; - - for (int i=start;i!=track;i+=interval) { - point += panel_timeline->GetTrackHeight(i); - if (olive::CurrentConfig.show_track_lines) point++; - } - - if (bottom_align) { - return height() - point - scroll; - } else { - return point - scroll; - } -} - -int TimelineWidget::getClipIndexFromCoords(long frame, int track) { - for (int i=0;iclips.size();i++) { - ClipPtr c = olive::ActiveSequence->clips.at(i); - if (c != nullptr && c->track() == track && frame >= c->timeline_in() && frame < c->timeline_out()) { - return i; - } - } - return -1; -} - -void TimelineWidget::setScroll(int s) { - scroll = s; - update(); -} - -void TimelineWidget::reveal_media() { - panel_project->reveal_media(rc_reveal_media); -} diff --git a/ui/updatenotification.cpp b/ui/updatenotification.cpp deleted file mode 100644 index e26ecfec6..000000000 --- a/ui/updatenotification.cpp +++ /dev/null @@ -1,58 +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 "updatenotification.h" - -#include -#include - -#include "mainwindow.h" - -UpdateNotification olive::update_notifier; - -UpdateNotification::UpdateNotification() -{ - -} - -void UpdateNotification::check() -{ -#if defined(GITHASH) && defined(UPDATEMSG) - QNetworkAccessManager* manager = new QNetworkAccessManager(); - - connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(finished_slot(QNetworkReply *))); - connect(manager, SIGNAL(finished(QNetworkReply *)), manager, SLOT(deleteLater())); - - QString update_url = QString("http://olivevideoeditor.org/update.php?version=0&hash=%1"); - - QNetworkRequest request(QUrl(update_url.arg(GITHASH))); - manager->get(request); -#endif -} - -void UpdateNotification::finished_slot(QNetworkReply *reply) -{ - QString response = QString::fromUtf8(reply->readAll()); - - if (response == "1") { - olive::MainWindow->statusBar()->showMessage(tr("An update is available from the Olive website. " - "Visit www.olivevideoeditor.org to download it.")); - } -} diff --git a/ui/updatenotification.h b/ui/updatenotification.h deleted file mode 100644 index 0fbc06282..000000000 --- a/ui/updatenotification.h +++ /dev/null @@ -1,39 +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 UPDATENOTIFICATION_H -#define UPDATENOTIFICATION_H - -#include - -class UpdateNotification : public QObject { - Q_OBJECT -public: - UpdateNotification(); - void check(); -private slots: - void finished_slot(QNetworkReply*); -}; - -namespace olive { - extern UpdateNotification update_notifier; -} - -#endif // UPDATENOTIFICATION_H diff --git a/ui/viewercontainer.cpp b/ui/viewercontainer.cpp deleted file mode 100644 index 0c2b689fd..000000000 --- a/ui/viewercontainer.cpp +++ /dev/null @@ -1,174 +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 "viewercontainer.h" - -#include -#include -#include -#include -#include - -#include "viewerwidget.h" -#include "panels/viewer.h" -#include "timeline/sequence.h" -#include "global/debug.h" - -// enforces aspect ratio -ViewerContainer::ViewerContainer(QWidget *parent) : - QWidget(parent), - fit(true), - child(nullptr) -{ - horizontal_scrollbar = new QScrollBar(Qt::Horizontal, this); - vertical_scrollbar = new QScrollBar(Qt::Vertical, this); - - horizontal_scrollbar->setVisible(false); - vertical_scrollbar->setVisible(false); - - horizontal_scrollbar->setSingleStep(20); - vertical_scrollbar->setSingleStep(20); - - child = new ViewerWidget(this); - child->container = this; - - connect(horizontal_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed())); - connect(vertical_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed())); -} - -ViewerContainer::~ViewerContainer() {} - -void ViewerContainer::dragScrollPress(const QPoint &p) { - drag_start_x = p.x(); - drag_start_y = p.y(); - - horiz_start = horizontal_scrollbar->value(); - vert_start = vertical_scrollbar->value(); -} - -void ViewerContainer::dragScrollMove(const QPoint &p) { - int this_x = p.x(); - int this_y = p.y(); - - horizontal_scrollbar->setValue(horiz_start + (drag_start_x-this_x)); - vertical_scrollbar->setValue(vert_start + (drag_start_y-this_y)); -} - -void ViewerContainer::parseWheelEvent(QWheelEvent *event) { - if (event->modifiers() & Qt::AltModifier) { - QApplication::sendEvent(horizontal_scrollbar, event); - } else { - QApplication::sendEvent(vertical_scrollbar, event); - } -} - -void ViewerContainer::adjust() { - if (viewer->seq != nullptr) { - if (child->waveform) { - child->move(0, 0); - child->resize(size()); - } else { - horizontal_scrollbar->setVisible(false); - vertical_scrollbar->setVisible(false); - - int zoomed_width = qRound(double(viewer->seq->width())*zoom); - int zoomed_height = qRound(double(viewer->seq->height())*zoom); - - if (fit || zoomed_width > width() || zoomed_height > height()) { - // if the zoom size is greater than or equal to the available area, only use the available area - - double aspect_ratio = double(viewer->seq->width())/double(viewer->seq->height()); - - int widget_x = 0; - int widget_y = 0; - int widget_width = width(); - int widget_height = height(); - - if (!fit) { - widget_width -= vertical_scrollbar->sizeHint().width(); - widget_height -= horizontal_scrollbar->sizeHint().height(); - } - - double widget_ar = double(widget_width) / double(widget_height); - - bool widget_is_wider_than_sequence = widget_ar > aspect_ratio; - - if (widget_is_wider_than_sequence) { - widget_width = widget_height * aspect_ratio; - widget_x = (width() / 2) - (widget_width / 2); - } else { - widget_height = widget_width / aspect_ratio; - widget_y = (height() / 2) - (widget_height / 2); - } - - child->move(widget_x, widget_y); - child->resize(widget_width, widget_height); - - if (fit) { - zoom = double(widget_width) / double(viewer->seq->width()); - } else if (zoomed_width > width() || zoomed_height > height()) { - horizontal_scrollbar->setVisible(true); - vertical_scrollbar->setVisible(true); - - horizontal_scrollbar->setMaximum(zoomed_width - width()); - vertical_scrollbar->setMaximum(zoomed_height - height()); - - horizontal_scrollbar->setValue(horizontal_scrollbar->maximum()/2); - vertical_scrollbar->setValue(vertical_scrollbar->maximum()/2); - - adjust_scrollbars(); - } - } else { - // if the zoom size is smaller than the available area, scale the surface down - - int zoomed_x = 0; - int zoomed_y = 0; - - if (zoomed_width < width()) zoomed_x = (width()>>1)-(zoomed_width>>1); - if (zoomed_height < height()) zoomed_y = (height()>>1)-(zoomed_height>>1); - - child->move(zoomed_x, zoomed_y); - child->resize(zoomed_width, zoomed_height); - } - } - } -} - -void ViewerContainer::adjust_scrollbars() { - horizontal_scrollbar->move(0, height()-horizontal_scrollbar->height()); - horizontal_scrollbar->setFixedWidth(qMax(0, width()-vertical_scrollbar->width())); - horizontal_scrollbar->setPageStep(width()); - - vertical_scrollbar->move(width() - vertical_scrollbar->width(), 0); - vertical_scrollbar->setFixedHeight(qMax(0, height()-horizontal_scrollbar->height())); - vertical_scrollbar->setPageStep(height()); -} - -void ViewerContainer::resizeEvent(QResizeEvent *event) { - event->accept(); - adjust(); -} - -void ViewerContainer::scroll_changed() { - child->set_scroll( - double(horizontal_scrollbar->value())/double(horizontal_scrollbar->maximum()), - double(vertical_scrollbar->value())/double(vertical_scrollbar->maximum()) - ); -} diff --git a/ui/viewercontainer.h b/ui/viewercontainer.h deleted file mode 100644 index ed6845782..000000000 --- a/ui/viewercontainer.h +++ /dev/null @@ -1,69 +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 VIEWERCONTAINER_H -#define VIEWERCONTAINER_H - -#include -class Viewer; -class ViewerWidget; -class QScrollBar; - -class ViewerContainer : public QWidget -{ - Q_OBJECT -public: - explicit ViewerContainer(QWidget *parent = 0); - ~ViewerContainer(); - - bool fit; - double zoom; - - void dragScrollPress(const QPoint&); - void dragScrollMove(const QPoint&); - void parseWheelEvent(QWheelEvent* event); - - Viewer* viewer; - ViewerWidget* child; - void adjust(); - - // manually moves scrollbars into the correct position - void adjust_scrollbars(); - -protected: - void resizeEvent(QResizeEvent *event); - -signals: - -public slots: - -private slots: - void scroll_changed(); - -private: - int drag_start_x; - int drag_start_y; - int horiz_start; - int vert_start; - QScrollBar* horizontal_scrollbar; - QScrollBar* vertical_scrollbar; -}; - -#endif // VIEWERCONTAINER_H diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp deleted file mode 100644 index 3f54c33ad..000000000 --- a/ui/viewerwidget.cpp +++ /dev/null @@ -1,806 +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 "viewerwidget.h" - -extern "C" { -#include -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "panels/panels.h" -#include "project/projectelements.h" -#include "rendering/renderfunctions.h" -#include "rendering/audio.h" -#include "global/config.h" -#include "global/debug.h" -#include "global/math.h" -#include "global/timing.h" -#include "ui/collapsiblewidget.h" -#include "undo/undo.h" -#include "project/media.h" -#include "ui/viewercontainer.h" -#include "rendering/cacher.h" -#include "ui/timelineview.h" -#include "rendering/renderfunctions.h" -#include "rendering/renderthread.h" -#include "rendering/shadergenerators.h" -#include "ui/viewerwindow.h" -#include "ui/menu.h" -#include "ui/waveform.h" -#include "mainwindow.h" -#include "effects/effectgizmo.h" - -const int kTitleActionSafeVertexSize = 84; - -ViewerWidget::ViewerWidget(QWidget *parent) : - QOpenGLWidget(parent), - waveform(false), - waveform_zoom(1.0), - waveform_scroll(0), - dragging(false), - gizmos(nullptr), - selected_gizmo(nullptr), - x_scroll(0), - y_scroll(0) -{ - setMouseTracking(true); - setFocusPolicy(Qt::ClickFocus); - - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); - - renderer.start(QThread::HighestPriority); - connect(&renderer, SIGNAL(ready()), this, SLOT(queue_repaint())); - - window = new ViewerWindow(this); -} - -ViewerWidget::~ViewerWidget() { - renderer.cancel(); -} - -void ViewerWidget::set_waveform_scroll(int s) { - if (waveform) { - waveform_scroll = s; - update(); - } -} - -void ViewerWidget::set_fullscreen(int screen) { - if (screen >= 0 && screen < QGuiApplication::screens().size()) { - QScreen* selected_screen = QGuiApplication::screens().at(screen); - window->showFullScreen(); - window->setGeometry(selected_screen->geometry()); - } else { - qCritical() << "Failed to find requested screen" << screen << "to set fullscreen to"; - } -} - -void ViewerWidget::show_context_menu() { - Menu menu(this); - - QAction* save_frame_as_image = menu.addAction(tr("Save Frame as Image...")); - connect(save_frame_as_image, SIGNAL(triggered(bool)), this, SLOT(save_frame())); - - Menu* fullscreen_menu = new Menu(tr("Show Fullscreen")); - menu.addMenu(fullscreen_menu); - QList screens = QGuiApplication::screens(); - if (window->isVisible()) { - fullscreen_menu->addAction(tr("Disable")); - } - for (int i=0;iaddAction(tr("Screen %1: %2x%3").arg( - QString::number(i), - QString::number(screens.at(i)->size().width()), - QString::number(screens.at(i)->size().height()))); - screen_action->setData(i); - } - connect(fullscreen_menu, SIGNAL(triggered(QAction*)), this, SLOT(fullscreen_menu_action(QAction*))); - - Menu zoom_menu(tr("Zoom")); - QAction* fit_zoom = zoom_menu.addAction(tr("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(tr("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); - - if (viewer->mode() != Viewer::kTimelineMode) { - menu.addAction(tr("Close Media"), viewer, SLOT(close_media())); - } - - menu.exec(QCursor::pos()); -} - -void ViewerWidget::save_frame() { - QFileDialog fd(this); - fd.setAcceptMode(QFileDialog::AcceptSave); - fd.setFileMode(QFileDialog::AnyFile); - fd.setWindowTitle(tr("Save Frame")); - fd.setNameFilter("Portable Network Graphic (*.png);;JPEG (*.jpg);;Windows Bitmap (*.bmp);;Portable Pixmap (*.ppm);;X11 Bitmap (*.xbm);;X11 Pixmap (*.xpm)"); - - if (fd.exec()) { - QString fn = fd.selectedFiles().at(0); - QString selected_ext = fd.selectedNameFilter().mid(fd.selectedNameFilter().indexOf(QRegExp("\\*.[a-z][a-z][a-z]")) + 1, 4); - if (!fn.endsWith(selected_ext, Qt::CaseInsensitive)) { - fn += selected_ext; - } - - renderer.start_render(context(), viewer->seq.get(), 1, fn); - } -} - -void ViewerWidget::queue_repaint() { - update(); -} - -void ViewerWidget::fullscreen_menu_action(QAction *action) { - if (action->data().isNull()) { - window->hide(); - } else { - set_fullscreen(action->data().toInt()); - } -} - -void ViewerWidget::set_fit_zoom() { - container->fit = true; - container->adjust(); -} - -void ViewerWidget::set_custom_zoom() { - bool ok; - double d = QInputDialog::getDouble(this, - tr("Viewer Zoom"), - tr("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(); -} - -void ViewerWidget::initializeGL() { - context()->functions()->initializeOpenGLFunctions(); - - connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(context_destroy()), Qt::DirectConnection); - - pipeline_ = olive::shader::GetPipeline(); - - vao_.create(); - - title_safe_area_buffer_.create(); - title_safe_area_buffer_.bind(); - title_safe_area_buffer_.allocate(nullptr, kTitleActionSafeVertexSize * sizeof(GLfloat)); - title_safe_area_buffer_.release(); - - gizmo_buffer_.create(); -} - -void ViewerWidget::frame_update() { - if (viewer->seq != nullptr) { - // send context to other thread for drawing - if (waveform) { - update(); - } else { - doneCurrent(); - renderer.start_render(context(), viewer->seq.get(), viewer->get_playback_speed()); - } - - // render the audio - olive::rendering::compose_audio(viewer, viewer->seq.get(), viewer->get_playback_speed(), false); - } -} - -RenderThread *ViewerWidget::get_renderer() { - return &renderer; -} - -void ViewerWidget::set_scroll(double x, double y) { - x_scroll = x; - y_scroll = y; - update(); -} - -void ViewerWidget::seek_from_click(int x) { - viewer->seek(getFrameFromScreenPoint(waveform_zoom, x+waveform_scroll)); -} - -QMatrix4x4 ViewerWidget::get_matrix() -{ - QMatrix4x4 matrix; - - double zoom_factor = container->zoom/(double(width())/double(viewer->seq->width())); - - if (zoom_factor > 1.0) { - double zoom_size = (zoom_factor*2.0) - 2.0; - - matrix.translate((-(x_scroll-0.5))*zoom_size, (y_scroll-0.5)*zoom_size); - matrix.scale(zoom_factor); - } - - return matrix; -} - -void ViewerWidget::context_destroy() { - makeCurrent(); - - renderer.delete_ctx(); - - title_safe_area_buffer_.destroy(); - - if (gizmo_buffer_.isCreated()) { - gizmo_buffer_.destroy(); - } - - vao_.destroy(); - - pipeline_ = nullptr; - - doneCurrent(); -} - -EffectGizmo* ViewerWidget::get_gizmo_from_mouse(int x, int y) { - if (gizmos != nullptr) { - double multiplier = double(viewer->seq->width()) / double(width()); - QPoint mouse_pos(qRound(x*multiplier), qRound((height()-y)*multiplier)); - int dot_size = 2 * qRound(GIZMO_DOT_SIZE * multiplier); - int target_size = 2 * qRound(GIZMO_TARGET_SIZE * multiplier); - for (int i=0;igizmo_count();i++) { - EffectGizmo* g = gizmos->gizmo(i); - - switch (g->get_type()) { - case GIZMO_TYPE_DOT: - if (mouse_pos.x() > g->screen_pos[0].x() - dot_size - && mouse_pos.y() > g->screen_pos[0].y() - dot_size - && mouse_pos.x() < g->screen_pos[0].x() + dot_size - && mouse_pos.y() < g->screen_pos[0].y() + dot_size) { - return g; - } - break; - case GIZMO_TYPE_POLY: - if (QPolygon(g->screen_pos).containsPoint(mouse_pos, Qt::OddEvenFill)) { - return g; - } - break; - case GIZMO_TYPE_TARGET: - if (mouse_pos.x() > g->screen_pos[0].x() - target_size - && mouse_pos.y() > g->screen_pos[0].y() - target_size - && mouse_pos.x() < g->screen_pos[0].x() + target_size - && mouse_pos.y() < g->screen_pos[0].y() + target_size) { - return g; - } - break; - } - } - } - return nullptr; -} - -void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) { - if (selected_gizmo != nullptr) { - double multiplier = double(viewer->seq->width()) / double(width()); - - int x_movement = qRound((event->pos().x() - drag_start_x)*multiplier); - int y_movement = qRound((event->pos().y() - drag_start_y)*multiplier); - - gizmos->gizmo_move(selected_gizmo, - x_movement, - y_movement, - get_timecode(gizmos->parent_clip, - gizmos->parent_clip->track()->sequence()->playhead), - done); - - gizmo_x_mvmt += x_movement; - gizmo_y_mvmt += y_movement; - - drag_start_x = event->pos().x(); - drag_start_y = event->pos().y(); - } -} - -void ViewerWidget::mousePressEvent(QMouseEvent* event) { - if (waveform) { - seek_from_click(event->x()); - } else if (event->buttons() & Qt::MiddleButton || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { - container->dragScrollPress(event->pos()*container->zoom); - } else if (event->buttons() & Qt::LeftButton) { - drag_start_x = event->pos().x(); - drag_start_y = event->pos().y(); - - gizmo_x_mvmt = 0; - gizmo_y_mvmt = 0; - - selected_gizmo = get_gizmo_from_mouse(event->pos().x(), event->pos().y()); - } - dragging = true; -} - -void ViewerWidget::mouseMoveEvent(QMouseEvent* event) { - unsetCursor(); - if (olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { - setCursor(Qt::OpenHandCursor); - } - if (dragging) { - if (waveform) { - seek_from_click(event->x()); - } else if (event->buttons() & Qt::MiddleButton || olive::timeline::current_tool == olive::timeline::TIMELINE_TOOL_HAND) { - container->dragScrollMove(event->pos()*container->zoom); - } else if (event->buttons() & Qt::LeftButton) { - if (gizmos == nullptr) { - viewer->initiate_drag(olive::timeline::kImportBoth); - dragging = false; - } else { - move_gizmos(event, false); - } - } - } else { - EffectGizmo* g = get_gizmo_from_mouse(event->pos().x(), event->pos().y()); - if (g != nullptr) { - if (g->get_cursor() > -1) { - setCursor(static_cast(g->get_cursor())); - } - } - } -} - -void ViewerWidget::mouseReleaseEvent(QMouseEvent *event) { - if (dragging - && gizmos != nullptr - && event->button() == Qt::LeftButton - && olive::timeline::current_tool != olive::timeline::TIMELINE_TOOL_HAND) { - move_gizmos(event, true); - } - dragging = false; -} - -void ViewerWidget::wheelEvent(QWheelEvent *event) { - container->parseWheelEvent(event); -} - -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) { - int in_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->workarea_in) - waveform_scroll; - int out_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->workarea_out) - waveform_scroll; - - p.fillRect(QRect(in_x, 0, out_x - in_x, height()), QColor(255, 255, 255, 64)); - p.setPen(Qt::white); - p.drawLine(in_x, 0, in_x, height()); - p.drawLine(out_x, 0, out_x, height()); - } - QRect wr = rect(); - wr.setX(wr.x() - waveform_scroll); - - p.setPen(Qt::green); - olive::ui::DrawWaveform(waveform_clip.get(), waveform_ms, waveform_clip->timeline_out(), &p, wr, waveform_scroll, width()+waveform_scroll, waveform_zoom); - p.setPen(Qt::red); - int playhead_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->playhead) - waveform_scroll; - p.drawLine(playhead_x, 0, playhead_x, height()); -} - -void ViewerWidget::draw_title_safe_area() { - QOpenGLFunctions* func = context()->functions(); - - pipeline_->bind(); - - - float ar = float(width()) / float(height()); - - float horizontal_cross_size = 0.05f / ar; - - // Set matrix to 0.0 -> 1.0 on both axes - QMatrix4x4 matrix; - matrix.ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); - - // adjust the horizontal center cross by the aspect ratio to appear "square" - if (olive::config.use_custom_title_safe_ratio && olive::config.custom_title_safe_ratio > 0) { - if (ar > olive::config.custom_title_safe_ratio) { - matrix.translate(((ar - olive::config.custom_title_safe_ratio) / 2.0) / ar, 0.0f); - matrix.scale(olive::config.custom_title_safe_ratio / ar, 1.0f); - } else { - matrix.translate(0.0f, (((olive::config.custom_title_safe_ratio - ar) / 2.0) / olive::config.custom_title_safe_ratio)); - matrix.scale(1.0f, ar / olive::config.custom_title_safe_ratio); - } - - horizontal_cross_size *= ar/olive::config.custom_title_safe_ratio; - } - - float adjusted_cross_x1 = 0.5f - horizontal_cross_size; - float adjusted_cross_x2 = 0.5f + horizontal_cross_size; - - pipeline_->setUniformValue("mvp_matrix", matrix); - pipeline_->setUniformValue("color_only", true); - pipeline_->setUniformValue("color_only_color", QColor(192, 192, 192, 255)); - - - - GLfloat vertices[] = { - // action safe lines - 0.05f, 0.05f, 0.0f, - 0.95f, 0.05f, 0.0f, - - 0.95f, 0.05f, 0.0f, - 0.95f, 0.95f, 0.0f, - - 0.95f, 0.95f, 0.0f, - 0.05f, 0.95f, 0.0f, - - 0.05f, 0.95f, 0.0f, - 0.05f, 0.05f, 0.0f, - - // title safe lines - 0.1f, 0.1f, 0.0f, - 0.9f, 0.1f, 0.0f, - - 0.9f, 0.1f, 0.0f, - 0.9f, 0.9f, 0.0f, - - 0.9f, 0.9f, 0.0f, - 0.1f, 0.9f, 0.0f, - - 0.1f, 0.9f, 0.0f, - 0.1f, 0.1f, 0.0f, - - // side-center markers - 0.05f, 0.5f, 0.0f, - 0.125f, 0.5f, 0.0f, - - 0.95f, 0.5f, 0.0f, - 0.875f, 0.5f, 0.0f, - - 0.5f, 0.05f, 0.0f, - 0.5f, 0.125f, 0.0f, - - 0.5f, 0.95f, 0.0f, - 0.5f, 0.875f, 0.0f, - - // horizontal center cross marker - adjusted_cross_x1, 0.5f, 0.0f, - adjusted_cross_x2, 0.5f, 0.0f, - - // vertical center cross marker - 0.5f, 0.45f, 0.0f, - 0.5f, 0.55f, 0.0f - }; - - vao_.bind(); - - title_safe_area_buffer_.bind(); - title_safe_area_buffer_.write(0, vertices, kTitleActionSafeVertexSize * sizeof(GLfloat)); - - GLuint vertex_location = pipeline_->attributeLocation("a_position"); - func->glEnableVertexAttribArray(vertex_location); - func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, 0); - - func->glDrawArrays(GL_LINES, 0, 28); - - pipeline_->setUniformValue("color_only", false); - - title_safe_area_buffer_.release(); - - vao_.release(); - - pipeline_->release(); - -} - -void ViewerWidget::draw_gizmos() { - QOpenGLFunctions* func = context()->functions(); - - pipeline_->bind(); - - double zoom_factor = container->zoom/(double(width())/double(viewer->seq->width())); - - QMatrix4x4 matrix; - matrix.ortho(0, viewer->seq->width(), 0, viewer->seq->height(), -1, 1); - matrix.scale(zoom_factor, zoom_factor); - matrix.translate(-(viewer->seq->width()-(width()/container->zoom))*x_scroll, - -((viewer->seq->height()-(height()/container->zoom))*(1.0-y_scroll))); - - // Set transformation matrix - pipeline_->setUniformValue("mvp_matrix", matrix); - - // Set pipeline shader to draw full white - pipeline_->setUniformValue("color_only", true); - pipeline_->setUniformValue("color_only_color", QColor(255, 255, 255, 255)); - - // Set up constants for gizmo sizes - float size_diff = float(viewer->seq->width()) / float(width()); - float dot_size = GIZMO_DOT_SIZE * size_diff; - float target_size = GIZMO_TARGET_SIZE * size_diff; - - QVector vertices; - - for (int j=0;jgizmo_count();j++) { - - EffectGizmo* g = gizmos->gizmo(j); - - switch (g->get_type()) { - case GIZMO_TYPE_DOT: - - // Draw standard square dot - - vertices.append(g->screen_pos[0].x()-dot_size); - vertices.append(g->screen_pos[0].y()-dot_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+dot_size); - vertices.append(g->screen_pos[0].y()-dot_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+dot_size); - vertices.append(g->screen_pos[0].y()+dot_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()-dot_size); - vertices.append(g->screen_pos[0].y()+dot_size); - vertices.append(0.0f); - - break; - case GIZMO_TYPE_POLY: - - // Draw an arbitrary polygon with lines - - for (int k=1;kget_point_count();k++) { - - vertices.append(g->screen_pos[k-1].x()); - vertices.append(g->screen_pos[k-1].y()); - vertices.append(0.0f); - - vertices.append(g->screen_pos[k].x()); - vertices.append(g->screen_pos[k].y()); - vertices.append(0.0f); - - } - - vertices.append(g->screen_pos[g->get_point_count()-1].x()); - vertices.append(g->screen_pos[g->get_point_count()-1].y()); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()); - vertices.append(g->screen_pos[0].y()); - vertices.append(0.0f); - - break; - case GIZMO_TYPE_TARGET: - - // Draw "target" gizmo (square with two lines through the middle) - - vertices.append(g->screen_pos[0].x()-target_size); - vertices.append(g->screen_pos[0].y()-target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+target_size); - vertices.append(g->screen_pos[0].y()-target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+target_size); - vertices.append(g->screen_pos[0].y()-target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+target_size); - vertices.append(g->screen_pos[0].y()+target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+target_size); - vertices.append(g->screen_pos[0].y()+target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()-target_size); - vertices.append(g->screen_pos[0].y()+target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()-target_size); - vertices.append(g->screen_pos[0].y()+target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()-target_size); - vertices.append(g->screen_pos[0].y()-target_size); - vertices.append(0.0f); - - - - vertices.append(g->screen_pos[0].x()-target_size); - vertices.append(g->screen_pos[0].y()); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()+target_size); - vertices.append(g->screen_pos[0].y()); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()); - vertices.append(g->screen_pos[0].y()-target_size); - vertices.append(0.0f); - - vertices.append(g->screen_pos[0].x()); - vertices.append(g->screen_pos[0].y()+target_size); - vertices.append(0.0f); - - break; - } - } - - vao_.bind(); - - // The gizmo buffer may have been destroyed or not created yet, ensure it's created here - if (!gizmo_buffer_.isCreated() && !gizmo_buffer_.create()) { - return; - } - - gizmo_buffer_.bind(); - - // Get the total byte size of the vertex array - int gizmo_buffer_desired_size = vertices.size() * sizeof(GLfloat); - - // Determine if the gizmo count has changed, and if so reallocate the buffer - if (gizmo_buffer_.size() != gizmo_buffer_desired_size) { - gizmo_buffer_.allocate(vertices.constData(), gizmo_buffer_desired_size); - } else { - gizmo_buffer_.write(0, vertices.constData(), gizmo_buffer_desired_size); - } - - - GLuint vertex_location = pipeline_->attributeLocation("a_position"); - func->glEnableVertexAttribArray(vertex_location); - func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, 0); - - gizmo_buffer_.release(); - - func->glDrawArrays(GL_LINES, 0, vertices.size() / 3); - - pipeline_->setUniformValue("color_only", false); - - vao_.release(); - - pipeline_->release(); - -} - -void ViewerWidget::paintGL() { - - if (viewer->seq != nullptr) { - - QOpenGLFunctions* f = context()->functions(); - - viewer->seq->SetGLContext(context()); - - makeCurrent(); - - // clear to solid black - f->glClearColor(0.0, 0.0, 0.0, 0.0); - f->glClear(GL_COLOR_BUFFER_BIT); - - - // draw texture from render thread - - f->glViewport(0, 0, width(), height()); - - GLuint tex = viewer->seq->texture(); - - f->glBindTexture(GL_TEXTURE_2D, tex); - - qDebug() << "drawing texture" << tex; - - olive::rendering::Blit(pipeline_.get(), true, get_matrix()); - - f->glBindTexture(GL_TEXTURE_2D, 0); - - } - - /* - if (waveform) { - draw_waveform_func(); - } else { - const GLuint tex = renderer.get_texture(); - QMutex* tex_lock = renderer.get_texture_mutex(); - - tex_lock->lock(); - - QOpenGLFunctions* f = context()->functions(); - - makeCurrent(); - - // clear to solid black - f->glClearColor(0.0, 0.0, 0.0, 0.0); - f->glClear(GL_COLOR_BUFFER_BIT); - - - // draw texture from render thread - - f->glViewport(0, 0, width(), height()); - - f->glBindTexture(GL_TEXTURE_2D, tex); - - olive::rendering::Blit(pipeline_.get(), true, get_matrix()); - - f->glBindTexture(GL_TEXTURE_2D, 0); - - // draw title/action safe area - if (olive::config.show_title_safe_area) { - draw_title_safe_area(); - } - - gizmos = renderer.gizmos; - if (gizmos != nullptr) { - draw_gizmos(); - } - - if (window->isVisible()) { - window->set_texture(tex, double(viewer->seq->width())/double(viewer->seq->height()), tex_lock); - } - - tex_lock->unlock(); - - if (renderer.did_texture_fail() && !viewer->playing) { - doneCurrent(); - renderer.start_render(context(), viewer->seq.get(), viewer->get_playback_speed()); - } - } - */ -} diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h deleted file mode 100644 index f66006b6c..000000000 --- a/ui/viewerwidget.h +++ /dev/null @@ -1,115 +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 VIEWERWIDGET_H -#define VIEWERWIDGET_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "timeline/clip.h" -#include "project/footage.h" -#include "nodes/oldeffectnode.h" -#include "ui/viewerwindow.h" -#include "ui/viewercontainer.h" -#include "rendering/renderthread.h" - -class Viewer; -class QOpenGLFramebufferObject; -struct GLTextureCoords; - -class ViewerWidget : public QOpenGLWidget -{ - Q_OBJECT -public: - ViewerWidget(QWidget *parent = nullptr); - ~ViewerWidget(); - - void close_window(); - void wait_until_render_is_paused(); - - void paintGL(); - void initializeGL(); - Viewer* viewer; - ViewerContainer* container; - - bool waveform; - ClipPtr waveform_clip; - const FootageStream* waveform_ms; - double waveform_zoom; - int waveform_scroll; - - void frame_update(); - RenderThread* get_renderer(); - void set_scroll(double x, double y); -public slots: - void set_waveform_scroll(int s); - void set_fullscreen(int screen = 0); -protected: - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void wheelEvent(QWheelEvent* event); -private: - void draw_waveform_func(); - void draw_title_safe_area(); - void draw_gizmos(); - EffectGizmo* get_gizmo_from_mouse(int x, int y); - void move_gizmos(QMouseEvent *event, bool done); - bool dragging; - void seek_from_click(int x); - QMatrix4x4 get_matrix(); - OldEffectNode* gizmos; - int drag_start_x; - int drag_start_y; - int gizmo_x_mvmt; - int gizmo_y_mvmt; - EffectGizmo* selected_gizmo; - RenderThread renderer; - ViewerWindow* window; - double x_scroll; - double y_scroll; - - QOpenGLShaderProgramPtr pipeline_; - QOpenGLVertexArrayObject vao_; - QOpenGLBuffer gizmo_buffer_; - QOpenGLBuffer title_safe_area_buffer_; - -private slots: - void context_destroy(); - void retry(); - void show_context_menu(); - void save_frame(); - void queue_repaint(); - void fullscreen_menu_action(QAction* action); - void set_fit_zoom(); - void set_custom_zoom(); - void set_menu_zoom(QAction *action); -}; - -#endif // VIEWERWIDGET_H diff --git a/ui/viewerwindow.cpp b/ui/viewerwindow.cpp deleted file mode 100644 index 9582c3e32..000000000 --- a/ui/viewerwindow.cpp +++ /dev/null @@ -1,193 +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 "viewerwindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rendering/renderfunctions.h" -#include "rendering/shadergenerators.h" -#include "ui/mainwindow.h" - -ViewerWindow::ViewerWindow(QWidget *parent) : - QOpenGLWidget(parent, Qt::Window), - texture_(0), - mutex_(nullptr), - show_fullscreen_msg_(false) -{ - setMouseTracking(true); - - fullscreen_msg_timer_.setInterval(2000); - connect(&fullscreen_msg_timer_, SIGNAL(timeout()), this, SLOT(fullscreen_msg_timeout())); -} - -void ViewerWindow::set_texture(GLuint t, double iar, QMutex* imutex) { - texture_ = t; - ar_ = iar; - mutex_ = 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(); - } -} - -void ViewerWindow::mousePressEvent(QMouseEvent *e) { - if (show_fullscreen_msg_ && fullscreen_msg_rect_.contains(e->pos())) { - hide(); - } -} - -void ViewerWindow::mouseMoveEvent(QMouseEvent *) { - fullscreen_msg_timer_.start(); - if (!show_fullscreen_msg_) { - show_fullscreen_msg_ = true; - update(); - } -} - -void ViewerWindow::initializeGL() -{ - pipeline_ = olive::shader::GetPipeline(); -} - -void ViewerWindow::paintGL() { - if (texture_ > 0) { - if (mutex_ != nullptr) mutex_->lock(); - - QOpenGLFunctions* f = context()->functions(); - //QOpenGLExtraFunctions* xf = context()->extraFunctions(); - - makeCurrent(); - - // clear to solid black - f->glClearColor(0.0, 0.0, 0.0, 0.0); - f->glClear(GL_COLOR_BUFFER_BIT); - - - // draw texture from render thread - - - QMatrix4x4 matrix; - - double widget_ar = (double(width()) / double(height())); - if (widget_ar > ar_) { - matrix.scale(ar_ / widget_ar, 1.0); - } else { - matrix.scale(1.0f, widget_ar / ar_); - } - - - f->glViewport(0, 0, width(), height()); - - f->glBindTexture(GL_TEXTURE_2D, texture_); - - olive::rendering::Blit(pipeline_.get(), true, matrix); - - f->glBindTexture(GL_TEXTURE_2D, 0); - - - - if (mutex_ != nullptr) mutex_->unlock(); - } - - if (show_fullscreen_msg_) { - QPainter p(this); - - QFont f = p.font(); - f.setPointSize(24); - p.setFont(f); - - QFontMetrics fm(f); - - QString fs_str = tr("Exit Fullscreen"); - - p.setPen(Qt::white); - p.setBrush(QColor(0, 0, 0, 128)); - - int text_width = fm.width(fs_str); - int text_x = (width()/2)-(text_width/2); - int text_y = fm.height()+fm.ascent(); - - int rect_padding = 8; - - fullscreen_msg_rect_ = QRect(text_x-rect_padding, - fm.height()-rect_padding, - text_width+rect_padding+rect_padding, - fm.height()+rect_padding+rect_padding); - - p.drawRect(fullscreen_msg_rect_); - - p.drawText(text_x, text_y, fs_str); - } -} - -void ViewerWindow::fullscreen_msg_timeout() { - fullscreen_msg_timer_.stop(); - if (show_fullscreen_msg_) { - show_fullscreen_msg_ = false; - update(); - } -} diff --git a/ui/viewerwindow.h b/ui/viewerwindow.h deleted file mode 100644 index 49179c2cf..000000000 --- a/ui/viewerwindow.h +++ /dev/null @@ -1,63 +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 VIEWERWINDOW_H -#define VIEWERWINDOW_H - -#include -#include -#include -#include -#include - -#include "rendering/qopenglshaderprogramptr.h" - -class ViewerWindow : public QOpenGLWidget { - Q_OBJECT -public: - ViewerWindow(QWidget *parent); - void set_texture(GLuint t, double iar, QMutex *imutex); -protected: - virtual void showEvent(QShowEvent*) override; - virtual void keyPressEvent(QKeyEvent*) override; - virtual void mousePressEvent(QMouseEvent*) override; - virtual void mouseMoveEvent(QMouseEvent*) override; - - virtual void initializeGL() override; - virtual void paintGL() override; -private: - GLuint texture_; - double ar_; - QMutex* mutex_; - QOpenGLShaderProgramPtr pipeline_; - - // 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(); -}; - -#endif // VIEWERWINDOW_H diff --git a/ui/waveform.cpp b/ui/waveform.cpp deleted file mode 100644 index 40933453b..000000000 --- a/ui/waveform.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "waveform.h" - -#include - -#include "global/config.h" - -int ConvertSampleToHeight(qint8 signed_sample, int channel_height) { - int half_channel_height = channel_height >> 1; - return (half_channel_height) + qRound(((double(signed_sample) / 128.0)) * half_channel_height); -} - -void olive::ui::DrawWaveform(Clip* clip, - const FootageStream* ms, - long media_length, - QPainter *p, - const QRect& clip_rect, - int waveform_start, - int waveform_limit, - double zoom) { - - int divider = ms->audio_channels; - - int channel_height = clip_rect.height()/ms->audio_channels; - - int last_waveform_index = -1; - - for (int i=waveform_start;iclip_in() + (double(i)/zoom))/media_length) * ms->audio_preview.size())/divider)*divider; - - if (clip->reversed()) { - waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2); - } - - if (last_waveform_index < 0) last_waveform_index = waveform_index; - - for (int j=0;jaudio_channels;j++) { - int bottom = clip_rect.top()+channel_height*(j+1); - - int offset_range_start = last_waveform_index+(j*2); - int offset_range_end = waveform_index+(j*2); - int offset_range_min = qMin(offset_range_start, offset_range_end); - int offset_range_max = qMax(offset_range_start, offset_range_end); - - // Break if we're about to draw from an index that doesn't exist - if (offset_range_min+1 >= ms->audio_preview.size()) { - break; - } - - int min = ConvertSampleToHeight(ms->audio_preview.at(offset_range_min), channel_height); - int max = ConvertSampleToHeight(ms->audio_preview.at(offset_range_min+1), channel_height); - - if ((offset_range_max + 1) < ms->audio_preview.size()) { - - // for waveform drawings, we get the maximum below 0 and maximum above 0 for this waveform range - for (int k=offset_range_min+2;k<=offset_range_max;k+=2) { - min = ConvertSampleToHeight(ms->audio_preview.at(k), channel_height); - max = ConvertSampleToHeight(ms->audio_preview.at(k+1), channel_height); - } - - // draw waveforms - if (olive::config.rectified_waveforms) { - p->drawLine(clip_rect.left()+i, bottom, clip_rect.left()+i, bottom - (max - min)); - } else { - p->drawLine(clip_rect.left()+i, bottom - min, clip_rect.left()+i, bottom - max); - } - } - } - last_waveform_index = waveform_index; - } -} diff --git a/ui/waveform.h b/ui/waveform.h deleted file mode 100644 index d7dc92040..000000000 --- a/ui/waveform.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef WAVEFORM_H -#define WAVEFORM_H - -#include -#include - -#include "timeline/clip.h" -#include "project/footage.h" - -namespace olive { -namespace ui { - -void DrawWaveform(Clip* clip, - const FootageStream *ms, - long media_length, - QPainter* p, - const QRect& clip_rect, - int waveform_start, - int waveform_limit, - double zoom); - -} -} - -#endif // WAVEFORM_H diff --git a/undo/comboaction.cpp b/undo/comboaction.cpp deleted file mode 100644 index 0c93e61d3..000000000 --- a/undo/comboaction.cpp +++ /dev/null @@ -1,60 +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 "comboaction.h" - -ComboAction::ComboAction() {} - -ComboAction::~ComboAction() { - for (int i=0;i=0;i--) { - commands.at(i)->undo(); - } - for (int i=0;iundo(); - } -} - -void ComboAction::redo() { - for (int i=0;iredo(); - } - for (int i=0;iredo(); - } -} - -void ComboAction::append(QUndoCommand* u) { - commands.append(u); -} - -void ComboAction::appendPost(QUndoCommand* u) { - post_commands.append(u); -} - -bool ComboAction::hasActions() -{ - return commands.size() > 0; -} diff --git a/undo/comboaction.h b/undo/comboaction.h deleted file mode 100644 index 1a845165c..000000000 --- a/undo/comboaction.h +++ /dev/null @@ -1,116 +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 COMBOACTION_H -#define COMBOACTION_H - -#include -#include - -/** - * @brief The ComboAction class - * - * The Undo/Redo system works by stacking an action that knows how to "do" and also "undo" itself. As Olive is - * a very complex program, there are many actions that can in one "user action". For example, moving a clip over - * another will delete the clip under it, which is at least two actions that need to be undone if the user clicks - * undo, however the user only (knowingly) did one thing and would find it confusing if this one user action required - * to undos to complete undo. - * - * To address this, ComboAction is an undo action that simply compiles several possible actions into one, doing them - * all on every redo, and undoing them all on every undo. - */ -class ComboAction : public QUndoCommand { -public: - /** - * @brief ComboAction Constructor. Currently empty. - */ - ComboAction(); - - /** - * @brief ~ComboAction Destructor. Cleans up all QUndoCommand classes that have been added to it. - */ - virtual ~ComboAction() override; - - /** - * @brief Undo Function - * - * Called by the QUndoStack to undo. - * - * Calls QUndoCommand::undo() on all QUndoCommand objects added by append() - * in REVERSE order to how they were added. Then calls QUndoCommand::redo() on every action added by appendPost() - * in the order they were added (not in reverse). - */ - virtual void undo() override; - - /** - * @brief Redo Function - * - * Called by the QUndoStack to redo. - * - * Calls QUndoCommand::redo() on all QUndoCommand objects added by append() - * in the order they were added. Then calls QUndoCommand::redo() on every action added by appendPost() in - * the order they were added. - */ - virtual void redo() override; - - /** - * @brief Add an undo action - * - * Add an action to be done/undone. ComboAction takes ownership of this QUndoCommand and will delete it when - * it is deleted. - * - * @param u - * - * The QUndoCommand to add. - */ - void append(QUndoCommand* u); - - /** - * @brief Add a post-undo PostAction - * - * Sometimes the results of all the actions require another function to be called (e.g. repainting the Viewer). - * QUndoCommand objects added by appendPost() will run after EVERY QUndoCommand added by append() has been run. - * - * @param u - * - * The PostAction to add - */ - void appendPost(QUndoCommand* u); - - /** - * @brief Returns whether actions have been appended or not - * - * @return **TRUE** if actions have been appended, **FALSE** if not. - */ - bool hasActions(); - -private: - /** - * @brief Internal array of QUndoCommand objects - */ - QVector commands; - - /** - * @brief Internal array of PostAction objects - */ - QVector post_commands; -}; - -#endif // COMBOACTION_H diff --git a/undo/undo.cpp b/undo/undo.cpp deleted file mode 100644 index 7e194071a..000000000 --- a/undo/undo.cpp +++ /dev/null @@ -1,1226 +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 "undo.h" - -#include -#include -#include -#include - -#include "global/global.h" -#include "panels/panels.h" -#include "panels/project.h" -#include "panels/effectcontrols.h" -#include "panels/viewer.h" -#include "panels/timeline.h" -#include "ui/sourcetable.h" -#include "project/footage.h" -#include "rendering/renderfunctions.h" -#include "rendering/cacher.h" -#include "ui/labelslider.h" -#include "ui/viewerwidget.h" -#include "project/media.h" -#include "global/clipboard.h" -#include "project/previewgenerator.h" -#include "ui/mainwindow.h" - -MoveClipAction::MoveClipAction(ClipPtr c, long iin, long iout, long iclip_in, Track* itrack, bool irelative) : - clip(c), - old_in(c->timeline_in()), - old_out(c->timeline_out()), - old_clip_in(c->clip_in()), - old_track(c->track()), - new_in(iin), - new_out(iout), - new_clip_in(iclip_in), - new_track(itrack), - relative(irelative), - done(false) -{ - doRedo(); -} - -void MoveClipAction::doUndo() { - if (relative) { - clip->set_timeline_in (clip->timeline_in() - new_in); - clip->set_timeline_out (clip->timeline_out() - new_out); - clip->set_clip_in (clip->clip_in() - new_clip_in); - } else { - clip->set_timeline_in(old_in); - clip->set_timeline_out(old_out); - clip->set_clip_in(old_clip_in); - } - - // Move clip to the new track ONLY IF the old track currently contains this clip - a workaround to ensure this - // action doesn't accidentaly add a clip that it's not supposed to - if (old_track != new_track && new_track->ContainsClip(clip.get())) { - old_track->AddClip(clip); - } - - done = false; -} - -void MoveClipAction::doRedo() { - if (!done) { - if (relative) { - clip->set_timeline_in(clip->timeline_in() + new_in); - clip->set_timeline_out(clip->timeline_out() + new_out); - clip->set_clip_in(clip->clip_in() + new_clip_in); - } else { - clip->set_timeline_in(new_in); - clip->set_timeline_out(new_out); - clip->set_clip_in(new_clip_in); - } - - // Move clip to the new track ONLY IF the old track currently contains this clip - a workaround to ensure this - // action doesn't accidentaly add a clip that it's not supposed to - if (old_track != new_track && old_track->ContainsClip(clip.get())) { - new_track->AddClip(clip); - } - - done = true; - } -} - -DeleteClipAction::DeleteClipAction(Clip *clip) : - done_(false) -{ - // Get shared_ptr object to take ownership of this Clip - - clip_ = clip->track()->GetClipObjectFromRawPtr(clip); - doRedo(); -} - -void DeleteClipAction::doUndo() { - // restore clip to this track - clip_->track()->AddClip(clip_); - - // restore links to this clip - for (int i=0;ilinked.append(clip_.get()); - } - - done_ = false; -} - -void DeleteClipAction::doRedo() { - if (!done_) { - - // remove ref to clip - if (clip_->IsOpen()) { - clip_->Close(true); - } - - clip_->track()->RemoveClip(clip_.get()); - - // delete link to this clip - QVector clips = clip_->track()->sequence()->GetAllClips(); - for (int i=0;ilinked.size();j++) { - if (c->linked.at(j) == clip_.get()) { - c->linked.removeAt(j); - clips_linked_to_this_one_.append(c); - break; - } - } - } - - done_ = true; - - } -} - -SetTimelineInOutCommand::SetTimelineInOutCommand(Sequence* s, bool enabled, long in, long out) { - seq = s; - new_enabled = enabled; - new_in = in; - new_out = out; -} - -void SetTimelineInOutCommand::doUndo() { - seq->using_workarea = old_enabled; - seq->workarea_in = old_in; - seq->workarea_out = old_out; - - // footage viewer functions - if (seq->wrapper_sequence) { - Footage* m = seq->GetAllClips().first()->media()->to_footage(); - m->using_inout = old_enabled; - m->in = old_in; - m->out = old_out; - } -} - -void SetTimelineInOutCommand::doRedo() { - old_enabled = seq->using_workarea; - old_in = seq->workarea_in; - old_out = seq->workarea_out; - - seq->using_workarea = new_enabled; - seq->workarea_in = new_in; - seq->workarea_out = new_out; - - // footage viewer functions - if (seq->wrapper_sequence) { - Footage* m = seq->GetAllClips().first()->media()->to_footage(); - m->using_inout = new_enabled; - m->in = new_in; - m->out = new_out; - } -} - -AddEffectCommand::AddEffectCommand(Clip* c, OldEffectNodePtr e, NodeType m, int insert_pos) { - clip = c; - ref = e; - meta = m; - pos = insert_pos; -} - -void AddEffectCommand::doUndo() { - clip->effects.last()->close(); - if (pos < 0) { - clip->effects.removeLast(); - } else { - clip->effects.removeAt(pos); - } -} - -void AddEffectCommand::doRedo() { - if (ref == nullptr) { - ref = olive::node_library[meta]->Create(clip); - } - if (pos < 0) { - clip->effects.append(ref); - } else { - clip->effects.insert(pos, ref); - } -} - -AddTransitionCommand::AddTransitionCommand(Clip* iopen, - Clip* iclose, - TransitionPtr copy, - NodeType itransition, - int ilength) { - open_ = iopen; - close_ = iclose; - transition_to_copy_ = copy; - transition_meta_ = itransition; - length_ = ilength; - new_transition_ref_ = nullptr; -} - -void AddTransitionCommand::doUndo() { - if (open_ != nullptr) { - open_->opening_transition = old_open_transition_; - } - - if (close_ != nullptr) { - close_->closing_transition = old_close_transition_; - } -} - -void AddTransitionCommand::doRedo() { - // convert open/close clips to primary/secondary for transition object - Clip* primary = open_; - Clip* secondary = close_; - if (primary == nullptr) { - primary = secondary; - secondary = nullptr; - } - - // create new transition object - if (new_transition_ref_ == nullptr) { - if (transition_to_copy_ == nullptr) { - new_transition_ref_ = std::static_pointer_cast(olive::node_library[transition_meta_]->Create(primary)); - new_transition_ref_->secondary_clip = secondary; - } else { - new_transition_ref_ = std::static_pointer_cast(transition_to_copy_->copy(primary)); - } - } - - // set opening clip's opening transition to this and store the old one - if (open_ != nullptr) { - old_open_transition_ = open_->opening_transition; - - open_->opening_transition = new_transition_ref_; - } - - // set closing clip's closing transition to this and store the old one - if (close_ != nullptr) { - old_close_transition_ = close_->closing_transition; - - close_->closing_transition = new_transition_ref_; - } - - // if a length was specified, set it now - if (length_ > 0) { - new_transition_ref_->set_length(length_); - } -} - -ModifyTransitionCommand::ModifyTransitionCommand(TransitionPtr t, long ilength) { - transition_ref_ = t; - new_length_ = ilength; - old_length_ = transition_ref_->get_true_length(); -} - -void ModifyTransitionCommand::doUndo() { - transition_ref_->set_length(old_length_); -} - -void ModifyTransitionCommand::doRedo() { - - transition_ref_->set_length(new_length_); -} - -DeleteTransitionCommand::DeleteTransitionCommand(TransitionPtr t) : - transition_ref_(t) -{ -} - -void DeleteTransitionCommand::doUndo() { - if (opened_clip_ != nullptr) { - opened_clip_->opening_transition = transition_ref_; - } - - if (closed_clip_ != nullptr) { - closed_clip_->closing_transition = transition_ref_; - } -} - -void DeleteTransitionCommand::doRedo() { - opened_clip_ = transition_ref_->get_opened_clip(); - closed_clip_ = transition_ref_->get_closed_clip(); - - if (opened_clip_ != nullptr) { - opened_clip_->opening_transition = nullptr; - } - - if (closed_clip_ != nullptr) { - closed_clip_->closing_transition = nullptr; - } -} - -AddMediaCommand::AddMediaCommand(MediaPtr iitem, Media *iparent) : - item(iitem), - parent(iparent), - done_(false) -{ - doRedo(); -} - -void AddMediaCommand::doUndo() { - olive::project_model.removeChild(parent, item.get()); - done_ = false; -} - -void AddMediaCommand::doRedo() { - if (!done_) { - olive::project_model.appendChild(parent, item); - done_ = true; - } -} - -DeleteMediaCommand::DeleteMediaCommand(MediaPtr i) : - item(i), - parent(i->parentItem()) -{ -} - -void DeleteMediaCommand::doUndo() { - olive::project_model.appendChild(parent, item); -} - -void DeleteMediaCommand::doRedo() { - olive::project_model.removeChild(parent, item.get()); -} - -AddClipCommand::AddClipCommand(const QVector &add) : - clips_(add), - done_(false) -{ - doRedo(); -} - -void AddClipCommand::doUndo() { - // clear effects panel - panel_graph_editor->set_row(nullptr); - panel_effect_controls->Clear(true); - - for (int i=0;itrack()->RemoveClip(c.get()); - - // deselect the area occupied by this clip - c->track()->DeselectArea(c->timeline_in(), c->timeline_out()); - - // if the clip is open, close it - if (c->IsOpen()) { - c->Close(true); - } - } - } - - done_ = false; -} - -void AddClipCommand::doRedo() { - if (!done_) { - for (int i=0;itrack()->AddClip(original); - } - } - done_ = true; - } -} - -LinkCommand::LinkCommand(const QVector& clips, bool link) : - clips_(clips), - link_(link) -{ -} - -void LinkCommand::doUndo() { - for (int i=0;ilinked.clear(); - } else { - c->linked = old_links_.at(i); - } - } - -} - -void LinkCommand::doRedo() { - old_links_.clear(); - for (int i=0;ilinked.append(clips_.at(j)); - } - } - - } else { - - old_links_.append(c->linked); - c->linked.clear(); - - } - } -} - -CheckboxCommand::CheckboxCommand(QCheckBox* b) { - box = b; - checked = box->isChecked(); - done = true; -} - -CheckboxCommand::~CheckboxCommand() {} - -void CheckboxCommand::doUndo() { - box->setChecked(!checked); - done = false; - -} - -void CheckboxCommand::doRedo() { - if (!done) { - box->setChecked(checked); - } -} - -ReplaceMediaCommand::ReplaceMediaCommand(MediaPtr i, QString s) { - item = i; - new_filename = s; - old_filename = item->to_footage()->url; -} - -void ReplaceMediaCommand::replace(QString& filename) { - // close any clips currently using this media - QVector all_sequences = olive::project_model.GetAllSequences(); - for (int i=0;i sequence_clips = all_sequences.at(i)->to_sequence()->GetAllClips(); - - for (int j=0;jmedia() == item.get() && c->IsOpen()) { - c->Close(true); - c->replaced = true; - } - } - } - - // replace media - QStringList files; - files.append(filename); - olive::project_model.process_file_list(files, false, item, nullptr); - PreviewGenerator::AnalyzeMedia(item.get()); -} - -void ReplaceMediaCommand::doUndo() { - replace(old_filename); - - -} - -void ReplaceMediaCommand::doRedo() { - replace(new_filename); -} - -ReplaceClipMediaCommand::ReplaceClipMediaCommand(Media *a, Media *b, bool e) { - old_media = a; - new_media = b; - preserve_clip_ins = e; -} - -void ReplaceClipMediaCommand::replace(bool undo) { - if (!undo) { - old_clip_ins.clear(); - } - - for (int i=0;iIsOpen()) { - c->Close(true); - } - - if (undo) { - if (!preserve_clip_ins) { - c->set_clip_in(old_clip_ins.at(i)); - } - - c->set_media(old_media, c->media_stream_index()); - } else { - if (!preserve_clip_ins) { - old_clip_ins.append(c->clip_in()); - c->set_clip_in(0); - } - - c->set_media(new_media, c->media_stream_index()); - } - - c->replaced = true; - c->refresh(); - } -} - -void ReplaceClipMediaCommand::doUndo() { - replace(true); -} - -void ReplaceClipMediaCommand::doRedo() { - replace(false); - - update_ui(true); -} - -EffectDeleteCommand::EffectDeleteCommand(OldEffectNode *e) : - effect_(e) -{} - -void EffectDeleteCommand::doUndo() { - parent_clip_->effects.insert(index_, deleted_obj_); - - panel_effect_controls->Reload(); -} - -void EffectDeleteCommand::doRedo() { - parent_clip_ = effect_->parent_clip; - - index_ = parent_clip_->IndexOfEffect(effect_); - - Q_ASSERT(index_ > -1); - - effect_->close(); - deleted_obj_ = parent_clip_->effects.at(index_); - parent_clip_->effects.removeAt(index_); - - panel_effect_controls->Reload(); -} - -MediaMove::MediaMove() {} - -void MediaMove::doUndo() { - for (int i=0;iparentItem(); - froms[i] = parent; - olive::project_model.moveChild(items.at(i), to); - } -} - -MediaRename::MediaRename(Media* iitem, QString ito) { - item = iitem; - from = iitem->get_name(); - to = ito; -} - -void MediaRename::doUndo() { - item->set_name(from); - -} - -void MediaRename::doRedo() { - item->set_name(to); -} - -KeyframeDelete::KeyframeDelete(EffectField *ifield, int iindex) : - field(ifield), - index(iindex) -{ -} - -void KeyframeDelete::doUndo() { - field->keyframes.insert(index, deleted_key); -} - -void KeyframeDelete::doRedo() { - deleted_key = field->keyframes.at(index); - field->keyframes.removeAt(index); -} - -SetClipProperty::SetClipProperty(SetClipPropertyType type) : type_(type) -{} - -void SetClipProperty::AddSetting(QVector clips, bool setting) -{ - for (int i=0;iautoscaled(); - break; - case kSetClipPropertyReversed: - old_setting = c->reversed(); - break; - case kSetClipPropertyMaintainAudioPitch: - old_setting = c->speed().maintain_audio_pitch; - break; - case kSetClipPropertyEnabled: - old_setting = c->enabled(); - break; - } - old_setting_.append(old_setting); -} - -void SetClipProperty::MainLoop(bool undo) -{ - for (int i=0;iset_autoscaled(setting); - break; - case kSetClipPropertyReversed: - clips_.at(i)->set_reversed(setting); - break; - case kSetClipPropertyMaintainAudioPitch: - { - ClipSpeed s = clips_.at(i)->speed(); - s.maintain_audio_pitch = setting; - clips_.at(i)->set_speed(s); - } - break; - case kSetClipPropertyEnabled: - clips_.at(i)->set_enabled(setting); - break; - } - } -} - -void SetClipProperty::doUndo() { - MainLoop(true); - panel_sequence_viewer->viewer_widget()->frame_update(); - -} - -void SetClipProperty::doRedo() { - MainLoop(false); - panel_sequence_viewer->viewer_widget()->frame_update(); -} - -AddMarkerAction::AddMarkerAction(QVector* m, long t, QString n) { - active_array = m; - time = t; - name = n; -} - -void AddMarkerAction::doUndo() { - if (index == -1) { - active_array->removeLast(); - } else { - active_array[0][index].name = old_name; - } -} - -void AddMarkerAction::doRedo() { - index = -1; - - for (int i=0;isize();i++) { - if (active_array->at(i).frame == time) { - index = i; - break; - } - } - - if (index == -1) { - Marker m; - m.frame = time; - m.name = name; - active_array->append(m); - } else { - old_name = active_array->at(index).name; - active_array[0][index].name = name; - } -} - -MoveMarkerAction::MoveMarkerAction(Marker* m, long o, long n) { - marker = m; - old_time = o; - new_time = n; -} - -void MoveMarkerAction::doUndo() { - marker->frame = old_time; - -} - -void MoveMarkerAction::doRedo() { - marker->frame = new_time; -} - -DeleteMarkerAction::DeleteMarkerAction(QVector *m) { - active_array = m; - sorted = false; -} - -void DeleteMarkerAction::doUndo() { - for (int i=markers.size()-1;i>=0;i--) { - active_array->insert(markers.at(i), copies.at(i)); - } - -} - -void DeleteMarkerAction::doRedo() { - for (int i=0;iat(markers.at(i))); - for (int j=i+1;j markers.at(i)) { - markers[j]--; - } - } - } - active_array->removeAt(markers.at(i)); - } - sorted = true; -} - -SetSpeedAction::SetSpeedAction(Clip* c, double speed) { - clip = c; - old_speed = c->speed().value; - new_speed = speed; -} - -void SetSpeedAction::doUndo() { - ClipSpeed cs = clip->speed(); - - cs.value = old_speed; - - clip->set_speed(cs); -} - -void SetSpeedAction::doRedo() { - ClipSpeed cs = clip->speed(); - - cs.value = new_speed; - - clip->set_speed(cs); -} - -SetBool::SetBool(bool* b, bool setting) { - boolean = b; - old_setting = *b; - new_setting = setting; -} - -void SetBool::doUndo() { - *boolean = old_setting; -} - -void SetBool::doRedo() { - *boolean = new_setting; -} - -SetSelectionsCommand::SetSelectionsCommand(Sequence *s, - const QVector &old_data, - const QVector &new_data) : - seq_(s), - old_data_(old_data), - new_data_(new_data) -{ - -} - -void SetSelectionsCommand::doUndo() { - seq_->SetSelections(old_data_); -} - -void SetSelectionsCommand::doRedo() { - seq_->SetSelections(new_data_); -} - -EditSequenceCommand::EditSequenceCommand(Media* i, SequencePtr s) { - item = i; - seq = s; - old_name = s->name(); - old_width = s->width(); - old_height = s->height(); - old_frame_rate = s->frame_rate(); - old_audio_frequency = s->audio_frequency(); - old_audio_layout = s->audio_layout(); -} - -void EditSequenceCommand::doUndo() { - seq->set_name(old_name); - seq->set_width(old_width); - seq->set_height(old_height); - seq->set_frame_rate(old_frame_rate); - seq->set_audio_frequency(old_audio_frequency); - seq->set_audio_layout(old_audio_layout); - update(); -} - -void EditSequenceCommand::doRedo() { - seq->set_name(name); - seq->set_width(width); - seq->set_height(height); - seq->set_frame_rate(frame_rate); - seq->set_audio_frequency(audio_frequency); - seq->set_audio_layout(audio_layout); - update(); -} - -void EditSequenceCommand::update() { - // Update sequence's tooltip - item->update_tooltip(); - - QVector all_clips = seq->GetAllClips(); - for (int i=0;irefresh(); - } - } -} - -SetInt::SetInt(int* pointer, int new_value) { - p = pointer; - oldval = *pointer; - newval = new_value; -} - -void SetInt::doUndo() { - *p = oldval; - -} - -void SetInt::doRedo() { - *p = newval; -} - -SetString::SetString(QString* pointer, QString new_value) { - p = pointer; - oldval = *pointer; - newval = new_value; -} - -void SetString::doUndo() { - *p = oldval; - -} - -void SetString::doRedo() { - *p = newval; -} - -void CloseAllClipsCommand::doUndo() { - redo(); -} - -void CloseAllClipsCommand::doRedo() { - QVector sequences = olive::project_model.GetAllSequences(); - - for (int i=0;ito_sequence()->Close(); - } -} - -UpdateFootageTooltip::UpdateFootageTooltip(Media *i) { - item = i; -} - -void UpdateFootageTooltip::doUndo() { - redo(); -} - -void UpdateFootageTooltip::doRedo() { - item->update_tooltip(); -} - -MoveEffectCommand::MoveEffectCommand() {} - -void MoveEffectCommand::doUndo() { - clip->effects.move(to, from); - -} - -void MoveEffectCommand::doRedo() { - clip->effects.move(from, to); -} - -RemoveClipsFromClipboard::RemoveClipsFromClipboard(int index) { - pos = index; - done = false; -} - -RemoveClipsFromClipboard::~RemoveClipsFromClipboard() {} - -void RemoveClipsFromClipboard::doUndo() { - olive::clipboard.Insert(pos, clip); - done = false; -} - -void RemoveClipsFromClipboard::doRedo() { - clip = std::static_pointer_cast(olive::clipboard.Get(pos)); - olive::clipboard.RemoveAt(pos); - done = true; -} - -RenameClipCommand::RenameClipCommand(Clip *clip, QString new_name) -{ - clip_ = clip; - old_name_ = clip_->name(); - new_name_ = new_name; -} - -void RenameClipCommand::doUndo() { - clip_->set_name(old_name_); -} - -void RenameClipCommand::doRedo() { - clip_->set_name(new_name_); -} - -SetPointer::SetPointer(void **pointer, void *data) { - p = pointer; - new_data = data; -} - -void SetPointer::doUndo() { - *p = old_data; -} - -void SetPointer::doRedo() { - old_data = *p; - *p = new_data; -} - -void ReloadEffectsCommand::doUndo() { - redo(); -} - -void ReloadEffectsCommand::doRedo() { - panel_effect_controls->Reload(); -} - -RippleAction::RippleAction(Sequence *is, long ipoint, long ilength, const QVector &iignore) : - s(is), - point(ipoint), - length(ilength), - ignore(iignore) -{ -} - -void RippleAction::doUndo() { - ca->undo(); - delete ca; -} - -void RippleAction::doRedo() { - ca = new ComboAction(); - - QVector all_clips = s->GetAllClips(); - - for (int i=0;itimeline_in() >= point) { - s->MoveClip(c, - ca, - length, - length, - 0, - c->track(), - false, - true); - } - } - } - ca->redo(); -} - -SetDouble::SetDouble(double* pointer, double old_value, double new_value) : - p(pointer), - oldval(old_value), - newval(new_value) -{ -} - -void SetDouble::doUndo() { - *p = oldval; - -} - -void SetDouble::doRedo() { - *p = newval; -} - -SetQVariant::SetQVariant(QVariant *itarget, const QVariant &iold, const QVariant &inew) : - target(itarget), - old_val(iold), - new_val(inew) -{ -} - -void SetQVariant::doUndo() { - *target = old_val; -} - -void SetQVariant::doRedo() { - *target = new_val; -} - -SetLong::SetLong(long *pointer, long old_value, long new_value) { - p = pointer; - oldval = old_value; - newval = new_value; -} - -void SetLong::doUndo() { - *p = oldval; - -} - -void SetLong::doRedo() { - *p = newval; -} - -KeyframeAdd::KeyframeAdd(EffectField *ifield, int ii) : - field(ifield), - index(ii), - key(ifield->keyframes.at(ii)), - done(true) -{ -} - -void KeyframeAdd::doUndo() { - field->keyframes.removeAt(index); - done = false; -} - -void KeyframeAdd::doRedo() { - if (!done) { - field->keyframes.insert(index, key); - done = true; - } -} - -SetIsKeyframing::SetIsKeyframing(NodeIO *irow, bool ib) { - row = irow; - b = ib; -} - -void SetIsKeyframing::doUndo() { - row->SetKeyframingInternal(!b); -} - -void SetIsKeyframing::doRedo() { - row->SetKeyframingInternal(b); -} - -RefreshClips::RefreshClips(Media *m) : - media(m) -{ -} - -void RefreshClips::doUndo() { - redo(); -} - -void RefreshClips::doRedo() { - // close any clips currently using this media - QVector all_sequences = olive::project_model.GetAllSequences(); - for (int i=0;i sequence_clips = all_sequences.at(i)->to_sequence().get()->GetAllClips(); - - for (int j=0;jmedia() == media || media == nullptr) { - c->replaced = true; - c->refresh(); - } - } - } -} - -void UpdateViewer::doUndo() { - redo(); -} - -void UpdateViewer::doRedo() { - panel_sequence_viewer->viewer_widget()->frame_update(); -} - -SetEffectData::SetEffectData(OldEffectNode *e, const QByteArray &s) { - effect = e; - data = s; -} - -void SetEffectData::doUndo() { - effect->load_from_string(old_data); - - old_data.clear(); -} - -void SetEffectData::doRedo() { - old_data = effect->save_to_string(); - - effect->load_from_string(data); -} - -OliveAction::OliveAction(bool iset_window_modified) { - set_window_modified = iset_window_modified; -} - -OliveAction::~OliveAction() {} - -void OliveAction::undo() { - doUndo(); - - if (set_window_modified) { - olive::Global->set_modified(old_window_modified); - } -} - -void OliveAction::redo() { - doRedo(); - - if (set_window_modified) { - - // store current modified state - old_window_modified = olive::Global->is_modified(); - - // set modified to true - olive::Global->set_modified(true); - - } -} - -KeyframeDataChange::KeyframeDataChange(EffectField *field) : - field_(field), - done_(true) -{ - old_keys_ = field_->keyframes; - old_persistent_data_ = field_->persistent_data_; -} - -void KeyframeDataChange::SetNewKeyframes() -{ - new_keys_ = field_->keyframes; - new_persistent_data_ = field_->persistent_data_; -} - -void KeyframeDataChange::doUndo() -{ - field_->keyframes = old_keys_; - field_->persistent_data_ = old_persistent_data_; - done_ = false; -} - -void KeyframeDataChange::doRedo() -{ - if (!done_) { - field_->keyframes = new_keys_; - field_->persistent_data_ = new_persistent_data_; - done_ = true; - } -} - -SetPointF::SetPointF(QPointF *pointer, const QPointF &old_val, const QPointF &new_val) : - pointer_(pointer), - old_val_(old_val), - new_val_(new_val) -{ -} - -void SetPointF::doUndo() -{ - *pointer_ = old_val_; -} - -void SetPointF::doRedo() -{ - *pointer_ = new_val_; -} diff --git a/undo/undo.h b/undo/undo.h deleted file mode 100644 index ebfa8b53c..000000000 --- a/undo/undo.h +++ /dev/null @@ -1,634 +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 UNDO_H -#define UNDO_H - -#include -#include -#include -#include -#include -#include - -#include "comboaction.h" - -#include "nodes/oldeffectnode.h" -#include "timeline/marker.h" -#include "timeline/selection.h" -#include "effects/keyframe.h" - -class Clip; -using ClipPtr = std::shared_ptr; - -class Sequence; -using SequencePtr = std::shared_ptr; - -class Media; -using MediaPtr = std::shared_ptr; - -class OldEffectNode; -using OldEffectNodePtr = std::shared_ptr; - -class Transition; -using TransitionPtr = std::shared_ptr; - -class NodeIO; -class EffectField; - -class OliveAction : public QUndoCommand { -public: - OliveAction(bool iset_window_modified = true); - virtual ~OliveAction() override; - - virtual void undo() override; - virtual void redo() override; - - virtual void doUndo() = 0; - virtual void doRedo() = 0; -private: - /** - * @brief Setting whether to change the windowModified state of MainWindow - */ - bool set_window_modified; - - /** - * @brief Cache previous window modified value to return to if the user undoes this action - */ - bool old_window_modified; -}; - -class MoveClipAction : public OliveAction { -public: - MoveClipAction(ClipPtr c, long iin, long iout, long iclip_in, Track* itrack, bool irelative); - virtual void doUndo() override; - virtual void doRedo() override; -private: - ClipPtr clip; - - long old_in; - long old_out; - long old_clip_in; - Track* old_track; - - long new_in; - long new_out; - long new_clip_in; - Track* new_track; - - bool relative; - - bool done; -}; - -class RippleAction : public OliveAction { -public: - RippleAction(Sequence* is, long ipoint, long ilength, const QVector &iignore); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Sequence* s; - long point; - long length; - QVector ignore; - ComboAction* ca; -}; - -class DeleteClipAction : public OliveAction { -public: - DeleteClipAction(Clip* clip); - virtual void doUndo() override; - virtual void doRedo() override; -private: - ClipPtr clip_; - QVector clips_linked_to_this_one_; - bool done_; -}; - -class AddEffectCommand : public OliveAction { -public: - AddEffectCommand(Clip* c, OldEffectNodePtr e, NodeType m, int insert_pos = -1); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Clip* clip; - NodeType meta; - OldEffectNodePtr ref; - int pos; - bool done; -}; - -class AddTransitionCommand : public OliveAction { -public: - AddTransitionCommand(Clip* iopen, Clip* iclose, TransitionPtr copy, NodeType itransition, int ilength); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Clip* open_; - Clip* close_; - TransitionPtr transition_to_copy_; - NodeType transition_meta_; - int length_; - TransitionPtr old_open_transition_; - TransitionPtr old_close_transition_; - TransitionPtr new_transition_ref_; -}; - -class ModifyTransitionCommand : public OliveAction { -public: - ModifyTransitionCommand(TransitionPtr t, long ilength); - virtual void doUndo() override; - virtual void doRedo() override; -private: - TransitionPtr transition_ref_; - long new_length_; - long old_length_; -}; - -class DeleteTransitionCommand : public OliveAction { -public: - DeleteTransitionCommand(TransitionPtr t); - virtual void doUndo() override; - virtual void doRedo() override; -private: - TransitionPtr transition_ref_; - Clip* opened_clip_; - Clip* closed_clip_; -}; - -class SetTimelineInOutCommand : public OliveAction { -public: - SetTimelineInOutCommand(Sequence* s, bool enabled, long in, long out); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Sequence* seq; - - bool old_enabled; - long old_in; - long old_out; - - bool new_enabled; - long new_in; - long new_out; -}; - -class AddMediaCommand : public OliveAction { -public: - AddMediaCommand(MediaPtr iitem, Media* iparent); - virtual void doUndo() override; - virtual void doRedo() override; -private: - MediaPtr item; - Media* parent; - bool done_; -}; - -class DeleteMediaCommand : public OliveAction { -public: - DeleteMediaCommand(MediaPtr i); - virtual void doUndo() override; - virtual void doRedo() override; -private: - MediaPtr item; - Media* parent; -}; - -class AddClipCommand : public OliveAction { -public: - AddClipCommand(const QVector& add); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Track* track_; - QVector clips_; - bool done_; -}; - -class LinkCommand : public OliveAction { -public: - LinkCommand(const QVector &clips, bool link); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QVector clips_; - bool link_; - QVector< QVector > old_links_; -}; - -class CheckboxCommand : public OliveAction { -public: - CheckboxCommand(QCheckBox* b); - virtual ~CheckboxCommand() override; - virtual void doUndo() override; - virtual void doRedo() override; -private: - QCheckBox* box; - bool checked; - bool done; -}; - -class ReplaceMediaCommand : public OliveAction { -public: - ReplaceMediaCommand(MediaPtr, QString); - virtual void doUndo() override; - virtual void doRedo() override; -private: - MediaPtr item; - QString old_filename; - QString new_filename; - void replace(QString& filename); -}; - -class ReplaceClipMediaCommand : public OliveAction { -public: - ReplaceClipMediaCommand(Media *, Media *, bool); - virtual void doUndo() override; - virtual void doRedo() override; - QVector clips; -private: - Media* old_media; - Media* new_media; - bool preserve_clip_ins; - QVector old_clip_ins; - void replace(bool undo); -}; - -class EffectDeleteCommand : public OliveAction { -public: - EffectDeleteCommand(OldEffectNode* e); - virtual void doUndo() override; - virtual void doRedo() override; -private: - OldEffectNode* effect_; - OldEffectNodePtr deleted_obj_; - Clip* parent_clip_; - int index_; -}; - -class MediaMove : public OliveAction { -public: - MediaMove(); - QVector items; - Media* to; - virtual void doUndo() override; - virtual void doRedo() override; -private: - QVector froms; -}; - -class MediaRename : public OliveAction { -public: - MediaRename(Media* iitem, QString to); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Media* item; - QString from; - QString to; -}; - -class KeyframeDelete : public OliveAction { -public: - KeyframeDelete(EffectField* ifield, int iindex); - virtual void doUndo() override; - virtual void doRedo() override; -private: - EffectField* field; - int index; - bool done; - EffectKeyframe deleted_key; -}; - -class KeyframeAdd : public OliveAction { -public: - KeyframeAdd(EffectField* ifield, int ii); - virtual void doUndo() override; - virtual void doRedo() override; -private: - EffectField* field; - int index; - EffectKeyframe key; - bool done; -}; - -enum SetClipPropertyType { - kSetClipPropertyAutoscale, - kSetClipPropertyReversed, - kSetClipPropertyMaintainAudioPitch, - kSetClipPropertyEnabled -}; - -class SetClipProperty : public OliveAction { -public: - SetClipProperty(SetClipPropertyType type); - virtual void doUndo() override; - virtual void doRedo() override; - void AddSetting(QVector clips, bool setting); - void AddSetting(Clip *c, bool setting); -private: - SetClipPropertyType type_; - QVector clips_; - QVector setting_; - QVector old_setting_; - void MainLoop(bool undo); -}; - -class AddMarkerAction : public OliveAction { -public: - AddMarkerAction(QVector* m, long t, QString n); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QVector* active_array; - long time; - QString name; - QString old_name; - int index; -}; - -class MoveMarkerAction : public OliveAction { -public: - MoveMarkerAction(Marker* m, long o, long n); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Marker* marker; - long old_time; - long new_time; -}; - -class DeleteMarkerAction : public OliveAction { -public: - DeleteMarkerAction(QVector* m); - virtual void doUndo() override; - virtual void doRedo() override; - QVector markers; -private: - QVector* active_array; - QVector copies; - bool sorted; -}; - -class SetSpeedAction : public OliveAction { -public: - SetSpeedAction(Clip* c, double speed); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Clip* clip; - double old_speed; - double new_speed; -}; - -class SetBool : public OliveAction { -public: - SetBool(bool* b, bool setting); - virtual void doUndo() override; - virtual void doRedo() override; -private: - bool* boolean; - bool old_setting; - bool new_setting; -}; - -class SetSelectionsCommand : public OliveAction { -public: - SetSelectionsCommand(Sequence* s, const QVector& old_data, const QVector& new_data); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QVector old_data_; - QVector new_data_; - Sequence* seq_; -}; - -class EditSequenceCommand : public OliveAction { -public: - EditSequenceCommand(Media *i, SequencePtr s); - virtual void doUndo() override; - virtual void doRedo() override; - void update(); - - QString name; - int width; - int height; - double frame_rate; - int audio_frequency; - int audio_layout; -private: - Media* item; - SequencePtr seq; - - QString old_name; - int old_width; - int old_height; - double old_frame_rate; - int old_audio_frequency; - int old_audio_layout; -}; - -class SetInt : public OliveAction { -public: - SetInt(int* pointer, int new_value); - virtual void doUndo() override; - virtual void doRedo() override; -private: - int* p; - int oldval; - int newval; -}; - -class SetLong : public OliveAction { -public: - SetLong(long* pointer, long old_value, long new_value); - virtual void doUndo() override; - virtual void doRedo() override; -private: - long* p; - long oldval; - long newval; -}; - -class SetDouble : public OliveAction { -public: - SetDouble(double* pointer, double old_value, double new_value); - virtual void doUndo() override; - virtual void doRedo() override; -private: - double* p; - double oldval; - double newval; -}; - -class SetString : public OliveAction { -public: - SetString(QString* pointer, QString new_value); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QString* p; - QString oldval; - QString newval; -}; - -class SetPointF : public OliveAction { -public: - SetPointF(QPointF* pointer, const QPointF& old_val, const QPointF& new_val); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QPointF* pointer_; - QPointF old_val_; - QPointF new_val_; -}; - -class CloseAllClipsCommand : public OliveAction { -public: - virtual void doUndo() override; - virtual void doRedo() override; -}; - -class UpdateFootageTooltip : public OliveAction { -public: - UpdateFootageTooltip(Media* i); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Media* item; -}; - -class MoveEffectCommand : public OliveAction { -public: - MoveEffectCommand(); - virtual void doUndo() override; - virtual void doRedo() override; - Clip* clip; - int from; - int to; -}; - -class RemoveClipsFromClipboard : public OliveAction { -public: - RemoveClipsFromClipboard(int index); - virtual ~RemoveClipsFromClipboard() override; - virtual void doUndo() override; - virtual void doRedo() override; -private: - int pos; - ClipPtr clip; - bool done; -}; - -class RenameClipCommand : public OliveAction { -public: - RenameClipCommand(Clip* clip, QString new_name); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QString old_name_; - QString new_name_; - Clip* clip_; -}; - -class SetPointer : public OliveAction { -public: - SetPointer(void** pointer, void* data); - virtual void doUndo() override; - virtual void doRedo() override; -private: - bool old_changed; - void** p; - void* new_data; - void* old_data; -}; - -class ReloadEffectsCommand : public OliveAction { -public: - virtual void doUndo() override; - virtual void doRedo() override; -}; - -class SetQVariant : public OliveAction { -public: - SetQVariant(QVariant* itarget, const QVariant& iold, const QVariant& inew); - virtual void doUndo() override; - virtual void doRedo() override; -private: - QVariant* target; - QVariant old_val; - QVariant new_val; -}; - -class SetIsKeyframing : public OliveAction { -public: - SetIsKeyframing(NodeIO* irow, bool ib); - virtual void doUndo() override; - virtual void doRedo() override; -private: - NodeIO* row; - bool b; -}; - -class RefreshClips : public OliveAction { -public: - RefreshClips(Media* m); - virtual void doUndo() override; - virtual void doRedo() override; -private: - Media* media; -}; - -class UpdateViewer : public OliveAction { -public: - virtual void doUndo() override; - virtual void doRedo() override; -}; - -class SetEffectData : public OliveAction { -public: - SetEffectData(OldEffectNode* e, const QByteArray &s); - virtual void doUndo() override; - virtual void doRedo() override; -private: - OldEffectNode* effect; - QByteArray data; - QByteArray old_data; -}; - -class KeyframeDataChange : public OliveAction { -public: - KeyframeDataChange(EffectField* field); - - void SetNewKeyframes(); - - virtual void doUndo() override; - virtual void doRedo() override; - -private: - EffectField* field_; - QVector old_keys_; - QVector new_keys_; - QVariant old_persistent_data_; - QVariant new_persistent_data_; - bool done_; -}; - -#endif // UNDO_H diff --git a/undo/undostack.cpp b/undo/undostack.cpp deleted file mode 100644 index 3fa41abdc..000000000 --- a/undo/undostack.cpp +++ /dev/null @@ -1,23 +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 "undostack.h" - -QUndoStack olive::undo_stack; diff --git a/undo/undostack.h b/undo/undostack.h deleted file mode 100644 index a2312642e..000000000 --- a/undo/undostack.h +++ /dev/null @@ -1,33 +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 UNDOSTACK_H -#define UNDOSTACK_H - -#include - -namespace olive { -/** - * @brief Global undo stack object - */ -extern QUndoStack undo_stack; -} - -#endif // UNDOSTACK_H