Compare commits
214 Commits
cherry-pic
...
refactorin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85e0e9808e | ||
|
|
20663d7b33 | ||
|
|
5ef795f509 | ||
|
|
2e2f488c90 | ||
|
|
9b28ddbe48 | ||
|
|
35ec064a62 | ||
|
|
f46dea749c | ||
|
|
2d6b84bba6 | ||
|
|
2a49f801e2 | ||
|
|
a267685415 | ||
|
|
c411a3c523 | ||
|
|
9ef2b9ba4f | ||
|
|
40d735e8da | ||
|
|
c7ca9f27ac | ||
|
|
5da2eb92f1 | ||
|
|
81707e9411 | ||
|
|
d257eb406c | ||
|
|
53c3ca5127 | ||
|
|
1eed118ece | ||
|
|
ed0f5102cd | ||
|
|
ff9bad0740 | ||
|
|
4608ca1dda | ||
|
|
2f92381b96 | ||
|
|
381b239532 | ||
|
|
9edcb7cc02 | ||
|
|
affe004127 | ||
|
|
02807c83b7 | ||
|
|
6d1938ab4e | ||
|
|
6954c6573b | ||
|
|
cafcd9339f | ||
|
|
ab67e058d5 | ||
|
|
30b94d484a | ||
|
|
ae7f426b69 | ||
|
|
f67f33d461 | ||
|
|
ddcaac19b4 | ||
|
|
6b9d68f47a | ||
|
|
ae9cedfed8 | ||
|
|
0f2c1f7f9d | ||
|
|
4a6ed227d7 | ||
|
|
6af0aceb17 | ||
|
|
cbe38d9efc | ||
|
|
14b5b4d8f3 | ||
|
|
17ed62f04c | ||
|
|
e00eadcc36 | ||
|
|
1efa3c1d38 | ||
|
|
bc1261f439 | ||
|
|
9e2b86bd6a | ||
|
|
2e17b6ab59 | ||
|
|
2f04ad1aac | ||
|
|
ec4182cac7 | ||
|
|
fa9e76c4c5 | ||
|
|
00d500f845 | ||
|
|
f013aae85e | ||
|
|
574c232695 | ||
|
|
1be0881b44 | ||
|
|
71afde5f0b | ||
|
|
b47c796bf2 | ||
|
|
b39d74ea65 | ||
|
|
fe1b3a4086 | ||
|
|
0538af2954 | ||
|
|
a8573ae1b4 | ||
|
|
0da7c8bd94 | ||
|
|
c02af737b2 | ||
|
|
4610d9c6c1 | ||
|
|
da90b478c5 | ||
|
|
dcfad98f8f | ||
|
|
2a26ee136b | ||
|
|
e85c4c8940 | ||
|
|
2cd963d24e | ||
|
|
1e0200da94 | ||
|
|
b1dfe4678c | ||
|
|
a2c923b428 | ||
|
|
7c13c5f63b | ||
|
|
e6995fffbc | ||
|
|
2aaa510110 | ||
|
|
9797308b17 | ||
|
|
8c35c8743f | ||
|
|
6f05726cc1 | ||
|
|
90ee526da0 | ||
|
|
3f39cf9dce | ||
|
|
c6f2b5f686 | ||
|
|
7c85fd3eca | ||
|
|
60dd7e20d0 | ||
|
|
0528edc164 | ||
|
|
57aa0e9126 | ||
|
|
c2ab685110 | ||
|
|
92546cbd4b | ||
|
|
c561f54977 | ||
|
|
62fea41c79 | ||
|
|
21701e6231 | ||
|
|
a48e231708 | ||
|
|
495c751675 | ||
|
|
964aed970d | ||
|
|
42627cfe39 | ||
|
|
3c91085cce | ||
|
|
bd098265d0 | ||
|
|
6caee75b8f | ||
|
|
34e009270a | ||
|
|
2c2c353327 | ||
|
|
96a29bed85 | ||
|
|
bc560c1bc5 | ||
|
|
e620ba6e21 | ||
|
|
594bb71802 | ||
|
|
df713257bd | ||
|
|
c4e95f4ee6 | ||
|
|
98717ef6aa | ||
|
|
d38050bf6d | ||
|
|
84bc98dccf | ||
|
|
82c2d74c1c | ||
|
|
6ef1962f83 | ||
|
|
557fb3ea0b | ||
|
|
b711b8125e | ||
|
|
6069ce084b | ||
|
|
28a2b7fa96 | ||
|
|
7ea11da975 | ||
|
|
74343fc4ad | ||
|
|
5388e17acd | ||
|
|
756d87e074 | ||
|
|
072944c953 | ||
|
|
6ef3bb63cc | ||
|
|
e329d11fed | ||
|
|
e01ad25458 | ||
|
|
36d560caf6 | ||
|
|
b7e0a9de00 | ||
|
|
42bface06d | ||
|
|
7e39c2b2ff | ||
|
|
420395edc8 | ||
|
|
d8b10cd44d | ||
|
|
1efe305ca2 | ||
|
|
0ef794e39a | ||
|
|
78701001d8 | ||
|
|
5813a31685 | ||
|
|
428196f276 | ||
|
|
c640110c7a | ||
|
|
a717b1b7ab | ||
|
|
e4889dc7fe | ||
|
|
7f874349bc | ||
|
|
72e99aaf5f | ||
|
|
c3b67e41c3 | ||
|
|
5f4f997774 | ||
|
|
0cbc9b8ae8 | ||
|
|
033c9e02b1 | ||
|
|
d62751f74d | ||
|
|
e4d3bd9a34 | ||
|
|
bc083fabe4 | ||
|
|
69b1c53d0e | ||
|
|
27042c59e0 | ||
|
|
2499a8cb2a | ||
|
|
88083dae38 | ||
|
|
173a31e8f7 | ||
|
|
34f38ea16a | ||
|
|
0c76bc4ad6 | ||
|
|
d270407690 | ||
|
|
38eaf619ef | ||
|
|
9705319ad5 | ||
|
|
8946f86005 | ||
|
|
d59d1c773f | ||
|
|
658688fe6b | ||
|
|
8fe051f21e | ||
|
|
cb432dc3b7 | ||
|
|
a03f67fc3c | ||
|
|
bde898da80 | ||
|
|
044fb8b3f7 | ||
|
|
5e3005cb90 | ||
|
|
b5bd0f7ff7 | ||
|
|
7954d56f4c | ||
|
|
f50a792176 | ||
|
|
2da75f88ec | ||
|
|
563e40bc56 | ||
|
|
8403250130 | ||
|
|
92619653f7 | ||
|
|
55043544bf | ||
|
|
730e0ff663 | ||
|
|
c51cf04e33 | ||
|
|
d5efda3811 | ||
|
|
1e97ddc90d | ||
|
|
6ac3368bef | ||
|
|
124d5075f9 | ||
|
|
b0dbb8aef2 | ||
|
|
7d5a55b5e6 | ||
|
|
ccf85b0fe2 | ||
|
|
245c23df89 | ||
|
|
4700403844 | ||
|
|
3dd55b31f9 | ||
|
|
a254a65994 | ||
|
|
092439a1fe | ||
|
|
42c57fd01a | ||
|
|
c6e878daf3 | ||
|
|
57f090a0c2 | ||
|
|
4381f2976a | ||
|
|
b5a933e558 | ||
|
|
74505eed37 | ||
|
|
8732cad923 | ||
|
|
a9c346817a | ||
|
|
1373516253 | ||
|
|
3887249b21 | ||
|
|
3896d5d0d5 | ||
|
|
100a68c7db | ||
|
|
2d998e5f52 | ||
|
|
997db532ce | ||
|
|
bafa25b5bb | ||
|
|
4474c3bdce | ||
|
|
b5c101970a | ||
|
|
51e4829d89 | ||
|
|
6ea3e0483c | ||
|
|
5306c68f87 | ||
|
|
07f7357724 | ||
|
|
e8ef2ff696 | ||
|
|
4afcb530a4 | ||
|
|
efb72f3bf9 | ||
|
|
eb3b733dc8 | ||
|
|
b39703956a | ||
|
|
04e1945deb | ||
|
|
de770d924b |
@@ -2,10 +2,10 @@ project(kdenlive)
|
||||
|
||||
# An odd patch version number means development version, while an even one means
|
||||
# stable release. An additional number can be used for bugfix-only releases.
|
||||
set(KDENLIVE_VERSION 0.9.7)
|
||||
set(KDENLIVE_VERSION 0.9.9)
|
||||
|
||||
# Minimum versions of main dependencies.
|
||||
set(LIBMLT_MIN_VERSION 0.8.8)
|
||||
set(LIBMLT_MIN_VERSION 0.9.0)
|
||||
set(QT_MIN_VERSION 4.5.0)
|
||||
set(KDE_MIN_VERSION 4.3.0)
|
||||
|
||||
@@ -78,18 +78,12 @@ macro_log_feature(LIBMLT_FOUND
|
||||
add_subdirectory(data)
|
||||
macro_optional_add_subdirectory(doc)
|
||||
add_subdirectory(effects)
|
||||
add_subdirectory(export)
|
||||
add_subdirectory(icons)
|
||||
add_subdirectory(lumas)
|
||||
add_subdirectory(man)
|
||||
add_subdirectory(plugins)
|
||||
macro_optional_add_subdirectory(po)
|
||||
add_subdirectory(renderer)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(thumbnailer)
|
||||
add_subdirectory(titles)
|
||||
add_subdirectory(testingArea)
|
||||
|
||||
macro_display_feature_log()
|
||||
|
||||
configure_file(config-kdenlive.h.cmake config-kdenlive.h @ONLY)
|
||||
|
||||
add_subdirectory(producers)
|
||||
|
||||
206
ChangeLog
@@ -1,206 +0,0 @@
|
||||
0.9.6
|
||||
* Fix keyframes when cutting a clip / undoing a clip cut
|
||||
* Warn before overwriting .mlt stabilized file
|
||||
* Fix monitor confusion (clip monitor sometimes playing timeline,...)
|
||||
* Fix the Mono to Stereo effect UI
|
||||
* Fix proxy of playlist having wrong aspect ratio in some locales
|
||||
* Fix transition widget not correctly updated when resizing a transition
|
||||
* Fix DVD chapters broken when using an intro movie
|
||||
* Fix error message (No matching profile) poping up in render widget when everything was ok
|
||||
* Fix clip keyframes not showing on project load
|
||||
* Fix bug when moving guide (was not moving to the correct place)
|
||||
* Fix project corruption (wrong character) caused by some clip's metadata
|
||||
* Fix possible crash on track deletion
|
||||
* Fix timeline corruption when using spacer tool or overwrite edit mode
|
||||
* Fix possible crash when editing speed effect
|
||||
* Fix transition losing all its properties when moved
|
||||
* Fix crash when pressing del when editing animation in title widget
|
||||
* Fix crash when doing quick clip resize
|
||||
* Fix corruption when groups where overlapping
|
||||
* Fix corruption when adding a title clip where a transition already existed
|
||||
* Fix timeline preview corruption with some transitions
|
||||
|
||||
0.9.4
|
||||
* Fix color parameter in some effects not working correctly (#2644)
|
||||
* Fix V4l licensing issue (#2632)
|
||||
* Fix keyframes lost / broken when pasting an effect
|
||||
|
||||
0.9.2
|
||||
* Fix firewire capture (preview not showing)
|
||||
* Fix freeze when reloading previously missing clip
|
||||
* Fade effects lost when moving / resizing clip
|
||||
* Undoing change in clip crop start breaking clip
|
||||
* Make disabling of track effects possible
|
||||
* Fix slideshow clips not working
|
||||
* Fix crash on composite transition
|
||||
* Fix crash when opening stop motion widget
|
||||
* Fix rendering of projects created in another locale
|
||||
|
||||
0.9
|
||||
* Fix monitor effect scene sometimes forcing monitor minimum size
|
||||
* Improve detection of locale issues (default to POSIX when there is a locale conflict on the system)
|
||||
* Improve timeline operation for small clips (disable resizing, only allow move)
|
||||
* Add background color parameter to "Rotate" and "Pan and Zoom" effects
|
||||
* Allow to scroll using the mouse wheel in monitor editing scene
|
||||
* Zoom to mouse when using CTRL + mouse wheel in monitor editing scene
|
||||
* Add support for new slope mode in "Color Selection" effect to allow smooth alpha transition
|
||||
* Introduce grouping of effects; groups can also be saved
|
||||
* Allow dragging an effect to another clip/track
|
||||
* Allow record monitor to go fullscreen
|
||||
* Image sequences can now start at an arbitrary frame (http://kdenlive.org/mantis/view.php?id=2508)
|
||||
* Add automatic clip alignment based on audio (experimental, has to be manually enabled)s
|
||||
* Allow archiving for offline use (only archive proxies)
|
||||
* Offline editing: Allow working on project with only proxies available (http://kdenlive.org/mantis/view.php?id=2509)
|
||||
* Allow rendering to another framerate
|
||||
* Check for missing locale and ask to install instead of opening corrupted project
|
||||
* Allow to open project files manually extracted from archived project
|
||||
* Support dropping a folder in the project tree (http://kdenlive.org/mantis/view.php?id=1288)
|
||||
* Add "select all clips in track" and "select all clips in timeline" features (http://kdenlive.org/mantis/view.php?id=1950)
|
||||
* Put audio effects in subcategories to avoid uberlong menus (http://kdenlive.org/mantis/view.php?id=2436)
|
||||
* Support for project metadata (can be embedded in rendered file)
|
||||
* Add Online Resource Widget allowing easy search and download of online services (freesound, openclipart, archive.org)
|
||||
* Introduce MLT clip analysis to get auto normalize data in sox gain effect
|
||||
* Connect recording to audio scopes
|
||||
* Add audio only recording (works while playing)
|
||||
* Add extract zone function: part of clip is copied to new file without re-encoding
|
||||
* Introduce generic job framework to process clips
|
||||
* Improve the Choose color widget: Use less space and make it easier to pick the average color value from an area
|
||||
* Add GUI for effect Dynamic Text: Allows to display timecode/framecount and other data
|
||||
* Rework effect stack: All effects are shown at once and are collapsible
|
||||
* Add two different video stabilizers
|
||||
* Add IIR Blur GUI
|
||||
* Add date column to project tree
|
||||
|
||||
* Fix clip move sometimes giving error when it should work
|
||||
* Fix custom effects not considering capital letters in name (http://kdenlive.org/mantis/view.php?id=2580)
|
||||
* Fix script rendering when script name contains whitespace
|
||||
* Ensure clip in project tree is visible after rename (scroll if necessary) (http://kdenlive.org/mantis/view.php?id=2563)
|
||||
* Fix monitor scene never resetting scrollbars
|
||||
* Fix issues with transitions when inserting track (http://kdenlive.org/mantis/view.php?id=2477)
|
||||
* Fix some GUI elements not responding to color theme change
|
||||
* Do not hide render profile list when there is only one item to avoid confusion (http://kdenlive.org/mantis/view.php?id=2543)
|
||||
* Fix consecutive error messages overwriting each other (http://www.kdenlive.org/mantis/view.php?id=2519)
|
||||
* Fix crash when editing properties of several missing clips
|
||||
* Fix vectorscope for 24b RGB images (http://kdenlive.org/mantis/view.php?id=2478)
|
||||
* Fix archiving sometimes not saving playlist clips and subclips (http://kdenlive.org/mantis/view.php?id=2475)
|
||||
* Fix archiving feature not saving playlist clips and slowmotion clips inside them (http://kdenlive.org/mantis/view.php?id=2475)
|
||||
* Fix crash recovery feature issues with long or non UTF-8 filenames (http://kdenlive.org/mantis/view.php?id=2441, http://kdenlive.org/mantis/view.php?id=2450)
|
||||
* Fix rendering jobs sometimes not starting
|
||||
* Fix crash on proxy creation (concurrency issue) (http://kdenlive.org/mantis/view.php?id=2471)
|
||||
* Fix zone playing (http://kdenlive.org/mantis/view.php?id=2468)
|
||||
* Fix click on monitor sometimes not triggering play
|
||||
* Fix crash when moving a folder and a clip in project tree (http://kdenlive.org/mantis/view.php?id=2458)
|
||||
* Fix color change not working in title widget (http://kdenlive.org/mantis/view.php?id=2459)
|
||||
* Fix slideshow clips created with invalid frame duration
|
||||
* Fix profile warning with clips that have 1088 pixels height
|
||||
* Fix unnecessary proxy reload on document load
|
||||
* Fix detection of broken render scripts
|
||||
|
||||
0.8.2.1
|
||||
* Fix title text oultine transparency not working
|
||||
* Make titler window fit on smaller resolutions (1024x768)
|
||||
* Fix corruption when undoing and redoing a transition add + move
|
||||
* Fix possible crash in thumbnails
|
||||
* Fix possible crashes in clip transcoding and improve feedback when failing
|
||||
* Various small optimizations (unnecessary clip reloads)
|
||||
* Fix timecode widget hard to edit and sometimes giving random values
|
||||
* Workaround locale issue ahappening when system C locale and Qt's locale did not give the same numeric separator
|
||||
* Fix audio thumbnail concurrency issue
|
||||
* Fix various video thumbnails issues (don't load several times the same thumb, load all of them, ...)
|
||||
* Fix crash when opening a file dialog on KDE < 4.5
|
||||
* Fix various proxy issues (missing extension, concurrency, disabling broken proxy, ...)
|
||||
* Fix startup crash caused by invalid parsing of v4l data
|
||||
* Fix project tree disabled after loading some projects / creating new one
|
||||
* Fix corrupted timeline / monitor timecode
|
||||
* Fix search path for Luma files when missing
|
||||
|
||||
0.8.2
|
||||
* Load zone thumbnails from disk if available.
|
||||
* Optimise document loading.
|
||||
* In case of missing or invalid clips, open only one dialog box instead of one for each clip.
|
||||
* Display proxy creation progress in project tree.
|
||||
* Improve way of picking an average color of an area.
|
||||
* Make audio bitrate in render dialog selectable.
|
||||
* Add support for handling different versions of filters and add rules to convert between them.
|
||||
* Move all cached data in one operation, so that user does not get one dialog box for each file in case of duplicates. (http://kdenlive.org/mantis/view.php?id=2297)
|
||||
* Show filter version in filter info box.
|
||||
* When multiple clips are selected do not allow resizing, but moving only. (http://kdenlive.org/mantis/view.php?id=2257)
|
||||
* Add remux with MKV transcode preset.
|
||||
* Make audio only render profiles faster by telling ffmpeg to skip video.
|
||||
* Open documents using a locale different to the system as read only.
|
||||
* Replace locale-dependent comma with slash in geometry value.
|
||||
* Add Kdenlive manual converted from UserBase QuickStart page.
|
||||
* Improve handling of missing luma files. (http://kdenlive.org/mantis/view.php?id=2216)
|
||||
* Remove the "avformat-novalidate" trick for faster loading, caused crash. (http://kdenlive.org/mantis/view.php?id=2205)
|
||||
* Allow to assign a shortcut to usage of proxies in project.
|
||||
* Use separate thread for generation of timeline thumbnails when zoom is at frame level to keep UI responsive.
|
||||
* Allow to use JScript in render profile parameter values. Values that need evalutation need to be indicated by '%'.
|
||||
* Check for missing proxies on document opening.
|
||||
* Check document for invalid (overlapping) transitions.
|
||||
* Check for duration mismatch in clip producers when opening a document (can cause corruption).
|
||||
* Automatically create backups of the project file; they can be restored in a recovery dialog.
|
||||
* Allow to manually edit video4linux capture profile.
|
||||
* Allow to store presets for proxy creation parameters.
|
||||
* Enable proxies for playlist clips (*.mlt, *.kdenlive).
|
||||
* Directly encode capture from Decklink card to make it usable in Kdenlive.
|
||||
* Allow to use bitrate different from presets in render dialog.
|
||||
* Whole projects (including all necessary files) can be archieved into a directory or file.
|
||||
* Allow use of different ffmpeg preset for 1st and 2nd render pass.
|
||||
* Notes widget: context menu now allows to insert clickable timecode to make easy reference to some place in the project.
|
||||
|
||||
* Fix encoding of dvd vob menu file.
|
||||
* Fix possible crash when doing fast start/stop.
|
||||
* Fix multiple concurrency crashes related to thumbnail and proxy creation.
|
||||
* Fix name of dvgrab captured file. (http://kdenlive.org/mantis/view.php?id=2344)
|
||||
* Fix issues with simultaneous 2-pass rendering (x264). (http://kdenlive.org/mantis/view.php?id=2338)
|
||||
* Fix rendering progress not shown if multiple copies of Kdenlive are open. (http://kdenlive.org/mantis/view.php?id=1265)
|
||||
* Fix DVD chapters discarded when opening from render dialog. (http://kdenlive.org/mantis/view.php?id=2335)
|
||||
* Fix possible corruption caused by vertical offset of transitions in timeline.
|
||||
* Fix aspect ratio of thumbnails to correctly use the project's arpect ratio.
|
||||
* Fix bitrate broken when editing render profile or making it a favorite. (http://kdenlive.org/mantis/view.php?id=2321)
|
||||
* Fix audio issues in rendered file when using a recent ffmpeg version by replacing 'b' with 'vb' (ffmpeg bitrate parameter). (http://kdenlive.org/mantis/view.php?id=2318)
|
||||
* Fix rendering to Flash could be broken by setting the number of encoder threads. (http://kdenlive.org/mantis/view.php?id=2312)
|
||||
* Fix DVD wizard losing chapters data when switching to menu page.
|
||||
* Fix previewing of affine transitions with transparent png.
|
||||
* Fix timeline corruption when using 'Remove space' tool (transitions could overlap).
|
||||
* Fix 'adjust to original size' and 'fit to width/height' for title and color clips in geometry widget (pan and zoom, composite, affine).
|
||||
* Fix vorbis rendering by setting the audio quality (aq).
|
||||
* Rotoscoping: do not allow to add keyframes until initial spline is created to avoid corruptions.
|
||||
* Fix possible crash in DVD wizard chapters. (http://kdenlive.org/mantis/view.php?id=2264)
|
||||
* Do not duplicate effect stack after split audio but move audio effects only.
|
||||
* Fix issues related to the usage of comma as numeric separator in some locales.
|
||||
* Fix build on GNU/kFreeBSD.
|
||||
* Fix cursor not visible in title widget. (http://kdenlive.org/mantis/view.php?id=2231)
|
||||
* Fix aspect ratio in title widget background image. (http://kdenlive.org/mantis/view.php?id=2225)
|
||||
* Fix layout in save profile dialog. (http://kdenlive.org/mantis/view.php?id=2224)
|
||||
* Fix timeline corruption because resizing a clip end could overlap another clip in some cases.
|
||||
* Fix last keyframe for composite transition (and other geometry effects) inserted one frame after the end of the transition.
|
||||
* Prevent crash when deleting a clip while playing. (http://kdenlive.org/mantis/view.php?id=2200)
|
||||
* Disable save action if we are in the same state as last save.
|
||||
* Fix pan and zoom keyframes lost after clip resize. (http://kdenlive.org/mantis/view.php?id=2210)
|
||||
* Fix mouse wheel in slider section of (effect) parameters with a large range (> 1000).
|
||||
* Fix GUI setup issues with some list parameters (for effects).
|
||||
* Fix timecode widget not communicating changes upon focus leave.
|
||||
* Fix list of effects in effect stack taking up to much space by default.
|
||||
* Fix transition track not correctly saved. (http://kdenlive.org/mantis/view.php?id=2187)
|
||||
* Fix "save zone" saving proxy instead of real clip. (http://kdenlive.org/mantis/view.php?id=2184)
|
||||
* Fix freeze when saving while timeline is at maximum zoom. (http://kdenlive.org/mantis/view.php?id=2174)
|
||||
* Fix crash when deleting a track and having an audio clip on last track. (http://kdenlive.org/mantis/view.php?id=2168)
|
||||
* Do not allow to create overlapping transitions that could corrupt timeline. (http://kdenlive.org/mantis/view.php?id=1901)
|
||||
* Fix sometimes effects were missing. (http://kdenlive.org/mantis/view.php?id=2152)
|
||||
* Fix crash in histogram scope.
|
||||
* Fix multiple possible timeline corruptions. (http://kdenlive.org/mantis/view.php?id=2157)
|
||||
* Do not allow rendering to a frame rate different than current project's profile. (http://kdenlive.org/mantis/view.php?id=2138)
|
||||
* Fix DVD menu entries hidden under some circumstances.
|
||||
* Fix channels in audio thumbnails being displaced by one frame. (http://kdenlive.org/mantis/view.php?id=1976)
|
||||
* Fix possible crash caused by audio thumbnails. (http://kdenlive.org/mantis/view.php?id=2147)
|
||||
* Fix possible freeze and error on project opening. (http://kdenlive.org/mantis/view.php?id=2144)
|
||||
* Fix progress bar running twice on 2pass render.
|
||||
* Fix proxy file path issue on system installation.
|
||||
* Use luma as default channel for levels effect.
|
||||
* Fix handling of proxies when duration != duration of original clip.
|
||||
* Fix filename encoding problem in renderer. (http://kdenlive.org/mantis/view.php?id=2110)
|
||||
* Fix user specified CFLAGS ignored. (http://kdenlive.org/mantis/view.php?id=2108)
|
||||
|
||||
0.8
|
||||
See http://kdenlive.org/discover/0.8
|
||||
70
TODO
@@ -1,70 +0,0 @@
|
||||
Some ideas for a big refactoring of code.
|
||||
|
||||
|
||||
Input
|
||||
=========
|
||||
handle MLT connection ((re-)move from renderer.cpp (hacks, special cases))
|
||||
handle project document entry
|
||||
draw layer on clip instances in timeline (thumbnails)
|
||||
settings management (available through project tree items)
|
||||
proxy creation
|
||||
input method (register mimetype in file dialog, custom widget)
|
||||
effect support (a, v, av, special effects (freeze, speed))
|
||||
support for multi-channel sound (5.1, ...)
|
||||
|
||||
=> modules for avformat, qimage/gtk_image(?), generators (slideshow, color, f0r)
|
||||
|
||||
|
||||
Timeline
|
||||
=========
|
||||
provides basic operations (resize, move, add, remove) (GUI + XML + MLT) to be applied on any item
|
||||
|
||||
=> modules for input modes (drag & drop, 3/4-point editing, cut, resize by dragging end), spacer, ripple edit, push/pull edit, ...)
|
||||
|
||||
Clip instances
|
||||
-------
|
||||
connection to input module
|
||||
manage project document entry
|
||||
information about support for timeline operations
|
||||
owns an effect device
|
||||
per instance settings (functionality provided by input module)
|
||||
graphical timeline item (modules can register layers they want to draw (thumbnails, effect names, keyframes))
|
||||
|
||||
Clip groups
|
||||
------
|
||||
manage project document entry
|
||||
pass on operations to items
|
||||
|
||||
|
||||
Effect system
|
||||
=========
|
||||
Keyframe manager
|
||||
------
|
||||
pipe information from/to timeline effect device, effect stack, effect parameter
|
||||
|
||||
Effect parameter
|
||||
------
|
||||
custom widget
|
||||
function to handle keyframes -> connect to keyframe manager
|
||||
written in QScript/QML ?
|
||||
|
||||
Effect device
|
||||
------
|
||||
manages list of effects attached to clip, track, timeline, group, the world
|
||||
passes info from/to timeline items and effect stack
|
||||
manage project document entry
|
||||
|
||||
|
||||
Project
|
||||
=========
|
||||
read/write
|
||||
project settings management
|
||||
provide functionality to manage settings (remove hardcoded stuff (slideshow, proxy, ...))
|
||||
|
||||
|
||||
Interface
|
||||
=========
|
||||
provide functions to add menu items, global actions (for shortcut management)
|
||||
layout management
|
||||
styles management (see digikam)
|
||||
...
|
||||
545
dependencies.svg
Normal file
@@ -0,0 +1,545 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="471.37357"
|
||||
height="312.8873"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="kdenlive-mlt-diagram.svg"
|
||||
inkscape:export-filename="/tmp/kdenlive-mlt-diagram.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10" />
|
||||
<inkscape:perspective
|
||||
id="perspective3625"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3652"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3725"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3725-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3725-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3725-80"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<marker
|
||||
markerWidth="31.09709"
|
||||
markerHeight="16.823833"
|
||||
orient="auto"
|
||||
id="marker3777">
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m -15.548545,-8.3235343 c 0.98737,-0.987372 31.09709,6.586995 31.09709,8.33243898 0,1.84100902 -30.23094,9.19859202 -31.09709,8.33244002 l 0,-16.664879 z"
|
||||
id="path3775"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</marker>
|
||||
<marker
|
||||
markerWidth="10.3371"
|
||||
markerHeight="5.5924713"
|
||||
orient="auto"
|
||||
id="marker4150">
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m -5.16855,-2.7668562 c 0.32822,-0.328216 10.3371,2.18960696 10.3371,2.76981596 0,0.611977 -10.04918,3.05773704 -10.3371,2.76981704 l 0,-5.539633 z"
|
||||
id="path4148"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</marker>
|
||||
<inkscape:perspective
|
||||
id="perspective4723"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<marker
|
||||
markerWidth="10.3371"
|
||||
markerHeight="5.5924711"
|
||||
orient="auto"
|
||||
id="marker4150-6">
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m -5.16855,-2.7668562 c 0.32822,-0.328216 10.3371,2.18960696 10.3371,2.76981596 0,0.611977 -10.04918,3.05773704 -10.3371,2.76981704 l 0,-5.539633 z"
|
||||
id="path4148-2"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</marker>
|
||||
<inkscape:perspective
|
||||
id="perspective4723-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<marker
|
||||
markerWidth="10.3371"
|
||||
markerHeight="5.5924711"
|
||||
orient="auto"
|
||||
id="marker4150-68">
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m -5.16855,-2.7668562 c 0.32822,-0.328216 10.3371,2.18960696 10.3371,2.76981596 0,0.611977 -10.04918,3.05773704 -10.3371,2.76981704 l 0,-5.539633 z"
|
||||
id="path4148-5"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</marker>
|
||||
<inkscape:perspective
|
||||
id="perspective4723-2"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<marker
|
||||
markerWidth="10.3371"
|
||||
markerHeight="5.5924711"
|
||||
orient="auto"
|
||||
id="marker4150-3">
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m -5.16855,-2.7668562 c 0.32822,-0.328216 10.3371,2.18960696 10.3371,2.76981596 0,0.611977 -10.04918,3.05773704 -10.3371,2.76981704 l 0,-5.539633 z"
|
||||
id="path4148-7"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</marker>
|
||||
<inkscape:perspective
|
||||
id="perspective4723-6"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<marker
|
||||
markerWidth="10.3371"
|
||||
markerHeight="5.5924711"
|
||||
orient="auto"
|
||||
id="marker4150-8">
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m -5.16855,-2.7668562 c 0.32822,-0.328216 10.3371,2.18960696 10.3371,2.76981596 0,0.611977 -10.04918,3.05773704 -10.3371,2.76981704 l 0,-5.539633 z"
|
||||
id="path4148-22"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#282828"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4323"
|
||||
inkscape:cx="377.1885"
|
||||
inkscape:cy="156.24755"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:window-width="1364"
|
||||
inkscape:window-height="713"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:showpageshadow="false"
|
||||
showborder="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="BG"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="color:#000000;fill:#282828;fill-opacity:1;fill-rule:nonzero;stroke:#282828;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect2843"
|
||||
width="469.87357"
|
||||
height="311.3873"
|
||||
x="0.75"
|
||||
y="0.74999857"
|
||||
rx="6.9817758"
|
||||
ry="6.9817758" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-45.329731,-60.897953)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:27.2442379px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="283.32236"
|
||||
y="332.06137"
|
||||
id="text2816"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2818"
|
||||
x="283.32236"
|
||||
y="332.06137">kdenlive</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:14.01654053px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="170.04121"
|
||||
y="141.98691"
|
||||
id="text2820"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2822"
|
||||
x="170.04121"
|
||||
y="141.98691">Frei0r</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:11.89307213px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="333.90146"
|
||||
y="137.10045"
|
||||
id="text2824"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2826"
|
||||
x="333.90146"
|
||||
y="137.10045">SoX</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:22.63406181px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="251.84148"
|
||||
y="241.51353"
|
||||
id="text2828"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2830"
|
||||
x="251.84148"
|
||||
y="241.51353">MLT</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="133.70102"
|
||||
y="244.91959"
|
||||
id="text2832"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2834"
|
||||
x="133.70102"
|
||||
y="244.91959">ffmpeg</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:11.37970638px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="319.48306"
|
||||
y="173.76093"
|
||||
id="text2836"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2838"
|
||||
x="319.48306"
|
||||
y="173.76093">LADSPA</tspan></text>
|
||||
<g
|
||||
id="g3618"
|
||||
transform="matrix(0.98815313,-0.15347112,0.15347112,0.98815313,-81.414431,-4.1588633)"
|
||||
style="fill:#eeeeee;fill-opacity:1">
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path2840"
|
||||
d="m 456.25917,185.68219 0,37.38942"
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:#eeeeee;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
inkscape:transform-center-y="-1.3963555"
|
||||
transform="matrix(0.99227788,-0.12403474,0.12403474,0.99227788,-21.929088,58.404098)"
|
||||
d="m 454.86282,222.22884 c 0,2.60275 -3.43844,4.7127 -7.67996,4.7127 -4.24152,0 -7.67995,-2.10995 -7.67995,-4.7127 0,-2.60276 3.43843,-4.7127 7.67995,-4.7127 4.24152,0 7.67996,2.10994 7.67996,4.7127 z"
|
||||
sodipodi:ry="4.7126999"
|
||||
sodipodi:rx="7.679955"
|
||||
sodipodi:cy="222.22884"
|
||||
sodipodi:cx="447.18286"
|
||||
id="path2842"
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.20999999;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path2844"
|
||||
d="m 477.57192,200.70203 c -17.10535,-0.69818 -7.06241,-14.14643 -20.67901,-15.01916 l 0,4.33654 c 10.49929,-1.82834 11.16527,8.53878 20.67901,10.68262 z"
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:13.83212471px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="385.48517"
|
||||
y="182.45871"
|
||||
id="text3623"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3625"
|
||||
x="385.48517"
|
||||
y="182.45871">SRC</tspan></text>
|
||||
<g
|
||||
id="g3631"
|
||||
transform="matrix(0.99709206,0.07620643,-0.07620643,0.99709206,-20.899324,-80.097483)"
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none">
|
||||
<rect
|
||||
rx="0"
|
||||
ry="0"
|
||||
y="204.02309"
|
||||
x="147.00932"
|
||||
height="14.623979"
|
||||
width="29.178928"
|
||||
id="rect3627"
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98357183;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
transform="matrix(0.9642511,-0.26499023,0.26499023,0.9642511,0,0)"
|
||||
inkscape:transform-center-y="-6.2147158"
|
||||
inkscape:transform-center-x="-13.932476"
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.98357183;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3629"
|
||||
width="29.178928"
|
||||
height="3.6175911"
|
||||
x="87.837669"
|
||||
y="230.97163"
|
||||
ry="0"
|
||||
rx="0" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr;text-anchor:start;color:#000000;fill:#6491e3;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="96.729767"
|
||||
y="103.21655"
|
||||
id="text3640"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3642"
|
||||
x="96.729767"
|
||||
y="103.21655">Video Effects</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3667"
|
||||
y="215.34749"
|
||||
x="65.922745"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr;text-anchor:start;color:#000000;fill:#6491e3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="215.34749"
|
||||
x="65.922745"
|
||||
id="tspan3669"
|
||||
sodipodi:role="line">Coding/Decoding, Transcoding</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr;text-anchor:start;color:#000000;fill:#6491e3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="384.85358"
|
||||
y="326.44742"
|
||||
id="text3671"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3673"
|
||||
x="384.85358"
|
||||
y="326.44742">Nonlinear Editor GUI</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr;text-anchor:start;color:#000000;fill:#6491e3;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro;stroke-width:1"
|
||||
x="317.05167"
|
||||
y="241.56248"
|
||||
id="text3675"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3677"
|
||||
x="317.05167"
|
||||
y="241.56248">Rendering, Effects</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans"
|
||||
x="301.14859"
|
||||
y="26.54929"
|
||||
id="text3679"
|
||||
sodipodi:linespacing="100%"
|
||||
transform="translate(45.329731,60.897953)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3681"
|
||||
x="301.14859"
|
||||
y="26.54929" /></text>
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3683"
|
||||
y="99.640968"
|
||||
x="386.87796"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:100%;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr;text-anchor:start;color:#000000;fill:#6491e3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="99.640968"
|
||||
x="386.87796"
|
||||
id="tspan3685"
|
||||
sodipodi:role="line">Audio Effects</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:8.99999998px;font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro Heavy"
|
||||
x="117.68263"
|
||||
y="221.66136"
|
||||
id="text3687"
|
||||
sodipodi:linespacing="100%"
|
||||
transform="matrix(0.97894222,0.20413754,-0.20413754,0.97894222,0,0)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3689"
|
||||
x="117.68263"
|
||||
y="221.66136">0111010...</tspan></text>
|
||||
<g
|
||||
id="g3707"
|
||||
transform="matrix(0.98972711,-0.14296942,0.14296942,0.98972711,13.042295,51.643621)">
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
transform="translate(45.329731,60.897953)"
|
||||
y="231.89868"
|
||||
x="61.788731"
|
||||
height="11.519938"
|
||||
width="82.73407"
|
||||
id="rect3691"
|
||||
style="color:#000000;fill:none;stroke:#eeeeee;stroke-width:1.5;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#eeeeee;stroke-width:1.5;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3693"
|
||||
width="82.73407"
|
||||
height="11.519938"
|
||||
x="107.11846"
|
||||
y="304.31656"
|
||||
rx="0"
|
||||
ry="0" />
|
||||
<rect
|
||||
y="293.06757"
|
||||
x="107.16393"
|
||||
height="10.861097"
|
||||
width="19.00692"
|
||||
id="rect3695"
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3697"
|
||||
width="9.1331959"
|
||||
height="10.861084"
|
||||
x="123.94926"
|
||||
y="304.91605" />
|
||||
<rect
|
||||
y="293.19101"
|
||||
x="130.12033"
|
||||
height="10.861084"
|
||||
width="9.1331959"
|
||||
id="rect3699"
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3701"
|
||||
width="22.215879"
|
||||
height="10.861084"
|
||||
x="136.53825"
|
||||
y="304.79263" />
|
||||
<rect
|
||||
ry="0"
|
||||
rx="0"
|
||||
y="315.91818"
|
||||
x="107.11846"
|
||||
height="11.519938"
|
||||
width="82.73407"
|
||||
id="rect3703"
|
||||
style="color:#000000;fill:none;stroke:#eeeeee;stroke-width:1.5;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;fill:#eeeeee;fill-opacity:1;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3705"
|
||||
width="6.664763"
|
||||
height="10.861084"
|
||||
x="156.53255"
|
||||
y="316.39426" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#eeeeee;fill-opacity:1;stroke:none"
|
||||
d="m 384.61901,7.4179919 c 0.32822,-0.328216 10.3371,2.189607 10.3371,2.7698161 0,0.611977 -10.04918,3.057737 -10.3371,2.769817 l 0,-5.5396331 z"
|
||||
id="path3773"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#eeeeee;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4150)"
|
||||
d="m 212.94421,150.21188 c 0,0 -8.02904,-35.25797 -50.61788,-54.10877"
|
||||
id="path4153"
|
||||
transform="translate(45.329731,60.897953)"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#eeeeee;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker4150);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 230.39866,150.91006 c 4.88724,-39.09795 37.00342,-53.759686 37.00342,-53.759686"
|
||||
id="path4713"
|
||||
transform="translate(45.329731,60.897953)" />
|
||||
<path
|
||||
style="fill:none;stroke:#eeeeee;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker4150);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 197.96818,173.66778 c -29.62118,-2.96211 -45.91282,2.96212 -45.91282,2.96212"
|
||||
id="path4742"
|
||||
transform="translate(45.329731,60.897953)" />
|
||||
<path
|
||||
style="fill:none;stroke:#eeeeee;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker4150);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 286.91992,244.25038 c -13.07116,-29.24727 -43.17751,-55.8918 -43.17751,-55.8918"
|
||||
id="path4756"
|
||||
transform="translate(45.329731,60.897953)"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#eeeeee;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker4150);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 229.40673,262.19851 c -54.65634,-23.5566 -85.74404,-69.77065 -85.74404,-69.77065"
|
||||
id="path4770"
|
||||
transform="translate(45.329731,60.897953)"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3861"
|
||||
y="162.93225"
|
||||
x="159.56856"
|
||||
style="font-size:14.01654053px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#eeeeee;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="162.93225"
|
||||
x="159.56856"
|
||||
id="tspan3863"
|
||||
sodipodi:role="line">Movit</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 25 KiB |
@@ -1,4 +0,0 @@
|
||||
kde4_create_handbook(index.docbook
|
||||
INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en
|
||||
SUBDIR kdenlive
|
||||
)
|
||||
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 313 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,357 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
|
||||
<!ENTITY % addindex "IGNORE">
|
||||
<!ENTITY % English "INCLUDE">
|
||||
]>
|
||||
<book id="kdenlive" lang="&language;">
|
||||
<bookinfo>
|
||||
<title>The Kdenlive Quick Start Guide</title>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>This documentation was converted from the KDE UserBase <ulink url=" http://userbase.kde.org/Kdenlive/Manual/QuickStart">Kdenlive/Manual/QuickStart</ulink> page.</firstname>
|
||||
<surname></surname>
|
||||
</personname>
|
||||
</author>
|
||||
<!-- TRANS:ROLES_OF_TRANSLATORS -->
|
||||
</authorgroup>
|
||||
<legalnotice>&FDLNotice;</legalnotice>
|
||||
<date>2011-06-17</date>
|
||||
<releaseinfo>0.8.2</releaseinfo>
|
||||
<abstract>
|
||||
<para></para>
|
||||
</abstract>
|
||||
<keywordset>
|
||||
<keyword>KDE</keyword>
|
||||
<keyword>multimedia</keyword>
|
||||
<keyword>video</keyword>
|
||||
</keywordset>
|
||||
</bookinfo>
|
||||
<!--userbase <timestamp>2011-06-17T15:39:59Z</timestamp>-->
|
||||
|
||||
<!--userbase-content-->
|
||||
<chapter id="creating-a-new-project"><title>Creating a new project</title>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Folder-Structure.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Kdenlive directory structure</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Kdenlive directory structure</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>The first step is creating a new (empty) folder for our new project. I will call it <filename>quickstart-tutorial/</filename> in this tutorial. Then get some sample video clips, or download them from here:<ulink url="http://granjow.net/uploads/kdenlive/manual/kdenlive-tutorial-videos-2011-avi.tar.bz2">kdenlive-tutorial-videos-2011-avi.tar.bz2</ulink> (7 MB)<footnote><para>If you prefer Theora (which you probably don’t since Ogg Video usually causes problems), you can alternatively download <ulink url="http://granjow.net/uploads/kdenlive/manual/kdenlive-tutorial-videos-2011-ogv.tar.bz2">kdenlive-tutorial-videos-2011-ogv.tar.bz2</ulink>.</para></footnote>, and extract them to ⪚ a <filename>quickstart-tutorial/Videos/</filename> subfolder inside the project folder.</para>
|
||||
<para>The image on the left shows the suggested directory structure: Each project has its own directory, with video files in the <filename>Videos</filename> subdirectory, audio files in the <filename>Audio</filename> directory, &etc; (<ulink url="http://userbase.kde.org/Special:myLanguage/Kdenlive/Manual/Projects_and_Files#File_Structure">read more</ulink>)</para>
|
||||
<para>(The tutorial from now on assumes that you use the sample videos provided, but it works with any.)</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-New-Project.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>New Project dialog</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>New Project dialog</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Open <application>Kdenlive</application> and create a new project (<menuchoice><guimenu>File</guimenu><guimenuitem>New</guimenuitem></menuchoice>).</para>
|
||||
<para>Choose the previously created project folder (<filename>quickstart-tutorial/</filename>) and select an appropriate project profile. The video files provided above are 720p, 23.98 fps.<footnote><para><ulink url="http://en.wikipedia.org/wiki/720p">720</ulink> is the video height, p stands for <ulink url="http://en.wikipedia.org/wiki/Progressive_scan">progressive scan</ulink> in contrast to <ulink url="http://en.wikipedia.org/wiki/Interlaced_video">interlaced video</ulink>, and the fps number denotes the number of full frames per second.</para></footnote> If you are using your own files and don’t know which one to use, <application>Kdenlive</application> will suggest an appropriate one when the first clip is added, so you can leave the field on whatever it is.</para>
|
||||
</chapter>
|
||||
<chapter id="adding-clips"><title>Adding clips</title>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Add-Clips.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Project Tree: Adding video clips</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Project Tree: Adding video clips</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Now that the project is ready, let’s start adding some clips (&ie; the ones you downloaded). This works via the <emphasis>Project Tree widget</emphasis>; a click on the <guilabel>Add Clip</guilabel> icon directly opens the file dialog, a click on the small arrow shows a list of additional clip types that can be added as well. Video clips, audio clips, images, and other <application>Kdenlive</application> projects can be added via the default <guilabel>Add Clip</guilabel> dialog.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Mainwindow.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Kdenlive 0.8 window with the tutorial files</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Kdenlive 0.8 window with the tutorial files</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>After loading the clips, <application>Kdenlive</application> will look similar to this. On the top left there is the already known project tree. Right of it are the monitors that show video; The clip monitor displays video from the original clips, the project monitor shows how the output video will look, with all effects, transitions, &etc; applied. The third, also very important, item is the timeline (below the monitors): This is the place where the video clips will be edited. There are two different types of tracks, Video and Audio. Video tracks can contain any kind of clip, audio tracks as well – but when dropping a video file to the audio track, only the audio will be used.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Save-Project.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Saving a Kdenlive project</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Saving a Kdenlive project</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Let’s save the work via <menuchoice><guimenu>File</guimenu><guimenuitem>Save</guimenuitem></menuchoice>. This saves our project, &ie; where we placed the clips on the timeline, which effects we applied, and so on. It can <emphasis>not</emphasis> be played.<footnote><para>To be correct, it <emphasis>can</emphasis> be played using <varname>melt yourproject.kdenlive</varname>, but this is not the way you would want to present your final video since it is (most likely) too slow. Additionally, it only works if melt is installed.</para></footnote> The process of creating the final video is called <emphasis>Rendering</emphasis>.</para>
|
||||
</chapter>
|
||||
<chapter id="timeline"><title>Timeline</title>
|
||||
<para>Now comes the actual editing. Project clips are combined to the final result on the timeline. They get there by drag and drop: Drag some Napoli (assuming you are using the files provided above, as in the rest of this quick start tutorial; If not, please make sure your screen is waterproof, and perhaps tomatoproof), and drop it onto the first track in the timeline.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Timeline-Clips.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>First clips in the timeline</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>First clips in the timeline</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Since some cutlery is needed as well, drop the spoon on the first track as well. Then drag the Napoli to the beginning of the timeline (otherwise the rendered video would start with some seconds of plain black), and the Spoon right after the Napoli, such that it looks like in the image on the left. (Where I have zoomed in with <keycombo>&Ctrl;<keycap>Wheel</keycap></keycombo>.)</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-TimelineCursor.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Timeline cursor</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Timeline cursor</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>The result can already be previewed by pressing <keycap>Space</keycap> (or the <guilabel>Play</guilabel> button in the project monitor). You will see the Napoli directly followed by a Spoon. If the timeline cursor is not at the beginning, the project monitor will start playing somewhere in the middle; you can move it by dragging it either on the timeline ruler or in the project monitor. If you prefer keyboard shortcuts, <keycombo>&Ctrl;<keycap>Home</keycap></keycombo> does the same for the monitor that is activated. (Select the <guilabel>Project Monitor</guilabel> if it is not selected yet before using the shortcut.)</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Resize-Marker.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Resize marker</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Resize marker</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Since after eating comes playing, there is a Billard clip. Add it to the timeline as well. The first 1.5 seconds nothing happens in the clip, so it should perhaps be <guilabel>cut</guilabel> to avoid the video becoming boring. An easy way<footnote><para>Writing it this way suggests that there are several ways of cutting a clip. This is in fact true.</para></footnote> for this is to move the timeline cursor to the desired position (&ie; the position where you want to cut the video), then drag the left border of the clip when the resize marker appears. It will snap in at the timeline cursor when you move close enough.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Overlap-Clips.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Overlapping clips</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Overlapping clips</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>To add a <emphasis>transition</emphasis> between eating (the Spoon) and playing billard, the two clips need to overlap. To be precise: the second clip should be above or below the first one and end some frames after the second one begins. Zooming in until the ticks for simple frames appear helps there; it also makes it easy to always have the same transition duration, like five frames in this case.</para>
|
||||
<para>You can zoom in by either using the <guilabel>zoom slider</guilabel> at the bottom of the <application>Kdenlive</application> window, or with <keycombo>&Ctrl;<keycap>Mousewheel</keycap></keycombo>. <application>Kdenlive</application> will zoom to the timeline cursor, so first set it to the position which you want to see enlarged, then zoom in.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive-Quickstart-Add-Transition.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Transition marker</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Transition marker</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Now that the clips overlap, the transition can be added. This is done either by right-clicking on the upper clip and choosing <guilabel>Add Transition</guilabel> or, easier, by clicking the lower right corner of the Spoon clip. The latter by default adds a dissolve transition, which is in this case the best idea anyway since the Spoon is not required for playing anyway.</para>
|
||||
<para>The dissolve transitions fades the first clip into the second one.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive-Quickstart-Add-Last-Clip.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase></phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para></para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Let’s add the last clip, the Piano, now, and again apply a dissolve transition. When adding it on the first track of the timeline, you need to click on the new clip’s lower left edge to add the transition to the previous clip.</para>
|
||||
<sect1 id="effects"><title>Effects</title>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Add-Effect.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Effect List</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Effect List</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>The Piano can be colourized by adding an <emphasis>effect</emphasis> to it. Select the piano clip, then double-click the <guilabel>RGB Adjustment</guilabel> effect in the <guilabel>Effect List</guilabel>. If it is not visible, you can get it via <menuchoice><guimenu>View</guimenu><guimenuitem>Effect List</guimenuitem></menuchoice>.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Effect-Flag.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase></phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para></para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Once the effect has been added, its name will be added to the timeline clip. It will also be shown in the <guilabel>Effect Stack</guilabel> widget.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive-Quickstart-EffectStack.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Effect Stack with RGB adjustment</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Effect Stack with RGB adjustment</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>To get a warm yellow-orange tone on the image, fitting the comfortable evening, blue needs to be reduced and red and green improved.</para>
|
||||
<para>The values in the effect stack widget can be changed by using the slider (middle mouse button resets it to the default value), or by entering a value directly by double-clicking the number right to the slider.</para>
|
||||
<para>Effects can also be added with the <guilabel>Add new effect</guilabel> icon (framed in the image on the left) in the <guilabel>Effect Stack</guilabel>; It always refers to the timeline clip that is currently selected. By unchecking the checkbox they are temporarily disabled (the settings remain though), this is ⪚ useful for effects that require a lot of computing power, so they can be disabled when editing and enabled again for rendering.</para>
|
||||
<para>For some effects, like the one used there, it is possible to add keyframes. The framed watch icon indicates this. Keyframes are used for changing effect parameters over time. In our clip this allows us to fade the piano’s colour from a warm evening colour to a cold night colour.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Keyframes.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Keyframes for effects</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Keyframes for effects</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>After clicking the <guilabel>keyframe</guilabel> icon (the clock icon framed in the previous image), the Effect Stack widget will re-arrange. By default there will be two keyframes, one at the beginning of the timeline clip and one at the end. Move the timeline cursor to the end of the timeline clip, such that the project monitor actually shows the new colours when changing the parameters of the keyframe at the end.</para>
|
||||
<para>Make sure the last keyframe is selected in the Effect Stack’s list. Then you are ready to flood the piano with a deep blue.</para>
|
||||
<para>Moving the timeline cursor to the beginning of the project and playing it (with <keycap>Space</keycap>, or the <guilabel>Play</guilabel> button in the <guilabel>Project Monitor</guilabel>), the piano should now change the colour as desired.</para>
|
||||
<para>Keyframing was the hardest part of this tutorial. If you managed to do it, you will master <guilabel>Kdenilve</guilabel> easily!</para>
|
||||
</sect1>
|
||||
<sect1 id="music"><title>Music</title>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Fadeout.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Audio fadeout</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Audio fadeout</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>Since the clips do not provide any audio, let’s search for some nice piece of music, on your local collection or on web pages like <ulink url="http://www.jamendo.com">Jamendo</ulink>. The audio clip should, after adding it, go to an audio track on the timeline.</para>
|
||||
<para>The audio clip can be resized on the timeline the same way as video clips are. The cursor will snap in at the end of the project automatically. To add a fade out effect at the end of the audio clip (except if you found a file with exactly the right length) you can hover the top right (or left) edge of the timeline clip and drag the green disc to the position where fading out should start.<footnote><para>This green disc is a shorthand for adding the effect <menuchoice><guimenu>Fade</guimenu><guimenuitem>Fade out</guimenuitem></menuchoice>. Both ways lead to the same result.</para></footnote></para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
<chapter id="rendering"><title>Rendering</title>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Renderer.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Rendering dialog</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Rendering dialog</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>A few minutes left, and the project is finished! Click the Render button (or go to <menuchoice><guimenu>Project</guimenu><guimenuitem>Render</guimenuitem></menuchoice>, or press <keycombo>&Ctrl;&Enter;</keycombo>) to get the dialog shown on the left. Select the desired output file for our new video with all effects and transitions, choose MPEG4 (works nearly everywhere) and a bitrate of 2000k (the higher the bitrate, the larger the output file and the better the quality – but since the bitrate for the input clips was 2000k already, using a higher one would not improve quality and is therefore unnecessary), and press the <emphasis>Render to File</emphasis> button.</para>
|
||||
<para>
|
||||
<screenshot>
|
||||
<screeninfo></screeninfo>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="Kdenlive_Quickstart-Rendering.png" format="PNG"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Rendering progress</phrase>
|
||||
</textobject>
|
||||
<caption>
|
||||
<para>Rendering progress</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</screenshot></para>
|
||||
<para>After some seconds rendering will be finished, and your first <application>Kdenlive</application> project completed. Congratulations!</para>
|
||||
</chapter>
|
||||
|
||||
<!--userbase-content-->
|
||||
<chapter id="credits">
|
||||
<title>Credits and License</title>
|
||||
<para>
|
||||
Documentation Copyright see the UserBase
|
||||
<ulink url="http://userbase.kde.org/index.php?title=Kdenlive/Manual/QuickStart&action=history">Kdenlive/Manual/QuickStart page history</ulink></para>
|
||||
<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
|
||||
&underFDL;
|
||||
</chapter>
|
||||
&documentation.index;
|
||||
</book>
|
||||
@@ -31,7 +31,6 @@
|
||||
<name>Invert</name>
|
||||
</parameter>
|
||||
</effect>
|
||||
|
||||
<effect LC_NUMERIC="C" tag="frei0r.alpha0ps" id="frei0r.alpha0ps" version="0.3">
|
||||
<name>Alpha operations</name>
|
||||
<description>Display and manipulation of the alpha channel</description>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<name>Max</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0">
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Write on clear,Max,Min,Add,Subtract</paramlistdisplay>
|
||||
<name>Operation</name>
|
||||
</parameter>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<author>Marko Cebokli</author>
|
||||
|
||||
|
||||
<parameter type="list" name="Shape" default="0.0" paramlist="0.0;0.38;0.62;1.0">
|
||||
<parameter type="list" name="Shape" default="0.0" paramlist="0.0;0.38;0.62;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Rectangle,Ellipse,Triangle,Diamond</paramlistdisplay>
|
||||
<name>Shape</name>
|
||||
</parameter>
|
||||
@@ -42,7 +42,7 @@
|
||||
<name>Max</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0">
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Write on clear,Max,Min,Add,Subtract</paramlistdisplay>
|
||||
<name>Operation</name>
|
||||
</parameter>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<description>Color curves adjustment</description>
|
||||
<author>Till Theato, Maksim Golovkin</author>
|
||||
|
||||
<parameter type="list" name="Channel" default="0.5" paramlist="0.5;0;0.1;0.2;0.3;0.4;0.6;0.71">
|
||||
<parameter type="list" name="Channel" default="0.5" paramlist="0.5;0;0.1;0.2;0.3;0.4;0.6;0.71" listitemtype="double">
|
||||
<paramlistdisplay>RGB,Red,Green,Blue,Alpha,Luma,Hue,Saturation</paramlistdisplay>
|
||||
<name>Channel</name>
|
||||
</parameter>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<name>Enable Stretch</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Interpolator" default="0.166" paramlist="0;0.166;0.333;0.5;0.666;0.833;1.0">
|
||||
<parameter type="list" name="Interpolator" default="0.166" paramlist="0;0.166;0.333;0.5;0.666;0.833;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Nearest neighbor,Bilinear,Bicubic smooth,Bicubic sharp,Spline 4x4,Spline 6x6,Lanczos</paramlistdisplay>
|
||||
<name>Interpolator</name>
|
||||
</parameter>
|
||||
@@ -61,7 +61,7 @@
|
||||
<name>Transparent Background</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Alpha operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0">
|
||||
<parameter type="list" name="Alpha operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Write on clear,Maximum,Minimum,Add,Subtract</paramlistdisplay>
|
||||
<name>Alpha operation</name>
|
||||
</parameter>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<name>B</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Action" default="0.5" paramlist="0.0;0.5;1.0">
|
||||
<parameter type="list" name="Action" default="0.5" paramlist="0.0;0.5;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Add constant,Change gamma,Multiply</paramlistdisplay>
|
||||
<name>Action</name>
|
||||
</parameter>
|
||||
@@ -29,7 +29,7 @@
|
||||
<name>Alpha controlled</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Luma formula" default="1.0" paramlist="0.0;1.0">
|
||||
<parameter type="list" name="Luma formula" default="1.0" paramlist="0.0;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Rec. 601,Rec. 709</paramlistdisplay>
|
||||
<name>Luma formula</name>
|
||||
</parameter>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<parameter type="bool" name="Show curves" default="0">
|
||||
<name>Show graph in picture</name>
|
||||
</parameter>
|
||||
<parameter type="list" name="Graph position" default="0.3" paramlist="0;0.1;0.2;0.3">
|
||||
<parameter type="list" name="Graph position" default="0.3" paramlist="0;0.1;0.2;0.3" listitemtype="double">
|
||||
<paramlistdisplay>Top Left,Top Right,Bottom Left,Bottom Right</paramlistdisplay>
|
||||
<name>Graph position</name>
|
||||
</parameter>
|
||||
|
||||
@@ -9,22 +9,22 @@
|
||||
<parameter type="bool" name="DeFish" default="1">
|
||||
<name>DeFish</name>
|
||||
</parameter>
|
||||
<parameter type="list" name="Type" default="0.666" paramlist="0;0.333;0.666;1.0">
|
||||
<parameter type="list" name="Type" default="0.666" paramlist="0;0.333;0.666;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Equidistant,Orthographic,Equiarea,Stereographic</paramlistdisplay>
|
||||
<name>Type</name>
|
||||
</parameter>
|
||||
<parameter type="list" name="Scaling" default="0" paramlist="0;0.333;0.666;1.0">
|
||||
<parameter type="list" name="Scaling" default="0" paramlist="0;0.333;0.666;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Fill,Center,Fit,Manual</paramlistdisplay>
|
||||
<name>Scaling</name>
|
||||
</parameter>
|
||||
<parameter type="constant" name="Manual Scale" default="500" min="0" max="1000" factor="1000">
|
||||
<name>Manual Scale</name>
|
||||
</parameter>
|
||||
<parameter type="list" name="Interpolator" default="0.166" paramlist="0;0.166;0.333;0.5;0.666;0.833;1.0">
|
||||
<parameter type="list" name="Interpolator" default="0.166" paramlist="0;0.166;0.333;0.5;0.666;0.833;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Nearest neighbor,Bilinear,Bicubic smooth,Bicubic sharp,Spline 4x4,Spline 6x6,Lanczos</paramlistdisplay>
|
||||
<name>Interpolator</name>
|
||||
</parameter>
|
||||
<parameter type="list" name="Aspect type" default="0" paramlist="0;0.25;0.5;0.75;1.0">
|
||||
<parameter type="list" name="Aspect type" default="0" paramlist="0;0.25;0.5;0.75;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Square,PAL DV,NTSC DV,HDV,Manual</paramlistdisplay>
|
||||
<name>Aspect type</name>
|
||||
</parameter>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<comment>How often to detect a face. In between checks, it does object motion tracking.</comment>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Shape" default="0.0" paramlist="0.0;0.1;0.2;1.0">
|
||||
<parameter type="list" name="Shape" default="0.0" paramlist="0.0;0.1;0.2;1.0" listitemtype="double">
|
||||
<paramlistdisplay>circle,ellipse,rectangle,random</paramlistdisplay>
|
||||
<name>Shape</name>
|
||||
</parameter>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<comment>Amount of blur</comment>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Type" default="0.5" paramlist="0.0,0.5,0.999">
|
||||
<parameter type="list" name="Type" default="0.5" paramlist="0.0;0.5;0.999" listitemtype="double">
|
||||
<paramlistdisplay>Exponential,Lowpass,Gaussian</paramlistdisplay>
|
||||
<name>Type</name>
|
||||
<comment>Select blurring algorithm</comment>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<description>Adjust levels</description>
|
||||
<author>Maksim Golovkin</author>
|
||||
|
||||
<parameter type="list" name="Channel" default="0.3" paramlist="0;0.1;0.2;0.3">
|
||||
<parameter type="list" name="Channel" default="0.3" paramlist="0;0.1;0.2;0.3" listitemtype="double">
|
||||
<paramlistdisplay>Red,Green,Blue,Luma</paramlistdisplay>
|
||||
<name>Channel</name>
|
||||
</parameter>
|
||||
@@ -59,7 +59,7 @@
|
||||
<parameter type="bool" name="Show histogram" default="0">
|
||||
<name>Show histogram</name>
|
||||
</parameter>
|
||||
<parameter type="list" name="Histogram position" default="0.3" paramlist="0;0.1;0.2;0.3">
|
||||
<parameter type="list" name="Histogram position" default="0.3" paramlist="0;0.1;0.2;0.3" listitemtype="double">
|
||||
<paramlistdisplay>Top Left,Top Right,Bottom Left,Bottom Right</paramlistdisplay>
|
||||
<name>Histogram position</name>
|
||||
</parameter>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<description>Measure video values</description>
|
||||
<author>Marko Cebokli</author>
|
||||
|
||||
<parameter type="list" name="Measurement" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0">
|
||||
<parameter type="list" name="Measurement" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0" listitemtype="double">
|
||||
<paramlistdisplay>RGB,Y'PbPr - rec. 601,Y'PbPr - rec. 709,HSV,HSL</paramlistdisplay>
|
||||
<name>Measurement</name>
|
||||
</parameter>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<name>Length</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Channel" default="0.5" paramlist="0.0;0.2;0.4;0.5;0.6;0.8;1.0">
|
||||
<parameter type="list" name="Channel" default="0.5" paramlist="0.0;0.2;0.4;0.5;0.6;0.8;1.0" listitemtype="double">
|
||||
<paramlistdisplay>R,G,B,Y',Pr,Pb,Alpha</paramlistdisplay>
|
||||
<name>Channel</name>
|
||||
</parameter>
|
||||
@@ -81,7 +81,7 @@
|
||||
<name>256 scale</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Color" default="0.0" paramlist="0.0;1.0">
|
||||
<parameter type="list" name="Color" default="0.0" paramlist="0.0;1.0" listitemtype="double">
|
||||
<paramlistdisplay>CCIR rec. 601,CCIR rec. 709</paramlistdisplay>
|
||||
<name>Color</name>
|
||||
</parameter>
|
||||
|
||||
@@ -25,22 +25,22 @@
|
||||
<name>Delta B / I / I</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Selection subspace" default="0.0" paramlist="0.0;0.5;1.0">
|
||||
<parameter type="list" name="Selection subspace" default="0.0" paramlist="0.0;0.5;1.0" listitemtype="double">
|
||||
<paramlistdisplay>RGB,ABI,HCI</paramlistdisplay>
|
||||
<name>Selection subspace</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Subspace shape" default="0.5" paramlist="0.0;0.5;1.0">
|
||||
<parameter type="list" name="Subspace shape" default="0.5" paramlist="0.0;0.5;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Box,Ellipsoid,Diamond</paramlistdisplay>
|
||||
<name>Subspace shape</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Edge mode" default="0.0" paramlist="0.0;0.35;0.60;1.0">
|
||||
<parameter type="list" name="Edge mode" default="0.0" paramlist="0.0;0.35;0.60;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Hard,Fat,Normal,Skinny</paramlistdisplay>
|
||||
<name>Edge mode</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0">
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Write on clear,Max,Min,Add,Subtract</paramlistdisplay>
|
||||
<name>Operation</name>
|
||||
</parameter>
|
||||
@@ -60,17 +60,17 @@
|
||||
<name>Invert selection</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Selection subspace" default="0.0" paramlist="0.0;0.5;1.0">
|
||||
<parameter type="list" name="Selection subspace" default="0.0" paramlist="0.0;0.5;1.0" listitemtype="double">
|
||||
<paramlistdisplay>RGB,ABI,HCI</paramlistdisplay>
|
||||
<name>Selection subspace</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Subspace shape" default="0.5" paramlist="0.0;0.5;1.0">
|
||||
<parameter type="list" name="Subspace shape" default="0.5" paramlist="0.0;0.5;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Box,Ellipsoid,Diamond</paramlistdisplay>
|
||||
<name>Subspace shape</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Edge mode" default="0.9" paramlist="0.0;0.35;0.60;0.7;0.9">
|
||||
<parameter type="list" name="Edge mode" default="0.9" paramlist="0.0;0.35;0.60;0.7;0.9" listitemtype="double">
|
||||
<paramlistdisplay>Hard,Fat,Normal,Skinny,Slope</paramlistdisplay>
|
||||
<name>Edge mode</name>
|
||||
</parameter>
|
||||
@@ -91,7 +91,7 @@
|
||||
<name>Slope</name>
|
||||
</parameter>
|
||||
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0">
|
||||
<parameter type="list" name="Operation" default="0.0" paramlist="0.0;0.3;0.5;0.7;1.0" listitemtype="double">
|
||||
<paramlistdisplay>Write on clear,Max,Min,Add,Subtract</paramlistdisplay>
|
||||
<name>Operation</name>
|
||||
</parameter>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<name>Mute</name>
|
||||
<description>Mute clip</description>
|
||||
<author>Dan Dennedy</author>
|
||||
<parameter type="fixed" name="gain" max="0" min="0" default="0">
|
||||
<parameter type="fixed" name="gain" value="0">
|
||||
<name>Gain</name>
|
||||
</parameter>
|
||||
</effect>
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
<parameter type="geometry" name="composite.geometry" default="0%,0%:100%x100%" fixed="1" opacity="false">
|
||||
<name>Pan and Zoom</name>
|
||||
</parameter>
|
||||
<parameter type="fixed" name="filter_only" min="1" max="1" default="1" />
|
||||
<parameter type="fixed" name="filter_only" value="1" />
|
||||
</effect>
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
<parameter type="color" name="background" default="colour:0x00000000" alpha="1" paramprefix="colour:">
|
||||
<name>Background Color</name>
|
||||
</parameter>
|
||||
<parameter type="fixed" name="transition.keyed" max="1" min="1" default="1" />
|
||||
<parameter type="fixed" name="transition.always_active" max="1" min="1" default="1" />
|
||||
<parameter type="fixed" name="transition.keyed" value="1" />
|
||||
<parameter type="fixed" name="transition.always_active" value="1" />
|
||||
</effect>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
INSTALL (FILES
|
||||
|
||||
profiles.xml
|
||||
|
||||
DESTINATION ${DATA_INSTALL_DIR}/kdenlive/export)
|
||||
@@ -1,150 +0,0 @@
|
||||
<profiles version="0.1">
|
||||
<group name="HDV" renderer="avformat" extension="m2t" type="av">
|
||||
<profile name="PAL 1080 50i" standard="PAL" args="f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video s=1440x1080 vb=25000k g=12 trellis=1 mlt_profile=hdv_1080_50i pass=%passes" />
|
||||
<profile name="PAL 1080 25p" standard="PAL" args="f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video s=1440x1080 vb=25000k g=12 trellis=1 mlt_profile=hdv_1080_25p pass=%passes" />
|
||||
<profile name="PAL 720 25p" standard="PAL" args="f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video s=1280x720 vb=19700k g=12 trellis=1 mlt_profile=hdv_720_25p pass=%passes" />
|
||||
<profile name="NTSC 1080 60i" standard="NTSC" args="f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video s=1440x1080 vb=25000k g=15 trellis=1 mlt_profile=hdv_1080_60i pass=%passes" />
|
||||
<profile name="NTSC 1080 30p" standard="NTSC" args="f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video s=1440x1080 vb=25000k g=15 trellis=1 mlt_profile=hdv_1080_30p pass=%passes" />
|
||||
<profile name="NTSC 720 30p" standard="NTSC" args="f=mpegts acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video s=1280x720 vb=19700k g=15 trellis=1 mlt_profile=hdv_720_30p pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="Raw DV" renderer="avformat" type="av" extension="dv">
|
||||
<profile name="DV PAL 4:3" standard="PAL" args="f=dv pix_fmt=yuv420p s=720x576 mlt_profile=dv_pal" />
|
||||
<profile name="DV PAL 16:9" standard="PAL" args="f=dv pix_fmt=yuv420p s=720x576 mlt_profile=dv_pal_wide" />
|
||||
<profile name="DVCPRO25 PAL 4:3" standard="PAL" args="f=dv pix_fmt=yuv411p s=720x576 mlt_profile=dv_pal" />
|
||||
<profile name="DVCPRO25 PAL 16:9" standard="PAL" args="f=dv pix_fmt=yuv411p s=720x576 mlt_profile=dv_pal_wide" />
|
||||
<profile name="DVCPRO50 PAL 4:3" standard="PAL" args="f=dv pix_fmt=yuv422p s=720x576 mlt_profile=dv_pal" />
|
||||
<profile name="DVCPRO50 PAL 16:9" standard="PAL" args="f=dv pix_fmt=yuv422p s=720x576 mlt_profile=dv_pal_wide" />
|
||||
|
||||
<profile name="DV NTSC 4:3" standard="NTSC" args="f=dv pix_fmt=yuv411p s=720x480 mlt_profile=dv_ntsc" />
|
||||
<profile name="DV NTSC 16:9" standard="NTSC" args="f=dv pix_fmt=yuv411p s=720x480 mlt_profile=dv_ntsc_wide" />
|
||||
<profile name="DVCPRO25 NTSC 4:3" standard="NTSC" args="f=dv pix_fmt=yuv411p s=720x480 mlt_profile=dv_ntsc" />
|
||||
<profile name="DVCPRO25 NTSC 16:9" standard="NTSC" args="f=dv pix_fmt=yuv411p s=720x480 mlt_profile=dv_ntsc_wide" />
|
||||
<profile name="DVCPRO50 NTSC 4:3" standard="NTSC" args="f=dv pix_fmt=yuv422p s=720x480 mlt_profile=dv_ntsc" />
|
||||
<profile name="DVCPRO50 NTSC 16:9" standard="NTSC" args="f=dv pix_fmt=yuv422p s=720x480 mlt_profile=dv_ntsc_wide" />
|
||||
</group>
|
||||
|
||||
<group name="AVI DV" renderer="avformat" type="av" extension="avi">
|
||||
<profile name="DV PAL 4:3" standard="PAL" args="f=avi vcodec=dvvideo pix_fmt=yuv420p acodec=pcm_s16le s=720x576 mlt_profile=dv_pal" />
|
||||
<profile name="DV PAL 16:9" standard="PAL" args="f=avi vcodec=dvvideo pix_fmt=yuv420p acodec=pcm_s16le s=720x576 mlt_profile=dv_pal_wide" />
|
||||
<profile name="DVCPRO25 PAL 4:3" standard="PAL" args="f=avi vcodec=dvvideo pix_fmt=yuv411p acodec=pcm_s16le s=720x576 mlt_profile=dv_pal" />
|
||||
<profile name="DVCPRO25 PAL 16:9" standard="PAL" args="f=avi vcodec=dvvideo pix_fmt=yuv411p acodec=pcm_s16le s=720x576 mlt_profile=dv_pal_wide" />
|
||||
<profile name="DVCPRO50 PAL 4:3" standard="PAL" args="f=avi vcodec=dvvideo pix_fmt=yuv422p acodec=pcm_s16le s=720x576 mlt_profile=dv_pal" />
|
||||
<profile name="DVCPRO50 PAL 16:9" standard="PAL" args="f=avi vcodec=dvvideo pix_fmt=yuv422p acodec=pcm_s16le s=720x576 mlt_profile=dv_pal_wide" />
|
||||
|
||||
<profile name="DV NTSC 4:3" standard="NTSC" args="f=avi vcodec=dvvideo pix_fmt=yuv411p acodec=pcm_s16le s=720x480 mlt_profile=dv_ntsc" />
|
||||
<profile name="DV NTSC 16:9" standard="NTSC" args="f=avi vcodec=dvvideo pix_fmt=yuv411p acodec=pcm_s16le s=720x480 mlt_profile=dv_ntsc_wide" />
|
||||
<profile name="DVCPRO25 NTSC 4:3" standard="NTSC" args="f=avi vcodec=dvvideo pix_fmt=yuv411p acodec=pcm_s16le s=720x480 mlt_profile=dv_ntsc" />
|
||||
<profile name="DVCPRO25 NTSC 16:9" standard="NTSC" args="f=avi vcodec=dvvideo pix_fmt=yuv411p acodec=pcm_s16le s=720x480 mlt_profile=dv_ntsc_wide" />
|
||||
<profile name="DVCPRO50 NTSC 4:3" standard="NTSC" args="f=avi vcodec=dvvideo pix_fmt=yuv422p acodec=pcm_s16le s=720x480 mlt_profile=dv_ntsc" />
|
||||
<profile name="DVCPRO50 NTSC 16:9" standard="NTSC" args="f=avi vcodec=dvvideo pix_fmt=yuv422p acodec=pcm_s16le s=720x480 mlt_profile=dv_ntsc_wide" />
|
||||
</group>
|
||||
|
||||
<group name="DVD" renderer="avformat" type="av">
|
||||
<groupname id="dvd">DVD</groupname>
|
||||
<profile name="PAL 4:3 VOB" standard="PAL" extension="vob" args="f=dvd vcodec=mpeg2video acodec=ac3 vb=5000k maxrate=8000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 s=720x576 g=15 me_range=63 trellis=1 mlt_profile=dv_pal pass=%passes" />
|
||||
<profile name="PAL 16:9 VOB" standard="PAL" extension="vob" args="f=dvd vcodec=mpeg2video acodec=ac3 vb=5000k maxrate=8000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 s=720x576 g=15 me_range=63 trellis=1 mlt_profile=dv_pal_wide pass=%passes" />
|
||||
<profile name="NTSC 4:3 VOB" standard="NTSC" extension="vob" args="f=dvd vcodec=mpeg2video acodec=ac3 s=720x480 vb=6000k maxrate=9000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 g=18 me_range=63 trellis=1 mlt_profile=dv_ntsc pass=%passes" />
|
||||
<profile name="NTSC 16:9 VOB" standard="NTSC" extension="vob" args="f=dvd vcodec=mpeg2video acodec=ac3 s=720x480 vb=6000k maxrate=9000k minrate=0 bufsize=1835008 packetsize=2048 muxrate=10080000 ab=192k ar=48000 g=18 me_range=63 trellis=1 mlt_profile=dv_ntsc_wide pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="MPEG-2" renderer="avformat" extension="mpg" type="av">
|
||||
<profile name="MPEG-2" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000,18000,25000" defaultbitrate="12000" audiobitrates="64,128,192,256,384" defaultaudiobitrate="384"
|
||||
args="f=mpeg acodec=mp2 ab=%audiobitrate+'k' ar=48000 vcodec=mpeg2video minrate=0 vb=%bitrate+'k' bf=2 b_strategy=1 trellis=1 aspect=%dar pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="MPEG-4" renderer="avformat" extension="mp4" type="av">
|
||||
<profile name="MPEG-4/AAC" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000,18000,25000" defaultbitrate="12000" audiobitrates="64,128,192,256,384" defaultaudiobitrate="128"
|
||||
args="f=mp4 acodec=aac ab=%audiobitrate+'k' ar=44100 vcodec=mpeg4 minrate=0 vb=%bitrate+'k' aspect=%dar mbd=2 trellis=1 mv4=1 pass=%passes" />
|
||||
<profile name="MPEG-4/MP3" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000,18000,25000" defaultbitrate="12000" audiobitrates="64,128,192,256,384" defaultaudiobitrate="128"
|
||||
args="f=mp4 acodec=libmp3lame ab=%audiobitrate+'k' ar=44100 vcodec=mpeg4 minrate=0 vb=%bitrate+'k' aspect=%dar mbd=2 trellis=1 mv4=1 pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="XVid4" renderer="avformat" extension="avi" type="av">
|
||||
<profile name="XVid4" bitrates="400,600,800,1000,2000,4000,8000,10000,12000" defaultbitrate="8000"
|
||||
audiobitrates="64,128,192,256,384" defaultaudiobitrate="128" args="acodec=libmp3lame ab=%audiobitrate+'k' ar=44100 vcodec=libxvid minrate=0 vb=%bitrate+'k' aspect=%dar mbd=2 trellis=1 mv4=1 pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="H.264" renderer="avformat" extension="mp4" type="av">
|
||||
<profile name="H.264" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000,18000,25000" defaultbitrate="12000" audiobitrates="64,128,192,256,384" defaultaudiobitrate="384"
|
||||
args="f=mp4 hq=1 acodec=aac ab=%audiobitrate+'k' ar=48000 pix_fmt=yuv420p vcodec=libx264 minrate=0 vb=%bitrate+'k' g=250 bf=3 b_strategy=1 subcmp=2 cmp=2 coder=1 flags=+loop flags2=dct8x8 qmax=51 subq=7 qmin=10 qcomp=0.6 qdiff=4 trellis=1 aspect=%dar pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="Flash" renderer="avformat" extension="flv" type="av">
|
||||
<profile name="Flash" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000" defaultbitrate="8000"
|
||||
args="f=flv acodec=libmp3lame ab=128k ar=44100 vcodec=flv minrate=0 vb=%bitrate+'k' progressive=1 pass=%passes threads=1" />
|
||||
<profile name="Flash 720x576" standard="PAL" args="f=flv acodec=libmp3lame ab=128k ar=44100 vcodec=flv minrate=0 vb=12000k s=720x576 progressive=1 pass=%passes threads=1" />
|
||||
<profile name="Flash 720x480" standard="NTSC" args="f=flv acodec=libmp3lame ab=128k ar=44100 vcodec=flv minrate=0 vb=12000k s=720x480 progressive=1 pass=%passes threads=1" />
|
||||
</group>
|
||||
|
||||
<group name="RealVideo" renderer="avformat" extension="rm" type="av">
|
||||
<profile name="RealVideo" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000" defaultbitrate="8000"
|
||||
args="vcodec=rv20 acodec=ac3 minrate=0 vb=%bitrate+'k' ab=128k ar=44100 g=8 pass=%passes" />
|
||||
<profile name="RealVideo 720x576" standard="PAL" args="vcodec=rv20 acodec=ac3 minrate=0 vb=12000k ab=384k ar=48000 s=720x576 g=8 pass=%passes" />
|
||||
<profile name="RealVideo 720x480" standard="NTSC" args="vcodec=rv20 acodec=ac3 minrate=0 vb=12000k ab=384k ar=48000 s=720x480 g=8 pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="Theora" renderer="avformat" extension="ogv" type="av">
|
||||
<profile name="Theora" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000" defaultbitrate="8000"
|
||||
audiobitrates="64,128,192,256,384" defaultaudiobitrate="128" args="acodec=vorbis ab=%audiobitrate+'k' ar=44100 aq=50 vcodec=libtheora minrate=0 vb=%bitrate+'k' aspect=%dar pass=%passes" />
|
||||
<profile name="Theora 720x576" standard="PAL" args="acodec=vorbis ab=384k aq=30 ar=44100 vcodec=libtheora minrate=0 vb=12000k s=720x576 aspect=%dar pass=%passes" />
|
||||
<profile name="Theora 720x480" standard="NTSC" args="acodec=vorbis ab=384k aq=30 ar=44100 vcodec=libtheora minrate=0 vb=12000k s=720x480 aspect=%dar pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="WebM" renderer="avformat" extension="webm" type="av">
|
||||
<profile name="WebM" bitrates="200,400,600,800,1000,2000,4000,6000,8000,10000,12000,18000,25000" defaultbitrate="8000"
|
||||
audiobitrates="64,128,192,256,384" defaultaudiobitrate="128" args="acodec=vorbis ab=%audiobitrate+'k' ar=44100 aq=50 vcodec=libvpx minrate=0 vb=%bitrate+'k' aspect=%dar maxrate=%bitrate*2+'k' g=120 qmax=42 qmin=10" />
|
||||
</group>
|
||||
|
||||
<group name="Media players" renderer="avformat" type="av">
|
||||
<groupname id="mediaplayers">Media players</groupname>
|
||||
<profile name="Windows Media Player WMV V7" bitrates="400,1000,2000" defaultbitrate="2000"
|
||||
extension="avi" args="acodec=libmp3lame ab=128k ar=48000 ac=2 vcodec=wmv1 minrate=0 vb=%bitrate+'k' aspect=%dar pass=%passes" />
|
||||
<profile name="Apple Quicktime Player MPEG-4" bitrates="400,1000,2000" defaultbitrate="2000"
|
||||
extension="mov" args="acodec=aac ab=128k ac=2 ar=48000 vcodec=mpeg4 minrate=0 vb=%bitrate+'k' aspect=%dar pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="Web sites" renderer="avformat" type="av">
|
||||
<groupname id="websites">Web sites</groupname>
|
||||
<profile name="Dailymotion 320x240" extension="flv" args="f=flv acodec=libmp3lame ab=128k ar=44100 vcodec=flv minrate=0 vb=800k s=320x240 aspect=%dar trellis=1 pass=%passes" url="http://www.dailymotion.com/upload" />
|
||||
<profile name="Dailymotion 512x384" extension="mp4" args="f=mp4 acodec=aac ab=96k ar=44100 vcodec=libx264 minrate=0 vb=600k g=250 bf=3 s=512x384 aspect=%dar mbd=2 trellis=1 mv4=1 subq=7 qmin=10 qcomp=0.6 qdiff=4 qmax=51 pass=%passes" url="http://www.dailymotion.com/upload" />
|
||||
<profile name="Dailymotion 1280x720" extension="mp4" args="f=mp4 acodec=aac ab=96k ar=44100 vcodec=libx264 minrate=0 vb=1500k g=250 bf=3 s=1280x720 aspect=%dar mbd=2 trellis=1 mv4=1 subq=7 qmin=10 qcomp=0.6 qdiff=4 qmax=51 pass=%passes" url="http://www.dailymotion.com/upload" />
|
||||
<profile name="Vimeo 640x480" extension="mp4" args="f=mp4 acodec=aac ab=128k ar=44100 vcodec=libx264 minrate=0 vb=3000k g=250 bf=3 s=640x480 aspect=%dar mbd=2 trellis=1 mv4=1 subq=7 qmin=10 qcomp=0.6 qdiff=4 qmax=51 pass=%passes" url="http://www.vimeo.com/upload" />
|
||||
<profile name="Vimeo 1280x720" extension="mp4" args="f=mp4 acodec=aac ab=128k ar=44100 vcodec=libx264 minrate=0 vb=5000k g=250 bf=3 s=1280x720 aspect=%dar mbd=2 trellis=1 mv4=1 subq=7 qmin=10 qcomp=0.6 qdiff=4 qmax=51 pass=%passes" url="http://www.vimeo.com/upload" />
|
||||
<profile name="YouTube 640x480" extension="mp4" args="f=mp4 acodec=libmp3lame ab=128k ar=44100 vcodec=mpeg4 minrate=0 vb=800k s=640x480 aspect=%dar mbd=2 trellis=1 mv4=1 subq=7 qmin=10 qcomp=0.6 qdiff=4 qmax=51 pass=%passes" url="http://www.youtube.com/upload" />
|
||||
<profile name="YouTube 1280x720" extension="mp4" args="f=mp4 hq=1 acodec=aac ab=128k ar=44100 vcodec=mpeg4 minrate=0 vb=2000k s=1280x720 aspect=%dar mbd=2 trellis=1 mv4=1 subq=7 qmin=10 qcomp=0.6 qdiff=4 qmax=51 pass=%passes" url="http://www.youtube.com/upload" />
|
||||
</group>
|
||||
|
||||
|
||||
<group name="Wav" renderer="avformat" type="audio">
|
||||
<groupname id="audioonly">Audio only</groupname>
|
||||
<profile name="WAV 22050 KHz" extension="wav" args="f=wav ar=22050 video_off=1" />
|
||||
<profile name="WAV 32000 KHz" extension="wav" args="f=wav ar=32000 video_off=1" />
|
||||
<profile name="WAV 44100 KHz" extension="wav" args="f=wav ar=44100 video_off=1" />
|
||||
<profile name="WAV 48000 KHz" extension="wav" args="f=wav ar=48000 video_off=1" />
|
||||
</group>
|
||||
|
||||
<group name="Lossless/HQ" renderer="avformat" type="av">
|
||||
<groupname id="lossless">Lossless / HQ</groupname>
|
||||
<profile name="FFV1 lossless (video) + FLAC (sound)" extension="mkv" args="f=matroska acodec=flac ar=48000 ac=2 vcodec=ffv1 aspect=%dar" />
|
||||
<profile name="FFV1 lossless (video) + PCM (sound)" extension="mkv" args="f=matroska acodec=pcm_s16le ac=2 vcodec=ffv1 aspect=%dar" />
|
||||
<profile name="HuffYUV lossless (video) + PCM (sound)" extension="avi" args="f=avi acodec=pcm_s16le ac=2 vcodec=huffyuv aspect=%dar" />
|
||||
<profile name="MPEG-2 I-frame only (video) + MP2 (sound)" extension="mpg" args="f=mpeg acodec=mp2 ab=384k ar=48000 ac=2 vcodec=mpeg2video qscale=1 qmin=1 aspect=%dar intra=1" />
|
||||
<profile name="MPEG-4 I-frame only (video) + MP3 (sound)" extension="mp4" args="f=mp4 acodec=libmp3lame ab=384k ar=48000 ac=2 vcodec=mpeg4 qscale=1 qmin=1 aspect=%dar intra=1" />
|
||||
<profile name="H.264 I-frame only (video) + AAC (sound)" extension="mp4" args="f=mp4 acodec=aac ab=384k ar=48000 ac=2 pix_fmt=yuv420p vcodec=libx264 cqp=1 subq=1 qmax=1 qmin=1 qcomp=0.6 qdiff=0 coder=ac trellis=1 aspect=%dar intra=1" />
|
||||
<profile name="H.264 lossless slow (video) + PCM (sound)" extension="mkv" args="f=matroska acodec=pcm_s16le ac=2 pix_fmt=yuv420p vcodec=libx264 qp=0 preset=veryslow aspect=%dar" />
|
||||
<profile name="H.264 lossless fast (video) + PCM (sound)" extension="mkv" args="f=matroska acodec=pcm_s16le ac=2 pix_fmt=yuv420p vcodec=libx264 qp=0 preset=ultrafast aspect=%dar" />
|
||||
</group>
|
||||
|
||||
<group name="Apple" renderer="avformat" type="av">
|
||||
<groupname id="mobile">Mobile devices</groupname>
|
||||
<profile name="iPod Classic 500k" extension="m4v" args="s=320x240 aspect=%dar progressive=1 acodec=aac ab=128k vcodec=libx264 vb=500k flags=+loop cmp=+chroma partitions=+parti8x8+parti4x4+partp8x8+partb8x8 me_method=umh subq=5 me_range=16 g=250 keyint_min=25 sc_threshold=40 i_qfactor=0.71 qcomp=0.6 qmin=10 qmax=51 qdiff=4 directpred=1 trellis=1 coder=0 bf=0 refs=1 flags2=-wpred-dct8x8 level=13 maxrate=3000k bufsize=768k wpredp=0 bt=256k pass=%passes" />
|
||||
<profile name="iPhone/iPod Touch 700k" extension="m4v" args="s=480x320 aspect=%dar progressive=1 acodec=aac ab=128k vcodec=libx264 vb=700k flags=+loop cmp=+chroma partitions=+parti8x8+parti4x4+partp8x8+partb8x8 me_method=umh subq=7 me_range=16 g=250 keyint_min=25 sc_threshold=40 i_qfactor=0.71 qcomp=0.6 qmin=10 qmax=51 qdiff=4 directpred=1 trellis=1 coder=0 bf=0 refs=3 flags2=-wpred-dct8x8 level=30 maxrate=10000k bufsize=10000k wpredp=0 pass=%passes" />
|
||||
</group>
|
||||
|
||||
<group name="Android" renderer="avformat" type="av">
|
||||
<groupname id="mobile">Mobile devices</groupname>
|
||||
<profile name="480x320 700k" extension="mp4" args="s=480x320 aspect=%dar progressive=1 acodec=aac ab=128k vcodec=libx264 vb=700k flags=+loop cmp=+chroma partitions=+parti8x8+parti4x4+partp8x8+partb8x8 me_method=umh subq=7 me_range=16 g=250 keyint_min=25 sc_threshold=40 i_qfactor=0.71 qcomp=0.6 qmin=10 qmax=51 qdiff=4 directpred=1 trellis=1 coder=0 bf=0 refs=1 flags2=-wpred-dct8x8 level=30 maxrate=10000k bufsize=10000k wpredp=0 pass=%passes" />
|
||||
</group>
|
||||
|
||||
</profiles>
|
||||
145
git-workflow.svg
@@ -14,7 +14,7 @@
|
||||
height="800"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.1 r9760"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="git-workflow.svg"
|
||||
inkscape:export-filename="/tmp/kdenlive-git-workflow.png"
|
||||
inkscape:export-xdpi="90"
|
||||
@@ -72,15 +72,15 @@
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.70710678"
|
||||
inkscape:cx="774.51484"
|
||||
inkscape:cx="831.08338"
|
||||
inkscape:cy="378.04332"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="709"
|
||||
inkscape:window-x="-3"
|
||||
inkscape:window-y="-3"
|
||||
inkscape:window-width="1364"
|
||||
inkscape:window-height="713"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-nodes="false"
|
||||
@@ -137,29 +137,6 @@
|
||||
height="72"
|
||||
x="-789.76361"
|
||||
y="-244.63782" />
|
||||
<g
|
||||
id="g3850"
|
||||
transform="translate(20.681252,9.4129353)">
|
||||
<use
|
||||
height="1052.3622"
|
||||
width="744.09448"
|
||||
transform="translate(646.46509,470.75735)"
|
||||
id="use3816"
|
||||
xlink:href="#g3811"
|
||||
y="0"
|
||||
x="0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text2991"
|
||||
y="278.65509"
|
||||
x="94"
|
||||
style="font-size:30px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="278.65509"
|
||||
x="94"
|
||||
id="tspan2993"
|
||||
sodipodi:role="line">Release</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g3791"
|
||||
transform="translate(-181.31874,-86.712769)">
|
||||
@@ -199,7 +176,7 @@
|
||||
id="text3005"
|
||||
y="289.24088"
|
||||
x="461"
|
||||
style="font-size:30px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
style="font-size:30px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
|
||||
xml:space="preserve"><tspan
|
||||
y="289.24088"
|
||||
x="461"
|
||||
@@ -287,37 +264,6 @@
|
||||
id="tspan3884"
|
||||
x="678.7309"
|
||||
y="237.77515">Experimental features</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
x="25.45586"
|
||||
y="237.77515"
|
||||
id="text3886"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3888"
|
||||
x="25.45586"
|
||||
y="237.77515">Bugfix branches</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
|
||||
d="m 160.13708,65.079645 0,141.421365"
|
||||
id="path3909"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
x="87.681259"
|
||||
y="118.6328"
|
||||
id="text4541"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4543"
|
||||
x="92.775009"
|
||||
y="118.6328">Branch a tagged release </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="87.681259"
|
||||
y="138.6328"
|
||||
id="tspan5179">for working on urgent fixes</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)"
|
||||
d="m 539.28845,217.81471 0,-154.149285"
|
||||
@@ -410,7 +356,11 @@
|
||||
sodipodi:role="line"
|
||||
x="678.7309"
|
||||
y="10.682662"
|
||||
id="tspan5259">with the newest features</tspan></text>
|
||||
id="tspan5259">with the newest features.</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="678.7309"
|
||||
y="30.682663"
|
||||
id="tspan4410">Refactoring work is done here.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#484848;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
@@ -433,17 +383,6 @@
|
||||
id="tspan5177"
|
||||
x="-750.03271"
|
||||
y="-269.9263">Originals of the clones in the drawing</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
x="25.45586"
|
||||
y="270.67548"
|
||||
id="text5181"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5183"
|
||||
x="25.45586"
|
||||
y="270.67548">Urgent bugfixes are done here</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
@@ -460,59 +399,21 @@
|
||||
id="path5247"
|
||||
d="m 271.73042,5.8836853 154.14928,0"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text5249"
|
||||
y="294.68268"
|
||||
x="678.7309"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan5253"
|
||||
y="294.68268"
|
||||
x="678.7309"
|
||||
sodipodi:role="line">Normal development goes on here only</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
x="678.7309"
|
||||
y="324.26544"
|
||||
y="294.56696"
|
||||
id="text3179"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3181"
|
||||
x="678.7309"
|
||||
y="324.26544">For new features and non-trivial bugfixes</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3183"
|
||||
y="298.95975"
|
||||
x="25.45586"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="298.95975"
|
||||
x="25.45586"
|
||||
id="tspan3185"
|
||||
sodipodi:role="line">(No need to create a new branch</tspan><tspan
|
||||
y="318.95975"
|
||||
x="25.45586"
|
||||
y="294.56696">For new features and non-trivial bugfixes;</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3187">if no urgent bugfixes)</tspan></text>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3189"
|
||||
d="m 189.83556,207.32903 0,-141.421365"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3191"
|
||||
y="118.6328"
|
||||
x="207.04877"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:125%;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan3195"
|
||||
y="118.6328"
|
||||
x="207.04877"
|
||||
sodipodi:role="line">Bugfixes</tspan></text>
|
||||
x="678.7309"
|
||||
y="314.56696"
|
||||
id="tspan4408">each feature gets its branch</tspan></text>
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 274.35745,59.807513 425.6783,211.12836"
|
||||
@@ -556,5 +457,17 @@
|
||||
x="87.681259"
|
||||
y="425.27512"
|
||||
id="tspan3238">the feature branch is merged directly into Master.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="784.88855"
|
||||
y="609.08118"
|
||||
id="text4412"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="translate(-325.2691,-253.92633)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4414"
|
||||
x="784.88855"
|
||||
y="609.08118">E.g. movit, newTimeline, …</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
@@ -1,22 +0,0 @@
|
||||
INSTALL(FILES
|
||||
bi-linear_x.pgm
|
||||
bi-linear_y.pgm
|
||||
burst.pgm
|
||||
checkerboard_small.pgm
|
||||
clock.pgm
|
||||
cloud.pgm
|
||||
curtain.pgm
|
||||
horizontal_blinds.pgm
|
||||
linear_x.pgm
|
||||
linear_y.pgm
|
||||
radial-bars.pgm
|
||||
radial.pgm
|
||||
spiral.pgm
|
||||
spiral2.pgm
|
||||
square.pgm
|
||||
square2-bars.pgm
|
||||
square2.pgm
|
||||
symmetric_clock.pgm
|
||||
|
||||
DESTINATION ${DATA_INSTALL_DIR}/kdenlive/lumas)
|
||||
|
||||
1379
lumas/cloud.pgm
1213
lumas/curtain.pgm
209
lumas/radial.pgm
125
lumas/square.pgm
@@ -91,7 +91,7 @@ KUrl SamplePlugin::generatedClip(const QString &renderer, const QString &generat
|
||||
}
|
||||
else {
|
||||
// Countdown producer
|
||||
for (int i = 0; i < view.duration->value(); i++) {
|
||||
for (int i = 0; i < view.duration->value(); ++i) {
|
||||
// Create the producers
|
||||
args << "pango:" << "in=0" << QString("out=" + QString::number((int) fps * view.duration->value()));
|
||||
args << QString("text=" + QString::number(view.duration->value() - i));
|
||||
@@ -99,7 +99,7 @@ KUrl SamplePlugin::generatedClip(const QString &renderer, const QString &generat
|
||||
}
|
||||
}
|
||||
|
||||
args << "-consumer"<<QString("xml:%1").arg(view.path->url().path());
|
||||
args << "-consumer"<<QString::fromLatin1("xml:%1").arg(view.path->url().path());
|
||||
generatorProcess.start(renderer, args);
|
||||
if (generatorProcess.waitForFinished()) {
|
||||
if (generatorProcess.exitStatus() == QProcess::CrashExit) {
|
||||
|
||||
6
producers/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
INSTALL (FILES
|
||||
|
||||
ladspa_sine_oscillator.xml
|
||||
|
||||
DESTINATION ${DATA_INSTALL_DIR}/kdenlive/producers)
|
||||
|
||||
12
producers/ladspa_sine_oscillator.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE kpartgui>
|
||||
<producer tag="ladspa.1047" library="" id="ladspa.1047" ladspaid="1047" type="audio">
|
||||
<name>Sine Oscillator</name>
|
||||
<description>LADSPA audio effect</description>
|
||||
<author>Richard Furse (LADSPA example plugins)</author>
|
||||
<parameter type="float" name="0" max="15000" min="0" default="2400" suffix="Hz">
|
||||
<name>Frequency</name>
|
||||
</parameter>
|
||||
<parameter type="float" name="1" max="100" min="0" default="1">
|
||||
<name>Amplitude</name>
|
||||
</parameter>
|
||||
</effect>
|
||||
25
refactoring-doc/1408refactoring-notes
Normal file
@@ -0,0 +1,25 @@
|
||||
State of refactoring
|
||||
=========================
|
||||
|
||||
* Initial position: Problems with the old code
|
||||
The last time the code structure saw bigger changes had been the port to the KDE 4 libs. But even back
|
||||
then central parts had only been updated and the structure remained the same. Over the years a latitude
|
||||
of features were added.
|
||||
Most action happens in very few, very big classes. They are tightly coupled together. So to add a feature,
|
||||
changes across the code base are required. This complicates not only adding features even for developers
|
||||
who know Kdenlive well, but also makes the process of doing so quite error prone. The inevitably following
|
||||
bugs are quite hard to track down and even little fixes tend to introduce further bugs because of side effects.
|
||||
As over time this only gets worse, some fundamental changes seemed to be long overdue.
|
||||
|
||||
* Refactoring concepts
|
||||
To counter the mentioned problems key concepts were discussed in Randa 2011:
|
||||
* OOP! Object Oriented Programming does not simply mean putting code in classes. One class per logical unit, every class has a clear responsibility.
|
||||
The same applies to functions.
|
||||
* Separation in Model and View.
|
||||
* The two points mentioned above mean that when dealing with MLT in most case its one class per MLT class.
|
||||
* All this should lead to a well defined Kdenlive core accessible through an API for additional features.
|
||||
|
||||
* Current State of the refactoring branch
|
||||
EffectSystem -> does not follow MV paradigm
|
||||
Basic timeline action missing -> how to handle movement of clips accross tracks
|
||||
Some later additions hackish/unclean
|
||||
1979
refactoring-doc/ArchitectureModel.svg
Normal file
|
After Width: | Height: | Size: 112 KiB |
1510
refactoring-doc/ArchitectureView.svg
Normal file
|
After Width: | Height: | Size: 78 KiB |
854
refactoring-doc/Timeline_Snapping.svg
Normal file
@@ -0,0 +1,854 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="1549.194"
|
||||
height="1332.16"
|
||||
id="svg3337"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="Timeline_Snapping.svg">
|
||||
<defs
|
||||
id="defs3339">
|
||||
<marker
|
||||
markerWidth="13.96875"
|
||||
markerHeight="12.15625"
|
||||
orient="auto"
|
||||
id="marker6345">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
|
||||
d="M -12.068051,-5.618565 0.4541487,5.0000002e-6 -12.068051,5.618565"
|
||||
id="path6343"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:transform-center-x="5.8069513" />
|
||||
</marker>
|
||||
<marker
|
||||
markerWidth="13.96875"
|
||||
markerHeight="12.15625"
|
||||
orient="auto"
|
||||
id="marker6345-8">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
|
||||
d="M -12.068051,-5.618565 0.4541487,5.0000002e-6 -12.068051,5.618565"
|
||||
id="path6343-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:transform-center-x="5.8069513" />
|
||||
</marker>
|
||||
<marker
|
||||
markerWidth="13.96875"
|
||||
markerHeight="12.15625"
|
||||
orient="auto"
|
||||
id="marker6345-5">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
|
||||
d="M -12.068051,-5.618565 0.4541487,5.0000002e-6 -12.068051,5.618565"
|
||||
id="path6343-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:transform-center-x="5.8069513" />
|
||||
</marker>
|
||||
<marker
|
||||
markerWidth="13.96875"
|
||||
markerHeight="12.15625"
|
||||
orient="auto"
|
||||
id="marker6345-7">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
|
||||
d="M -12.068051,-5.618565 0.4541487,5.0000002e-6 -12.068051,5.618565"
|
||||
id="path6343-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:transform-center-x="5.8069513" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35355339"
|
||||
inkscape:cx="678.36725"
|
||||
inkscape:cy="684.94539"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
showborder="true"
|
||||
inkscape:window-width="1364"
|
||||
inkscape:window-height="713"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-center="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3391"
|
||||
empspacing="6"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
spacingx="20px"
|
||||
spacingy="20px"
|
||||
color="#808080"
|
||||
opacity="0.1254902"
|
||||
empcolor="#808080"
|
||||
empopacity="0.20392157"
|
||||
originx="440px"
|
||||
originy="423.28px" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3342">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(440,-143.48218)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:125%;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro Bold"
|
||||
x="-240"
|
||||
y="172.36218"
|
||||
id="text3345"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3347"
|
||||
x="-240"
|
||||
y="172.36218">Kdenlive Model: Timeline moving + snapping helper</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="232.36218"
|
||||
id="text3349"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="232.36218"
|
||||
id="tspan4823">When moving items in the timeline, we need “collision detection” and snapping.</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="252.36218"
|
||||
id="tspan4827">In the following example, the lighter clip is dragged over another clip. It cannot be dropped there.</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="272.36218"
|
||||
id="tspan4829">When dragging it to the left, the user would expect it to stick on the right of the other clip until </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="292.36218"
|
||||
id="tspan4831">it is dragged far enough that it can be inserted again.</tspan></text>
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3372"
|
||||
width="240"
|
||||
height="60"
|
||||
x="0"
|
||||
y="332.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3412"
|
||||
width="100"
|
||||
height="60"
|
||||
x="60"
|
||||
y="352.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4216"
|
||||
width="20"
|
||||
height="60"
|
||||
x="0"
|
||||
y="332.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4218"
|
||||
width="20"
|
||||
height="60"
|
||||
x="140"
|
||||
y="352.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4233"
|
||||
width="120"
|
||||
height="60"
|
||||
x="-180"
|
||||
y="332.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4220"
|
||||
width="20"
|
||||
height="60"
|
||||
x="-180"
|
||||
y="332.36218" />
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 160,432.36218 -160,0"
|
||||
id="path4241"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 160,452.36218 -340,0"
|
||||
id="path4243"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="167.26912"
|
||||
y="438.0582"
|
||||
id="text4815"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4817"
|
||||
x="167.26912"
|
||||
y="438.0582">10 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="167.61313"
|
||||
y="458.0582"
|
||||
id="text4819"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4821"
|
||||
x="167.61313"
|
||||
y="458.0582">20 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="512.36218"
|
||||
id="text4833"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4835"
|
||||
x="-240"
|
||||
y="512.36218">If a clip cannot be moved to the current mouse position, the helper calculates two points:</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="532.36218"
|
||||
id="tspan4839">The shortest distance to the left and to the right where insertion is possible again. For all</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="552.36218"
|
||||
id="tspan4843">of those points, we know that the right edge of the selected (i.e. dragged) clip must be adjacent</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="572.36218"
|
||||
id="tspan4847">to a left edge of an unselected clip—otherwise we could move it a few frames to the right.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="612.36218"
|
||||
id="text3019"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3021"
|
||||
x="-240"
|
||||
y="612.36218">The following algorithm can be used to find the next matching point:</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="632.65387"
|
||||
id="tspan3023">1. Create a list of possible positions (how many frames Δf to move) for the selected clip</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="652.9455"
|
||||
id="tspan3025">2. Sort the list ascendingly, so the smallest Δf is taken first</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="672.9455"
|
||||
id="tspan3027">3. Test all positions in order, and return the first one where no overlaps occur.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="712.36218"
|
||||
id="text3029"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3031"
|
||||
x="-240"
|
||||
y="712.36218">If multiple clips are selected and moved together, step 1 needs to be repeated for all clips</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="732.36218"
|
||||
id="tspan3033">in the selection. Example:</tspan></text>
|
||||
<g
|
||||
id="g3967">
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="-220"
|
||||
height="60"
|
||||
width="100"
|
||||
id="rect3035"
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="100"
|
||||
height="60"
|
||||
width="80"
|
||||
id="rect3854"
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="100"
|
||||
height="60"
|
||||
width="20"
|
||||
id="rect3898"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="-220"
|
||||
height="60"
|
||||
width="20"
|
||||
id="rect3900"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
id="g3961">
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="120"
|
||||
height="60"
|
||||
width="60"
|
||||
id="rect3856"
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="240"
|
||||
height="60"
|
||||
width="100"
|
||||
id="rect3858"
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="160"
|
||||
height="60"
|
||||
width="20"
|
||||
id="rect3888"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="320"
|
||||
height="60"
|
||||
width="20"
|
||||
id="rect3896"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 180,872.36218 -80,0"
|
||||
id="path3902"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 180,892.36218 -400,0"
|
||||
id="path3904"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 340,912.36218 -240,0"
|
||||
id="path3906"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 340,932.36218 -560,0"
|
||||
id="path3908"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="187.26912"
|
||||
y="878.05817"
|
||||
id="text3910"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3912"
|
||||
x="187.26912"
|
||||
y="878.05817">10 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="347.69312"
|
||||
y="918.05817"
|
||||
id="text3914"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3916"
|
||||
x="347.69312"
|
||||
y="918.05817">30 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="187.70113"
|
||||
y="898.05817"
|
||||
id="text3918"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3920"
|
||||
x="187.70113"
|
||||
y="898.05817">50 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="347.54913"
|
||||
y="938.05817"
|
||||
id="text3922"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3924"
|
||||
x="347.54913"
|
||||
y="938.05817">70 f</tspan></text>
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot3926"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"><flowRegion
|
||||
id="flowRegion3928"><rect
|
||||
id="rect3930"
|
||||
width="88"
|
||||
height="26"
|
||||
x="429"
|
||||
y="654.36218" /></flowRegion><flowPara
|
||||
id="flowPara3932" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="992.36218"
|
||||
id="text3957"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3959"
|
||||
x="-240"
|
||||
y="992.36218">This would lead to the following tests (the vertical offset is just for clarity; </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="1012.3622"
|
||||
id="tspan4115">clips are all on the same track):</tspan></text>
|
||||
<g
|
||||
id="g3973"
|
||||
transform="translate(0,280)">
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3975"
|
||||
width="100"
|
||||
height="20"
|
||||
x="-220"
|
||||
y="772.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3977"
|
||||
width="80"
|
||||
height="20"
|
||||
x="100"
|
||||
y="772.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3979"
|
||||
width="20"
|
||||
height="20"
|
||||
x="100"
|
||||
y="772.36218" />
|
||||
</g>
|
||||
<g
|
||||
id="g3983"
|
||||
transform="translate(-80,280)">
|
||||
<rect
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3985"
|
||||
width="60"
|
||||
height="20"
|
||||
x="120"
|
||||
y="792.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3987"
|
||||
width="100"
|
||||
height="20"
|
||||
x="240"
|
||||
y="792.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3989"
|
||||
width="20"
|
||||
height="20"
|
||||
x="160"
|
||||
y="792.36218" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,360)"
|
||||
id="g3993">
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="-220"
|
||||
height="20"
|
||||
width="100"
|
||||
id="rect3995"
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="100"
|
||||
height="20"
|
||||
width="80"
|
||||
id="rect3997"
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="100"
|
||||
height="20"
|
||||
width="20"
|
||||
id="rect3999"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-240,360)"
|
||||
id="g4003">
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="120"
|
||||
height="20"
|
||||
width="60"
|
||||
id="rect4005"
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="240"
|
||||
height="20"
|
||||
width="100"
|
||||
id="rect4007"
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="320"
|
||||
height="20"
|
||||
width="20"
|
||||
id="rect4011"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
id="g4013"
|
||||
transform="translate(0,440)">
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4015"
|
||||
width="100"
|
||||
height="20"
|
||||
x="-220"
|
||||
y="772.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4017"
|
||||
width="80"
|
||||
height="20"
|
||||
x="100"
|
||||
y="772.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4021"
|
||||
width="20"
|
||||
height="20"
|
||||
x="-220"
|
||||
y="772.36218" />
|
||||
</g>
|
||||
<g
|
||||
id="g4023"
|
||||
transform="translate(-400,440)">
|
||||
<rect
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4025"
|
||||
width="60"
|
||||
height="20"
|
||||
x="120"
|
||||
y="792.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4027"
|
||||
width="100"
|
||||
height="20"
|
||||
x="240"
|
||||
y="792.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4029"
|
||||
width="20"
|
||||
height="20"
|
||||
x="160"
|
||||
y="792.36218" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,520)"
|
||||
id="g4033">
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="-220"
|
||||
height="20"
|
||||
width="100"
|
||||
id="rect4035"
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="100"
|
||||
height="20"
|
||||
width="80"
|
||||
id="rect4037"
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="772.36218"
|
||||
x="-220"
|
||||
height="20"
|
||||
width="20"
|
||||
id="rect4041"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-560,520)"
|
||||
id="g4043">
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="120"
|
||||
height="20"
|
||||
width="60"
|
||||
id="rect4045"
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="240"
|
||||
height="20"
|
||||
width="100"
|
||||
id="rect4047"
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="792.36218"
|
||||
x="320"
|
||||
height="20"
|
||||
width="20"
|
||||
id="rect4051"
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4056"
|
||||
d="m 180,1092.3622 -80,0"
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4058"
|
||||
y="1098.0582"
|
||||
x="187.26912"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="1098.0582"
|
||||
x="187.26912"
|
||||
id="tspan4060"
|
||||
sodipodi:role="line">10 f</tspan></text>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4062"
|
||||
d="m 180,1172.3622 -240,0"
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4064"
|
||||
y="1178.0582"
|
||||
x="187.69312"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="1178.0582"
|
||||
x="187.69312"
|
||||
id="tspan4066"
|
||||
sodipodi:role="line">30 f</tspan></text>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4068"
|
||||
d="m 180,1252.3622 -400,0"
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4070"
|
||||
y="1258.0582"
|
||||
x="187.70113"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="1258.0582"
|
||||
x="187.70113"
|
||||
id="tspan4072"
|
||||
sodipodi:role="line">50 f</tspan></text>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4074"
|
||||
d="m 180,1332.3622 -560,0"
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4076"
|
||||
y="1338.0582"
|
||||
x="187.54913"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
xml:space="preserve"><tspan
|
||||
y="1338.0582"
|
||||
x="187.54913"
|
||||
id="tspan4078"
|
||||
sodipodi:role="line">70 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="1392.3622"
|
||||
id="text4117"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4119"
|
||||
x="-240"
|
||||
y="1392.3622">Tests 1, 2, and 4 match here. The algorithm would stop after test 1.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="-240"
|
||||
y="1452.3622"
|
||||
id="text4121"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4123"
|
||||
x="-240"
|
||||
y="1452.3622">This algorithm can be extended to multiple tracks as it has been extended to multiple clips</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-240"
|
||||
y="1472.3622"
|
||||
id="tspan4125">per selection. </tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="540"
|
||||
y="232.36218"
|
||||
id="text4127"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4129"
|
||||
x="540"
|
||||
y="232.36218">Another application of this algorithm is snapping to adjacent clips. The difference</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="252.36218"
|
||||
id="tspan4131">is minor: Instead of trying to find the first place to the left (when dragging the clip </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="272.36218"
|
||||
id="tspan4133">this way) where we can put the selected clip, we search for the first place where </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="292.36218"
|
||||
id="tspan4135">another clip stops the selected one.</tspan></text>
|
||||
<rect
|
||||
style="color:#000000;fill:#d4d4d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3112"
|
||||
width="140"
|
||||
height="60"
|
||||
x="580"
|
||||
y="332.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#e9e9e9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3114"
|
||||
width="140"
|
||||
height="60"
|
||||
x="880"
|
||||
y="352.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4218-0"
|
||||
width="20"
|
||||
height="60"
|
||||
x="880"
|
||||
y="352.36218" />
|
||||
<rect
|
||||
style="color:#000000;fill:#5b5b5b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4218-4"
|
||||
width="20"
|
||||
height="60"
|
||||
x="700"
|
||||
y="332.36218" />
|
||||
<path
|
||||
style="opacity:0.2893082;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#marker6345);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 880,432.36218 -160,0"
|
||||
id="path3964"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="887.2691"
|
||||
y="438.0582"
|
||||
id="text3966"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3968"
|
||||
x="887.2691"
|
||||
y="438.0582">15 f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="540"
|
||||
y="492.36218"
|
||||
id="text3993"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="492.36218"
|
||||
id="tspan4001">In this case, the helper takes the left edge of the selected clip and compares it to the</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="512.36218"
|
||||
id="tspan4011">right edge of the clip to the left of it. This way the helper can give feedback about</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="532.36218"
|
||||
id="tspan4015">where snapping is possible.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="540"
|
||||
y="592.36218"
|
||||
id="text4017"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4019"
|
||||
x="540"
|
||||
y="592.36218">Performance of the algorithm can be improved by e.g. considering the visible part</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="540"
|
||||
y="612.36218"
|
||||
id="tspan4021">of the timeline only, or by limiting the number of “lookahead steps” in a different way.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Source Sans Pro;-inkscape-font-specification:Source Sans Pro"
|
||||
x="920"
|
||||
y="172.36221"
|
||||
id="text4023"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4025"
|
||||
x="920"
|
||||
y="172.36221">Author: Simon A. Eugster</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 40 KiB |
1563
refactoring-doc/Timeline_TransitionView.svg
Normal file
|
After Width: | Height: | Size: 82 KiB |
43
refactoring-doc/timeline-operations
Normal file
@@ -0,0 +1,43 @@
|
||||
* How operations on clips in the timeline are implemented (in the model)
|
||||
|
||||
TimelineClip->setIn (in: number of frames relative to uncut clip (same as in MLT))
|
||||
->setInOut()
|
||||
TimelineClip->setOut(out: number of frames relative to uncut clip (same as in MLT))
|
||||
->setInOut()
|
||||
TimelineClip->setInOut(in, out)
|
||||
=> ResizeClipCommand: * does not do any safety checks for available space!
|
||||
* resizes the clip's producer,
|
||||
* does not change its position when changing the in point!
|
||||
* makes the clip emit resized()
|
||||
|
||||
TimelineClip->setPosition(position, track)
|
||||
=> MoveClipCommand: * does not do any safety checks for available space!
|
||||
* inserts the same producer cut at the requested position (if on same track)
|
||||
* inserts a new producer cut at the requested position on the requested track,
|
||||
as avformat clips require on base producer per track (audio bugs, search ml (kdenlive-devel, mlt-devel) for more info),
|
||||
it asks the the ProjectClip (through TimelineClip) for the base producer associated with this track, then uses it
|
||||
to create a cut and insert it.
|
||||
* notifies the affacted tracks, so they can update their stored clip indices
|
||||
* makes the clip emit moved()
|
||||
|
||||
To create a TimelineClip:
|
||||
ProjectClip->createInstance()
|
||||
To remove a TimelineClip:
|
||||
TimelineClip->remove() -> ProjectClip->removeInstance()
|
||||
|
||||
=> 4 basic operations: add, remove, resize, move
|
||||
These four operations should be enough to achieve everything imaginable,
|
||||
without the need to use the MLT API.
|
||||
Because they do not perform safety checks they should never be used directly (without performing checks).
|
||||
As set of "compiled operations" can be directly used from the UI or from plugins.
|
||||
|
||||
|
||||
Moving Helper:
|
||||
The UI can use a moving helper from the model, to check if a move is allowed,
|
||||
the moving helper provides alternative positions if a move is not possible, or because of snapping.
|
||||
|
||||
|
||||
Regarding groups/selections:
|
||||
They do not fit into the timeline tree (timeline->tracks->clips), and they do not represent a Mlt producer.
|
||||
Instead they are some sort of meta clip. They forward operations applied on them to their member clips,
|
||||
adding some safety checks and taking care of the right order.
|
||||
@@ -1,21 +0,0 @@
|
||||
set(QT_DONT_USE_QTGUI 1)
|
||||
set(QT_USE_QTDBUS 1)
|
||||
|
||||
set(kdenlive_render_SRCS
|
||||
kdenlive_render.cpp
|
||||
renderjob.cpp
|
||||
)
|
||||
|
||||
kde4_add_executable(kdenlive_render ${kdenlive_render_SRCS})
|
||||
|
||||
include_directories(
|
||||
${QT_INCLUDES}
|
||||
)
|
||||
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
target_link_libraries(kdenlive_render
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS kdenlive_render DESTINATION ${BIN_INSTALL_DIR})
|
||||
@@ -1,141 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "renderjob.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QStringList args = app.arguments();
|
||||
QStringList preargs;
|
||||
QString locale;
|
||||
int pid = 0;
|
||||
int in = -1;
|
||||
int out = -1;
|
||||
if (args.count() >= 7) {
|
||||
// Remove program name
|
||||
args.removeFirst();
|
||||
|
||||
bool erase = false;
|
||||
if (args.at(0) == "-erase") {
|
||||
erase = true;
|
||||
args.removeFirst();
|
||||
}
|
||||
bool usekuiserver = false;
|
||||
if (args.at(0) == "-kuiserver") {
|
||||
usekuiserver = true;
|
||||
args.removeFirst();
|
||||
}
|
||||
if (QString(args.at(0)).startsWith("-pid:")) {
|
||||
pid = QString(args.at(0)).section(':', 1).toInt();
|
||||
args.removeFirst();
|
||||
}
|
||||
|
||||
if (QString(args.at(0)).startsWith("-locale:")) {
|
||||
locale = QString(args.at(0)).section(':', 1);
|
||||
args.removeFirst();
|
||||
}
|
||||
if (args.at(0).startsWith("in="))
|
||||
in = args.takeFirst().section('=', -1).toInt();
|
||||
if (args.at(0).startsWith("out="))
|
||||
out = args.takeFirst().section('=', -1).toInt();
|
||||
if (args.at(0).startsWith("preargs="))
|
||||
preargs = args.takeFirst().section('=', 1).split(' ', QString::SkipEmptyParts);
|
||||
|
||||
QString render = args.takeFirst();
|
||||
QString profile = args.takeFirst();
|
||||
QString rendermodule = args.takeFirst();
|
||||
QString player = args.takeFirst();
|
||||
QByteArray srcString = args.takeFirst().toUtf8();
|
||||
QUrl srcurl = QUrl::fromEncoded(srcString);
|
||||
QString src = srcurl.path();
|
||||
// The QUrl path() strips the consumer: protocol, so re-add it if necessary
|
||||
if (srcString.startsWith("consumer:"))
|
||||
src.prepend("consumer:");
|
||||
QUrl desturl = QUrl::fromEncoded(args.takeFirst().toUtf8());
|
||||
QString dest = desturl.path();
|
||||
bool dualpass = false;
|
||||
bool doerase;
|
||||
QString vpre;
|
||||
|
||||
int vprepos = args.indexOf(QRegExp("vpre=.*"));
|
||||
if (vprepos >= 0) {
|
||||
vpre=args.at(vprepos);
|
||||
}
|
||||
QStringList vprelist = vpre.replace("vpre=", "").split(',');
|
||||
if (vprelist.size() > 0) {
|
||||
args.replaceInStrings(QRegExp("^vpre=.*"), QString("vpre=").append(vprelist.at(0)));
|
||||
}
|
||||
|
||||
if (args.contains("pass=2")) {
|
||||
// dual pass encoding
|
||||
dualpass = true;
|
||||
doerase = false;
|
||||
args.replace(args.indexOf("pass=2"), "pass=1");
|
||||
if (args.contains("vcodec=libx264")) args << QString("passlogfile=%1").arg(dest + ".log");
|
||||
} else {
|
||||
args.removeAll("pass=1");
|
||||
doerase = erase;
|
||||
}
|
||||
|
||||
// Decode metadata
|
||||
for (int i = 0; i < args.count(); ++i) {
|
||||
if (args.at(i).startsWith("meta.attr")) {
|
||||
QString data = args.at(i);
|
||||
args.replace(i, data.section('=', 0, 0) + "=\"" + QUrl::fromPercentEncoding(data.section('=', 1).toUtf8()) + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "//STARTING RENDERING: " << erase << "," << usekuiserver << "," << render << "," << profile << "," << rendermodule << "," << player << "," << src << "," << dest << "," << preargs << "," << args << "," << in << "," << out ;
|
||||
RenderJob *job = new RenderJob(doerase, usekuiserver, pid, render, profile, rendermodule, player, src, dest, preargs, args, in, out);
|
||||
if (!locale.isEmpty()) job->setLocale(locale);
|
||||
job->start();
|
||||
if (dualpass) {
|
||||
if (vprelist.size()>1)
|
||||
args.replaceInStrings(QRegExp("^vpre=.*"),QString("vpre=").append(vprelist.at(1)));
|
||||
args.replace(args.indexOf("pass=1"), "pass=2");
|
||||
RenderJob *dualjob = new RenderJob(erase, usekuiserver, pid, render, profile, rendermodule, player, src, dest, preargs, args, in, out);
|
||||
QObject::connect(job, SIGNAL(renderingFinished()), dualjob, SLOT(start()));
|
||||
}
|
||||
app.exec();
|
||||
} else {
|
||||
fprintf(stderr, "Kdenlive video renderer for MLT.\nUsage: "
|
||||
"kdenlive_render [-erase] [-kuiserver] [-locale:LOCALE] [in=pos] [out=pos] [render] [profile] [rendermodule] [player] [src] [dest] [[arg1] [arg2] ...]\n"
|
||||
" -erase: if that parameter is present, src file will be erased at the end\n"
|
||||
" -kuiserver: if that parameter is present, use KDE job tracker\n"
|
||||
" -locale:LOCALE : set a locale for rendering. For example, -locale:fr_FR.UTF-8 will use a french locale (comma as numeric separator)\n"
|
||||
" in=pos: start rendering at frame pos\n"
|
||||
" out=pos: end rendering at frame pos\n"
|
||||
" render: path to MLT melt renderer\n"
|
||||
" profile: the MLT video profile\n"
|
||||
" rendermodule: the MLT consumer used for rendering, usually it is avformat\n"
|
||||
" player: path to video player to play when rendering is over, use '-' to disable playing\n"
|
||||
" src: source file (usually MLT XML)\n"
|
||||
" dest: destination file\n"
|
||||
" args: space separated libavformat arguments\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "renderjob.h"
|
||||
|
||||
#include <stdlib.h> // for getenv, posix portable to Windows: http://msdn.microsoft.com/en-us/library/tehxacec(VS.80).aspx
|
||||
|
||||
#include <QtDBus>
|
||||
#include <QFile>
|
||||
#include <QThread>
|
||||
#include <QStringList>
|
||||
|
||||
|
||||
// Can't believe I need to do this to sleep.
|
||||
class SleepThread : QThread
|
||||
{
|
||||
public:
|
||||
virtual void run() {}
|
||||
static void msleep(unsigned long msecs) {
|
||||
QThread::msleep(msecs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
RenderJob::RenderJob(bool erase, bool usekuiserver, int pid, const QString& renderer, const QString& profile, const QString& rendermodule, const QString& player, const QString& scenelist, const QString& dest, const QStringList& preargs, const QStringList& args, int in, int out) :
|
||||
QObject(),
|
||||
m_jobUiserver(NULL),
|
||||
m_kdenliveinterface(NULL),
|
||||
m_usekuiserver(usekuiserver),
|
||||
m_enablelog(false),
|
||||
m_pid(pid)
|
||||
{
|
||||
m_scenelist = scenelist;
|
||||
m_dest = dest;
|
||||
m_player = player;
|
||||
m_progress = 0;
|
||||
m_erase = erase;
|
||||
m_renderProcess = new QProcess;
|
||||
|
||||
// Disable VDPAU so that rendering will work even if there is a Kdenlive instance using VDPAU
|
||||
#if QT_VERSION >= 0x040600
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("MLT_NO_VDPAU", "1");
|
||||
m_renderProcess->setProcessEnvironment(env);
|
||||
#else
|
||||
QStringList env = QProcess::systemEnvironment();
|
||||
env << "MLT_NO_VDPAU=1";
|
||||
m_renderProcess->setEnvironment(env);
|
||||
#endif
|
||||
|
||||
m_prog = renderer;
|
||||
m_args << scenelist;
|
||||
if (in != -1) m_args << "in=" + QString::number(in);
|
||||
if (out != -1) m_args << "out=" + QString::number(out);
|
||||
|
||||
m_args << preargs;
|
||||
//qDebug()<<"PRE ARGS: "<<preargs;
|
||||
if (scenelist.startsWith("consumer:")) {
|
||||
// Use MLT's producer_consumer, needs a different syntax for profile:
|
||||
m_args << "profile=" + profile;
|
||||
} else m_args << "-profile" << profile;
|
||||
m_args << "-consumer" << rendermodule + ':' + m_dest << "progress=1" << args;
|
||||
|
||||
m_dualpass = false;
|
||||
if (args.contains("pass=1")) m_dualpass = true;
|
||||
|
||||
connect(m_renderProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotCheckProcess(QProcess::ProcessState)));
|
||||
m_renderProcess->setReadChannel(QProcess::StandardError);
|
||||
|
||||
m_enablelog = (getenv("KDENLIVE_RENDER_LOG") != NULL);
|
||||
if (m_enablelog) {
|
||||
// Create a log of every render process.
|
||||
m_logfile.setAutoRemove(false);
|
||||
m_logfile.setFileTemplate(QDir::tempPath() + "/kdenlive_render.log.XXXXXXXX");
|
||||
if (m_logfile.open()) {
|
||||
qDebug() << "Writing render log to " << m_logfile.fileName();
|
||||
|
||||
} else {
|
||||
qDebug() << "Unable to log to " << m_logfile.fileName();
|
||||
}
|
||||
m_logstream.setDevice(&m_logfile);
|
||||
QString tmplist = scenelist;
|
||||
if (tmplist.contains("consumer:")) {
|
||||
QStringList tl = tmplist.split("consumer:");
|
||||
if (tl.count() == 2) {
|
||||
tmplist = tl[1];
|
||||
}
|
||||
}
|
||||
m_logstream << "Log starting. Dumping contents of " << tmplist << endl;
|
||||
QFile file(tmplist);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
m_logstream << "Unable to read contents of " << tmplist << endl;
|
||||
} else {
|
||||
m_logstream.flush();
|
||||
QTextStream in(&file);
|
||||
m_logstream << in.readAll() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RenderJob::~RenderJob()
|
||||
{
|
||||
delete m_renderProcess;
|
||||
if (m_enablelog) {
|
||||
m_logfile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderJob::setLocale(const QString &locale)
|
||||
{
|
||||
#if QT_VERSION >= 0x040600
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("LC_NUMERIC", locale);
|
||||
m_renderProcess->setProcessEnvironment(env);
|
||||
#else
|
||||
QStringList env = QProcess::systemEnvironment();
|
||||
env << QString("LC_NUMERIC=%1").arg(locale);
|
||||
m_renderProcess->setEnvironment(env);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RenderJob::slotAbort(const QString& url)
|
||||
{
|
||||
if (m_dest == url) slotAbort();
|
||||
}
|
||||
|
||||
void RenderJob::slotAbort()
|
||||
{
|
||||
qDebug() << "Kdenlive-render: JOB ABORTED BY USER...";
|
||||
m_renderProcess->kill();
|
||||
|
||||
if (m_kdenliveinterface) {
|
||||
m_dbusargs[1] = -3;
|
||||
m_dbusargs.append(QString());
|
||||
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, "setRenderingFinished", m_dbusargs);
|
||||
}
|
||||
if (m_jobUiserver) m_jobUiserver->call("terminate", QString());
|
||||
if (m_erase) {
|
||||
QFile f(m_scenelist);
|
||||
f.remove();
|
||||
}
|
||||
QFile f(m_dest);
|
||||
f.remove();
|
||||
if (m_enablelog) {
|
||||
m_logstream << "Job aborted by user" << endl;
|
||||
m_logstream.flush();
|
||||
m_logfile.close();
|
||||
}
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
void RenderJob::receivedStderr()
|
||||
{
|
||||
QString result = QString(m_renderProcess->readAllStandardError()).simplified();
|
||||
//fprintf(stderr, "* * * *RENDER LG: %s\n", result.toUtf8().data());
|
||||
if (!result.startsWith("Current Frame")) m_errorMessage.append(result + "<br>");
|
||||
else {
|
||||
if (m_enablelog) m_logstream << "ReceivedStderr from melt: " << result << endl;
|
||||
result = result.section(' ', -1);
|
||||
int pro = result.toInt();
|
||||
if (pro < 0 || pro > 100) return;
|
||||
if (pro > m_progress) {
|
||||
m_progress = pro;
|
||||
if (m_args.contains("pass=1")) {
|
||||
m_progress /= 2.0;
|
||||
} else if (m_args.contains("pass=2")) {
|
||||
m_progress = 50 + m_progress / 2.0;
|
||||
}
|
||||
if (m_kdenliveinterface) {
|
||||
if (!m_kdenliveinterface->isValid()) {
|
||||
delete m_kdenliveinterface;
|
||||
m_kdenliveinterface = NULL;
|
||||
// qDebug() << "BROKEN COMMUNICATION WITH KDENLIVE";
|
||||
} else {
|
||||
m_dbusargs[1] = m_progress;
|
||||
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, "setRenderingProgress", m_dbusargs);
|
||||
}
|
||||
} else if (pro % 5 == 0) {
|
||||
// Try to restart communication with Kdenlive every 5 percents
|
||||
// qDebug() << "TRYING TO RESTART COMMUNICATION WITH KDENLIVE";
|
||||
initKdenliveDbusInterface();
|
||||
}
|
||||
|
||||
if (m_jobUiserver) {
|
||||
m_jobUiserver->call("setPercent", (uint) m_progress);
|
||||
/*int seconds = m_startTime.secsTo(QTime::currentTime());
|
||||
seconds = seconds * (100 - m_progress) / m_progress;
|
||||
m_jobUiserver->call("setDescriptionField", (uint) 1, tr("Remaining time"), QTime().addSecs(seconds).toString("hh:mm:ss"));*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderJob::start()
|
||||
{
|
||||
QDBusConnectionInterface* interface = QDBusConnection::sessionBus().interface();
|
||||
if (interface && m_usekuiserver) {
|
||||
if (!interface->isServiceRegistered("org.kde.JobViewServer")) {
|
||||
qDebug() << "No org.kde.JobViewServer registered, trying to start kuiserver";
|
||||
if (m_enablelog) m_logstream << "No org.kde.JobViewServer registered, trying to start kuiserver";
|
||||
if (QProcess::startDetached("kuiserver")) {
|
||||
qDebug() << "Started kuiserver";
|
||||
if (m_enablelog) m_logstream << "Started kuiserver";
|
||||
// Give it a couple of seconds to start
|
||||
QTime t;
|
||||
t.start();
|
||||
while (!interface->isServiceRegistered("org.kde.JobViewServer") && t.elapsed() < 3000) {
|
||||
SleepThread::msleep(100); //Sleep 100 ms
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Failed to start kuiserver";
|
||||
if (m_enablelog) m_logstream << "Failed to start kuiserver";
|
||||
}
|
||||
}
|
||||
|
||||
if (interface->isServiceRegistered("org.kde.JobViewServer")) {
|
||||
QDBusInterface kuiserver("org.kde.JobViewServer", "/JobViewServer", "org.kde.JobViewServer");
|
||||
QDBusReply<QDBusObjectPath> objectPath = kuiserver.call("requestView", "Kdenlive", "kdenlive", 0x0001);
|
||||
QString reply = ((QDBusObjectPath) objectPath).path();
|
||||
|
||||
// Use of the KDE JobViewServer is an ugly hack, it is not reliable
|
||||
QString dbusView = "org.kde.JobViewV2";
|
||||
m_jobUiserver = new QDBusInterface("org.kde.JobViewServer", reply, dbusView);
|
||||
if (!m_jobUiserver || !m_jobUiserver->isValid()) {
|
||||
dbusView = "org.kde.JobView";
|
||||
m_jobUiserver = new QDBusInterface("org.kde.JobViewServer", reply, dbusView);
|
||||
}
|
||||
|
||||
if (m_jobUiserver && m_jobUiserver->isValid()) {
|
||||
m_startTime = QTime::currentTime();
|
||||
if (!m_args.contains("pass=2"))
|
||||
m_jobUiserver->call("setPercent", (uint) 0);
|
||||
//m_jobUiserver->call("setInfoMessage", tr("Rendering %1").arg(QFileInfo(m_dest).fileName()));
|
||||
m_jobUiserver->call("setDescriptionField", (uint) 0, tr("Rendering"), m_dest);
|
||||
QDBusConnection::sessionBus().connect("org.kde.JobViewServer", reply, dbusView, "cancelRequested", this, SLOT(slotAbort()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initKdenliveDbusInterface();
|
||||
|
||||
// Make sure the destination file is writable
|
||||
QFile checkDestination(m_dest);
|
||||
if (!checkDestination.open(QIODevice::WriteOnly)) {
|
||||
slotIsOver(QProcess::NormalExit, false);
|
||||
}
|
||||
checkDestination.close();
|
||||
|
||||
// Because of the logging, we connect to stderr in all cases.
|
||||
connect(m_renderProcess, SIGNAL(readyReadStandardError()), this, SLOT(receivedStderr()));
|
||||
m_renderProcess->start(m_prog, m_args);
|
||||
if (m_enablelog) m_logstream << "Started render process: " << m_prog << " " << m_args.join(" ") << endl;
|
||||
qDebug() << "Started render process: " << m_prog << " " << m_args.join(" ");
|
||||
}
|
||||
|
||||
|
||||
void RenderJob::initKdenliveDbusInterface()
|
||||
{
|
||||
QString kdenliveId;
|
||||
QDBusConnection connection = QDBusConnection::sessionBus();
|
||||
QDBusConnectionInterface* ibus = connection.interface();
|
||||
kdenliveId = QString("org.kde.kdenlive-%1").arg(m_pid);
|
||||
if (!ibus->isServiceRegistered(kdenliveId))
|
||||
{
|
||||
kdenliveId.clear();
|
||||
const QStringList services = ibus->registeredServiceNames();
|
||||
foreach(const QString & service, services) {
|
||||
if (!service.startsWith("org.kde.kdenlive"))
|
||||
continue;
|
||||
kdenliveId = service;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_dbusargs.clear();
|
||||
if (kdenliveId.isEmpty()) return;
|
||||
m_kdenliveinterface = new QDBusInterface(kdenliveId,
|
||||
"/MainWindow",
|
||||
"org.kdenlive.MainWindow",
|
||||
connection,
|
||||
this);
|
||||
|
||||
if (m_kdenliveinterface) {
|
||||
m_dbusargs.append(m_dest);
|
||||
m_dbusargs.append((int) 0);
|
||||
if (!m_args.contains("pass=2"))
|
||||
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, "setRenderingProgress", m_dbusargs);
|
||||
connect(m_kdenliveinterface, SIGNAL(abortRenderJob(QString)),
|
||||
this, SLOT(slotAbort(QString)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderJob::slotCheckProcess(QProcess::ProcessState state)
|
||||
{
|
||||
if (state == QProcess::NotRunning) slotIsOver(m_renderProcess->exitStatus());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RenderJob::slotIsOver(QProcess::ExitStatus status, bool isWritable)
|
||||
{
|
||||
if (m_jobUiserver) m_jobUiserver->call("terminate", QString());
|
||||
if (!isWritable) {
|
||||
QString error = tr("Cannot write to %1, check the permissions.").arg(m_dest);
|
||||
if (m_kdenliveinterface) {
|
||||
m_dbusargs[1] = (int) - 2;
|
||||
m_dbusargs.append(error);
|
||||
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, "setRenderingFinished", m_dbusargs);
|
||||
}
|
||||
QStringList args;
|
||||
args << "--error" << error;
|
||||
if (m_enablelog) m_logstream << error << endl;
|
||||
qDebug() << error;
|
||||
QProcess::startDetached("kdialog", args);
|
||||
qApp->quit();
|
||||
}
|
||||
if (m_erase) {
|
||||
QFile f(m_scenelist);
|
||||
f.remove();
|
||||
}
|
||||
if (status == QProcess::CrashExit || m_renderProcess->error() != QProcess::UnknownError) {
|
||||
// rendering crashed
|
||||
if (m_kdenliveinterface) {
|
||||
m_dbusargs[1] = (int) - 2;
|
||||
m_dbusargs.append(m_errorMessage);
|
||||
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, "setRenderingFinished", m_dbusargs);
|
||||
}
|
||||
QStringList args;
|
||||
QString error = tr("Rendering of %1 aborted, resulting video will probably be corrupted.").arg(m_dest);
|
||||
args << "--error" << error;
|
||||
if (m_enablelog) m_logstream << error << endl;
|
||||
qDebug() << error;
|
||||
QProcess::startDetached("kdialog", args);
|
||||
qApp->quit();
|
||||
} else {
|
||||
if (!m_dualpass && m_kdenliveinterface) {
|
||||
m_dbusargs[1] = (int) - 1;
|
||||
m_dbusargs.append(QString());
|
||||
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, "setRenderingFinished", m_dbusargs);
|
||||
}
|
||||
QDBusConnectionInterface* interface = QDBusConnection::sessionBus().interface();
|
||||
if (!m_dualpass && interface && interface->isServiceRegistered("org.kde.knotify")) {
|
||||
QDBusMessage m = QDBusMessage::createMethodCall("org.kde.knotify",
|
||||
"/Notify",
|
||||
"org.kde.KNotify",
|
||||
"event");
|
||||
int seconds = m_startTime.secsTo(QTime::currentTime());
|
||||
QList<QVariant> args;
|
||||
args.append(QString("RenderFinished")); // action name
|
||||
args.append(QString("kdenlive")); // app name
|
||||
args.append(QVariantList()); // contexts
|
||||
args.append(tr("Rendering of %1 finished in %2").arg(m_dest, QTime(0, 0, seconds).toString("hh:mm:ss"))); // body
|
||||
args.append(QByteArray()); // app icon
|
||||
QStringList actionList;
|
||||
args.append(actionList); // actions
|
||||
qlonglong wid = 0;
|
||||
args.append(wid); // win id
|
||||
|
||||
m.setArguments(args);
|
||||
QDBusMessage replyMsg = QDBusConnection::sessionBus().call(m);
|
||||
}
|
||||
if (m_enablelog) m_logstream << "Rendering of " << m_dest << " finished" << endl;
|
||||
qDebug() << "Rendering of " << m_dest << " finished";
|
||||
if (!m_dualpass && m_player != "-") {
|
||||
if (m_enablelog) m_logstream << "Starting player" << endl;
|
||||
QStringList args;
|
||||
args << m_dest;
|
||||
QProcess::startDetached(m_player, args);
|
||||
}
|
||||
if (m_dualpass) {
|
||||
emit renderingFinished();
|
||||
deleteLater();
|
||||
} else qApp->quit();
|
||||
}
|
||||
}
|
||||
|
||||
#include "renderjob.moc"
|
||||
@@ -1,80 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef RENDERJOB_H
|
||||
#define RENDERJOB_H
|
||||
|
||||
#include <QProcess>
|
||||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
#include <QTime>
|
||||
// Testing
|
||||
#include <QTemporaryFile>
|
||||
#include <QTextStream>
|
||||
|
||||
class RenderJob : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RenderJob(bool erase, bool usekuiserver, int pid, const QString& renderer, const QString& profile, const QString& rendermodule, const QString& player, const QString& scenelist, const QString& dest, const QStringList& preargs, const QStringList& args, int in = -1, int out = -1);
|
||||
~RenderJob();
|
||||
void setLocale(const QString &locale);
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
|
||||
private slots:
|
||||
void slotIsOver(QProcess::ExitStatus status, bool isWritable = true);
|
||||
void receivedStderr();
|
||||
void slotAbort();
|
||||
void slotAbort(const QString& url);
|
||||
void slotCheckProcess(QProcess::ProcessState state);
|
||||
|
||||
private:
|
||||
QString m_scenelist;
|
||||
QString m_dest;
|
||||
int m_progress;
|
||||
QProcess* m_renderProcess;
|
||||
QString m_errorMessage;
|
||||
QString m_prog;
|
||||
QString m_player;
|
||||
QStringList m_args;
|
||||
bool m_erase;
|
||||
bool m_dualpass;
|
||||
QDBusInterface* m_jobUiserver;
|
||||
QDBusInterface* m_kdenliveinterface;
|
||||
QList<QVariant> m_dbusargs;
|
||||
QTime m_startTime;
|
||||
void initKdenliveDbusInterface();
|
||||
bool m_usekuiserver;
|
||||
bool m_enablelog;
|
||||
/** @brief Used to create a temporary file for logging. */
|
||||
QTemporaryFile m_logfile;
|
||||
/** @brief Used to write to the log file. */
|
||||
QTextStream m_logstream;
|
||||
/** @brief The process id of the Kdenlive instance, used to get the dbus service. */
|
||||
int m_pid;
|
||||
|
||||
signals:
|
||||
void renderingFinished();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,9 @@ set(QT_USE_QTSVG 1)
|
||||
set(QT_USE_QTXML 1)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
find_package(GLEW REQUIRED)
|
||||
|
||||
if(APPLE)
|
||||
find_package(SDL REQUIRED)
|
||||
endif(APPLE)
|
||||
@@ -33,6 +36,13 @@ if(WITH_JogShuttle)
|
||||
endif(HAVE_LINUX_INPUT_H)
|
||||
endif(WITH_JogShuttle)
|
||||
|
||||
macro_log_feature(GLEW_FOUND
|
||||
"GLEW"
|
||||
"OpenGL Extension Wrangler Library (GLEW)"
|
||||
""
|
||||
TRUE
|
||||
)
|
||||
|
||||
macro_log_feature(QT_QTOPENGL_FOUND
|
||||
"QtOpenGL"
|
||||
"Qt bindings for the OpenGL library"
|
||||
@@ -79,223 +89,14 @@ macro_log_feature(QJSON_FOUND
|
||||
"Required to build the rotoscoping filter and for Freesound.org queries"
|
||||
)
|
||||
|
||||
|
||||
add_subdirectory(beziercurve)
|
||||
add_subdirectory(colorcorrection)
|
||||
add_subdirectory(commands)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(projecttree)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(databackup)
|
||||
add_subdirectory(effectstack)
|
||||
add_subdirectory(mimetypes)
|
||||
add_subdirectory(onmonitoritems)
|
||||
add_subdirectory(scopes)
|
||||
add_subdirectory(simplekeyframes)
|
||||
add_subdirectory(stopmotion)
|
||||
|
||||
if(QJSON_FOUND)
|
||||
add_subdirectory(onmonitoritems/rotoscoping)
|
||||
add_subdirectory(rotoscoping)
|
||||
endif(QJSON_FOUND)
|
||||
|
||||
if(BUILD_V4L)
|
||||
add_subdirectory(v4l)
|
||||
endif(BUILD_V4L)
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(plugins)
|
||||
|
||||
list(APPEND kdenlive_SRCS
|
||||
main.cpp
|
||||
mainwindow.cpp
|
||||
|
||||
KoSliderCombo.cpp
|
||||
abstractclipitem.cpp
|
||||
abstractgroupitem.cpp
|
||||
abstractmonitor.cpp
|
||||
archivewidget.cpp
|
||||
choosecolorwidget.cpp
|
||||
clipdurationdialog.cpp
|
||||
clipitem.cpp
|
||||
clipmanager.cpp
|
||||
clipproperties.cpp
|
||||
cliptranscode.cpp
|
||||
clipstabilize.cpp
|
||||
colorpickerwidget.cpp
|
||||
colorplaneexport.cpp
|
||||
colortools.cpp
|
||||
complexparameter.cpp
|
||||
cornerswidget.cpp
|
||||
customruler.cpp
|
||||
customtrackscene.cpp
|
||||
customtrackview.cpp
|
||||
definitions.cpp
|
||||
docclipbase.cpp
|
||||
documentchecker.cpp
|
||||
documentvalidator.cpp
|
||||
doubleparameterwidget.cpp
|
||||
dragvalue.cpp
|
||||
dvdwizard.cpp
|
||||
dvdwizardchapters.cpp
|
||||
dvdwizardmenu.cpp
|
||||
dvdwizardvob.cpp
|
||||
effectslist.cpp
|
||||
effectslistview.cpp
|
||||
effectslistwidget.cpp
|
||||
effectstackedit.cpp
|
||||
encodingprofilesdialog.cpp
|
||||
folderprojectitem.cpp
|
||||
gentime.cpp
|
||||
geometryval.cpp
|
||||
geometrywidget.cpp
|
||||
graphicsscenerectmove.cpp
|
||||
guide.cpp
|
||||
headertrack.cpp
|
||||
initeffects.cpp
|
||||
kdenlivedoc.cpp
|
||||
kdenlivesettingsdialog.cpp
|
||||
keyframeedit.cpp
|
||||
keyframehelper.cpp
|
||||
kis_cubic_curve.cpp
|
||||
kis_curve_widget.cpp
|
||||
kthumb.cpp
|
||||
managecapturesdialog.cpp
|
||||
markerdialog.cpp
|
||||
mltdevicecapture.cpp
|
||||
monitor.cpp
|
||||
monitoreditwidget.cpp
|
||||
monitormanager.cpp
|
||||
monitorscene.cpp
|
||||
noteswidget.cpp
|
||||
parameterplotter.cpp
|
||||
positionedit.cpp
|
||||
profilesdialog.cpp
|
||||
projectitem.cpp
|
||||
projectlist.cpp
|
||||
projectlistview.cpp
|
||||
projectsettings.cpp
|
||||
recmonitor.cpp
|
||||
renderer.cpp
|
||||
renderwidget.cpp
|
||||
slideshowclip.cpp
|
||||
smallruler.cpp
|
||||
spacerdialog.cpp
|
||||
statusbarmessagelabel.cpp
|
||||
subprojectitem.cpp
|
||||
timecode.cpp
|
||||
timecodedisplay.cpp
|
||||
titledocument.cpp
|
||||
titlewidget.cpp
|
||||
trackdialog.cpp
|
||||
tracksconfigdialog.cpp
|
||||
trackview.cpp
|
||||
transition.cpp
|
||||
transitionsettings.cpp
|
||||
unicodedialog.cpp
|
||||
wizard.cpp
|
||||
)
|
||||
|
||||
kde4_add_ui_files(kdenlive_UIS
|
||||
widgets/addtrack_ui.ui
|
||||
widgets/archivewidget_ui.ui
|
||||
widgets/audiospectrum_ui.ui
|
||||
widgets/backupdialog_ui.ui
|
||||
widgets/bezierspline_ui.ui
|
||||
widgets/boolval_ui.ui
|
||||
widgets/clipdurationdialog_ui.ui
|
||||
widgets/clipproperties_ui.ui
|
||||
widgets/cliptranscode_ui.ui
|
||||
widgets/collapsiblewidget_ui.ui
|
||||
widgets/clipstabilize_ui.ui
|
||||
widgets/colorclip_ui.ui
|
||||
widgets/colorplaneexport_ui.ui
|
||||
widgets/configcapture_ui.ui
|
||||
widgets/configenv_ui.ui
|
||||
widgets/configjogshuttle_ui.ui
|
||||
widgets/configmisc_ui.ui
|
||||
widgets/configproject_ui.ui
|
||||
widgets/configsdl_ui.ui
|
||||
widgets/configtimeline_ui.ui
|
||||
widgets/configtranscode_ui.ui
|
||||
widgets/dvdwizardchapters_ui.ui
|
||||
widgets/dvdwizardmenu_ui.ui
|
||||
widgets/dvdwizardstatus_ui.ui
|
||||
widgets/dvdwizardvob_ui.ui
|
||||
widgets/effectlist_ui.ui
|
||||
widgets/effectstack_ui.ui
|
||||
widgets/effectstack2_ui.ui
|
||||
widgets/freesound_ui.ui
|
||||
widgets/geometryval_ui.ui
|
||||
widgets/geometrywidget_ui.ui
|
||||
widgets/histogram_ui.ui
|
||||
widgets/keyframedialog_ui.ui
|
||||
widgets/keyframeeditor_ui.ui
|
||||
widgets/keyframewidget_ui.ui
|
||||
widgets/listval_ui.ui
|
||||
widgets/managecaptures_ui.ui
|
||||
widgets/manageencodingprofile_ui.ui
|
||||
widgets/markerdialog_ui.ui
|
||||
widgets/missingclips_ui.ui
|
||||
widgets/monitoreditwidget_ui.ui
|
||||
widgets/profiledialog_ui.ui
|
||||
widgets/projectsettings_ui.ui
|
||||
widgets/recmonitor_ui.ui
|
||||
widgets/renderwidget_ui.ui
|
||||
widgets/rgbparade_ui.ui
|
||||
widgets/saveprofile_ui.ui
|
||||
widgets/slideshowclip_ui.ui
|
||||
widgets/smconfig_ui.ui
|
||||
widgets/spacerdialog_ui.ui
|
||||
widgets/spectrogram_ui.ui
|
||||
widgets/stopmotion_ui.ui
|
||||
widgets/templateclip_ui.ui
|
||||
widgets/timeline_ui.ui
|
||||
widgets/timelinebuttons_ui.ui
|
||||
widgets/titlewidget_ui.ui
|
||||
widgets/trackheader_ui.ui
|
||||
widgets/tracksconfigdialog_ui.ui
|
||||
widgets/transitionsettings_ui.ui
|
||||
widgets/unicodewidget_ui.ui
|
||||
widgets/urlval_ui.ui
|
||||
widgets/vectorscope_ui.ui
|
||||
widgets/waveform_ui.ui
|
||||
widgets/wipeval_ui.ui
|
||||
widgets/wizardcapture_ui.ui
|
||||
widgets/wizardcheck_ui.ui
|
||||
widgets/wizardextra_ui.ui
|
||||
widgets/wizardmltcheck_ui.ui
|
||||
widgets/wizardstandard_ui.ui
|
||||
widgets/keywordval_ui.ui
|
||||
widgets/fontval_ui.ui
|
||||
widgets/cutjobdialog_ui.ui
|
||||
widgets/scenecutdialog_ui.ui
|
||||
widgets/importkeyframesdialog_ui.ui
|
||||
)
|
||||
|
||||
if(OPENGL_FOUND)
|
||||
list(APPEND kdenlive_SRCS videoglwidget.cpp)
|
||||
endif(OPENGL_FOUND)
|
||||
|
||||
if(BUILD_JogShuttle)
|
||||
list(APPEND kdenlive_SRCS
|
||||
jogaction.cpp
|
||||
jogshuttle.cpp
|
||||
jogshuttleconfig.cpp
|
||||
)
|
||||
endif(BUILD_JogShuttle)
|
||||
|
||||
kde4_add_kcfg_files(kdenlive_SRCS kdenlivesettings.kcfgc)
|
||||
qt4_add_dbus_adaptor(kdenlive_SRCS
|
||||
org.kdenlive.MainWindow.xml
|
||||
mainwindow.h
|
||||
MainWindow
|
||||
)
|
||||
qt4_add_resources(kdenlive_SRCS widgets/resources.qrc)
|
||||
kde4_add_executable(kdenlive
|
||||
${kdenlive_SRCS}
|
||||
${kdenlive_UIS}
|
||||
)
|
||||
|
||||
# To compile kiss_fft.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --std=c99")
|
||||
|
||||
# KDE definitions and include directories *must* always come first, Qt follows
|
||||
# (to avoid breaking builds when KDE and/or Qt are installed to different
|
||||
@@ -303,10 +104,13 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --std=c99")
|
||||
add_definitions(${KDE4_DEFINITIONS})
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/src/core
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${KDE4_INCLUDES} # Adds Qt include directories too.
|
||||
${LIBMLT_INCLUDE_DIR}
|
||||
${LIBMLTPLUS_INCLUDE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
|
||||
@@ -314,6 +118,19 @@ include_directories(
|
||||
# to the components requested in find_package().
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
|
||||
# qt4_add_dbus_adaptor(kdenlive_SRCS
|
||||
# org.kdenlive.MainWindow.xml
|
||||
# mainwindow.h
|
||||
# MainWindow
|
||||
# )
|
||||
kde4_add_executable(kdenlive
|
||||
${kdenlive_SRCS}
|
||||
)
|
||||
|
||||
# To compile kiss_fft.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --std=c99")
|
||||
|
||||
if(${KDE_VERSION} VERSION_LESS 4.3.80)
|
||||
set(KDE4_KNEWSTUFF_LIBS ${KDE4_KNEWSTUFF2_LIBS})
|
||||
else(${KDE_VERSION} VERSION_LESS 4.3.80)
|
||||
@@ -321,6 +138,7 @@ else(${KDE_VERSION} VERSION_LESS 4.3.80)
|
||||
endif(${KDE_VERSION} VERSION_LESS 4.3.80)
|
||||
|
||||
target_link_libraries(kdenlive
|
||||
kdenlivecore
|
||||
${KDE4_KDEUI_LIBS}
|
||||
${KDE4_KIO_LIBS}
|
||||
${KDE4_KNEWSTUFF_LIBS}
|
||||
@@ -377,19 +195,11 @@ if(BUILD_JogShuttle)
|
||||
endif(BUILD_JogShuttle)
|
||||
|
||||
install(TARGETS kdenlive DESTINATION ${BIN_INSTALL_DIR})
|
||||
install(FILES
|
||||
kdenliveui.rc
|
||||
kdenlive.notifyrc
|
||||
DESTINATION ${DATA_INSTALL_DIR}/kdenlive
|
||||
)
|
||||
install(FILES kdenlivesettings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
|
||||
install(FILES
|
||||
kdenlive_projectprofiles.knsrc
|
||||
kdenlive_renderprofiles.knsrc
|
||||
kdenlive_titles.knsrc
|
||||
kdenlive_wipes.knsrc
|
||||
kdenlivetranscodingrc
|
||||
DESTINATION ${CONFIG_INSTALL_DIR}
|
||||
)
|
||||
# install(FILES
|
||||
# kdenliveui.rc
|
||||
# kdenlive.notifyrc
|
||||
# DESTINATION ${DATA_INSTALL_DIR}/kdenlive
|
||||
# )
|
||||
|
||||
kde4_install_icons(${ICON_INSTALL_DIR})
|
||||
install(FILES kdenlive.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (c) 2007 Casper Boemann <cbr@boemann.dk>
|
||||
Copyright (c) 2010 Jean-Baptiste Mardelle <jb@kdenlive.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "KoSliderCombo.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QApplication>
|
||||
#include <QSize>
|
||||
#include <QSlider>
|
||||
#include <QStyle>
|
||||
#include <QStylePainter>
|
||||
#include <QStyleOptionSlider>
|
||||
#include <QLineEdit>
|
||||
#include <QValidator>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFrame>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include <kglobal.h>
|
||||
#include <klocale.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
class KoSliderComboContainer : public QMenu
|
||||
{
|
||||
public:
|
||||
KoSliderComboContainer(KoSliderCombo *parent) : QMenu(parent), m_parent(parent) {}
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *e);
|
||||
private:
|
||||
KoSliderCombo *m_parent;
|
||||
};
|
||||
|
||||
void KoSliderComboContainer::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
QStyleOptionComboBox opt;
|
||||
opt.init(m_parent);
|
||||
opt.subControls = QStyle::SC_All;
|
||||
opt.activeSubControls = QStyle::SC_ComboBoxArrow;
|
||||
QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
|
||||
m_parent->mapFromGlobal(e->globalPos()),
|
||||
m_parent);
|
||||
if (sc == QStyle::SC_ComboBoxArrow)
|
||||
setAttribute(Qt::WA_NoMouseReplay);
|
||||
QMenu::mousePressEvent(e);
|
||||
}
|
||||
|
||||
class KoSliderCombo::KoSliderComboPrivate
|
||||
{
|
||||
public:
|
||||
KoSliderCombo *thePublic;
|
||||
QValidator *m_validator;
|
||||
QTimer m_timer;
|
||||
KoSliderComboContainer *container;
|
||||
QSlider *slider;
|
||||
QStyle::StateFlag arrowState;
|
||||
qreal minimum;
|
||||
qreal maximum;
|
||||
int decimals;
|
||||
bool firstShowOfSlider;
|
||||
|
||||
void showPopup();
|
||||
void hidePopup();
|
||||
|
||||
void sliderValueChanged(int value);
|
||||
void sliderReleased();
|
||||
void lineEditFinished();
|
||||
};
|
||||
|
||||
KoSliderCombo::KoSliderCombo(QWidget *parent)
|
||||
: QComboBox(parent)
|
||||
, d(new KoSliderComboPrivate())
|
||||
{
|
||||
d->thePublic = this;
|
||||
d->minimum = 0.0;
|
||||
d->maximum = 100.0;
|
||||
d->decimals = 2;
|
||||
d->container = new KoSliderComboContainer(this);
|
||||
d->container->setAttribute(Qt::WA_WindowPropagation);
|
||||
QStyleOptionComboBox opt;
|
||||
opt.init(this);
|
||||
// d->container->setFrameStyle(style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, this));
|
||||
|
||||
d->slider = new QSlider(Qt::Horizontal);
|
||||
d->slider->setMinimum(0);
|
||||
d->slider->setMaximum(256);
|
||||
d->slider->setPageStep(10);
|
||||
d->slider->setValue(0);
|
||||
// When set to true, causes flicker on Qt 4.6. Any reason to keep it?
|
||||
d->firstShowOfSlider = false; //true;
|
||||
|
||||
QHBoxLayout * l = new QHBoxLayout();
|
||||
l->setMargin(2);
|
||||
l->setSpacing(2);
|
||||
l->addWidget(d->slider);
|
||||
d->container->setLayout(l);
|
||||
d->container->resize(200, 30);
|
||||
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
setEditable(true);
|
||||
setEditText(KGlobal::locale()->formatNumber(0, d->decimals));
|
||||
|
||||
connect(d->slider, SIGNAL(valueChanged(int)), SLOT(sliderValueChanged(int)));
|
||||
connect(d->slider, SIGNAL(sliderReleased()), SLOT(sliderReleased()));
|
||||
connect(lineEdit(), SIGNAL(editingFinished()), SLOT(lineEditFinished()));
|
||||
}
|
||||
|
||||
KoSliderCombo::~KoSliderCombo()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
QSize KoSliderCombo::sizeHint() const
|
||||
{
|
||||
return minimumSizeHint();
|
||||
}
|
||||
|
||||
QSize KoSliderCombo::minimumSizeHint() const
|
||||
{
|
||||
QSize sh;
|
||||
|
||||
const QFontMetrics &fm = fontMetrics();
|
||||
|
||||
sh.setWidth(5 * fm.width(QLatin1Char('8')));
|
||||
sh.setHeight(qMax(fm.lineSpacing(), 14) + 2);
|
||||
|
||||
// add style and strut values
|
||||
QStyleOptionComboBox opt;
|
||||
opt.init(this);
|
||||
opt.subControls = QStyle::SC_All;
|
||||
opt.editable = true;
|
||||
sh = style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, this);
|
||||
|
||||
return sh.expandedTo(QApplication::globalStrut());
|
||||
}
|
||||
|
||||
void KoSliderCombo::KoSliderComboPrivate::showPopup()
|
||||
{
|
||||
if (firstShowOfSlider) {
|
||||
container->show(); //show container a bit early so the slider can be layout'ed
|
||||
firstShowOfSlider = false;
|
||||
}
|
||||
|
||||
QStyleOptionSlider opt;
|
||||
opt.init(slider);
|
||||
opt.maximum = 256;
|
||||
opt.sliderPosition = opt.sliderValue = slider->value();
|
||||
int hdlPos = thePublic->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle).center().x();
|
||||
|
||||
QStyleOptionComboBox optThis;
|
||||
optThis.init(thePublic);
|
||||
optThis.subControls = QStyle::SC_All;
|
||||
optThis.editable = true;
|
||||
int arrowPos = thePublic->style()->subControlRect(QStyle::CC_ComboBox, &optThis, QStyle::SC_ComboBoxArrow).center().x();
|
||||
|
||||
QSize popSize = container->size();
|
||||
QRect popupRect(thePublic->mapToGlobal(QPoint(arrowPos - hdlPos - slider->x(), thePublic->size().height())), popSize);
|
||||
|
||||
// Make sure the popup is not drawn outside the screen area
|
||||
QRect screenRect = QApplication::desktop()->availableGeometry(thePublic);
|
||||
if (popupRect.right() > screenRect.right())
|
||||
popupRect.translate(screenRect.right() - popupRect.right(), 0);
|
||||
if (popupRect.left() < screenRect.left())
|
||||
popupRect.translate(screenRect.left() - popupRect.left(), 0);
|
||||
if (popupRect.bottom() > screenRect.bottom())
|
||||
popupRect.translate(0, -(thePublic->height() + container->height()));
|
||||
|
||||
container->setGeometry(popupRect);
|
||||
container->raise();
|
||||
container->show();
|
||||
slider->setFocus();
|
||||
}
|
||||
|
||||
void KoSliderCombo::KoSliderComboPrivate::hidePopup()
|
||||
{
|
||||
container->hide();
|
||||
}
|
||||
|
||||
void KoSliderCombo::hideEvent(QHideEvent *)
|
||||
{
|
||||
d->hidePopup();
|
||||
}
|
||||
|
||||
void KoSliderCombo::changeEvent(QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
case QEvent::EnabledChange:
|
||||
if (!isEnabled())
|
||||
d->hidePopup();
|
||||
break;
|
||||
case QEvent::PaletteChange:
|
||||
d->container->setPalette(palette());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
QComboBox::changeEvent(e);
|
||||
}
|
||||
|
||||
void KoSliderCombo::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStylePainter gc(this);
|
||||
|
||||
gc.setPen(palette().color(QPalette::Text));
|
||||
|
||||
QStyleOptionComboBox opt;
|
||||
opt.init(this);
|
||||
opt.subControls = QStyle::SC_All;
|
||||
opt.editable = true;
|
||||
gc.drawComplexControl(QStyle::CC_ComboBox, opt);
|
||||
gc.drawControl(QStyle::CE_ComboBoxLabel, opt);
|
||||
}
|
||||
|
||||
void KoSliderCombo::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
QStyleOptionComboBox opt;
|
||||
opt.init(this);
|
||||
opt.subControls = QStyle::SC_All;
|
||||
opt.editable = true;
|
||||
QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->pos(),
|
||||
this);
|
||||
if (sc == QStyle::SC_ComboBoxArrow && !d->container->isVisible()) {
|
||||
d->showPopup();
|
||||
} else
|
||||
QComboBox::mousePressEvent(e);
|
||||
}
|
||||
|
||||
void KoSliderCombo::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
if (e->key() == Qt::Key_Up) setValue(value() + d->slider->singleStep() *(maximum() - minimum()) / 256 + 0.5);
|
||||
else if (e->key() == Qt::Key_Down) setValue(value() - d->slider->singleStep() *(maximum() - minimum()) / 256 - 0.5);
|
||||
else QComboBox::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void KoSliderCombo::wheelEvent(QWheelEvent *e)
|
||||
{
|
||||
if (e->delta() > 0) setValue(value() + d->slider->singleStep() *(maximum() - minimum()) / 256 + 0.5);
|
||||
else setValue(value() - d->slider->singleStep() *(maximum() - minimum()) / 256 - 0.5);
|
||||
}
|
||||
|
||||
void KoSliderCombo::KoSliderComboPrivate::lineEditFinished()
|
||||
{
|
||||
qreal value = thePublic->currentText().toDouble();
|
||||
slider->blockSignals(true);
|
||||
slider->setValue(int((value - minimum) * 256 / (maximum - minimum) + 0.5));
|
||||
slider->blockSignals(false);
|
||||
emit thePublic->valueChanged(value, true);
|
||||
}
|
||||
|
||||
void KoSliderCombo::KoSliderComboPrivate::sliderValueChanged(int slidervalue)
|
||||
{
|
||||
thePublic->setEditText(KGlobal::locale()->formatNumber(minimum + (maximum - minimum)*slidervalue / 256, decimals));
|
||||
|
||||
qreal value = thePublic->currentText().toDouble();
|
||||
emit thePublic->valueChanged(value, false);
|
||||
}
|
||||
|
||||
void KoSliderCombo::KoSliderComboPrivate::sliderReleased()
|
||||
{
|
||||
qreal value = thePublic->currentText().toDouble();
|
||||
emit thePublic->valueChanged(value, true);
|
||||
}
|
||||
|
||||
qreal KoSliderCombo::maximum() const
|
||||
{
|
||||
return d->maximum;
|
||||
}
|
||||
|
||||
qreal KoSliderCombo::minimum() const
|
||||
{
|
||||
return d->minimum;
|
||||
}
|
||||
|
||||
qreal KoSliderCombo::decimals() const
|
||||
{
|
||||
return d->decimals;
|
||||
}
|
||||
|
||||
qreal KoSliderCombo::value() const
|
||||
{
|
||||
return currentText().toDouble();
|
||||
}
|
||||
|
||||
void KoSliderCombo::setDecimals(int dec)
|
||||
{
|
||||
d->decimals = dec;
|
||||
if (dec == 0) lineEdit()->setValidator(new QIntValidator(this));
|
||||
else lineEdit()->setValidator(new QDoubleValidator(this));
|
||||
}
|
||||
|
||||
void KoSliderCombo::setMinimum(qreal min)
|
||||
{
|
||||
d->minimum = min;
|
||||
}
|
||||
|
||||
void KoSliderCombo::setMaximum(qreal max)
|
||||
{
|
||||
d->maximum = max;
|
||||
}
|
||||
|
||||
void KoSliderCombo::setValue(qreal value)
|
||||
{
|
||||
if (value < d->minimum)
|
||||
value = d->minimum;
|
||||
if (value > d->maximum)
|
||||
value = d->maximum;
|
||||
setEditText(KGlobal::locale()->formatNumber(value, d->decimals));
|
||||
d->slider->blockSignals(true);
|
||||
d->slider->setValue(int((value - d->minimum) * 256 / (d->maximum - d->minimum) + 0.5));
|
||||
d->slider->blockSignals(false);
|
||||
emit valueChanged(value, true);
|
||||
}
|
||||
|
||||
#include <KoSliderCombo.moc>
|
||||
@@ -1,140 +0,0 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (c) 2007 Casper Boemann <cbr@boemann.dk>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; see the file COPYING.LIB. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KOSLIDERCOMBO_H_
|
||||
#define KOSLIDERCOMBO_H_
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
|
||||
/**
|
||||
* @short A widget for qreal values with a popup slider
|
||||
*
|
||||
* KoSliderCombo combines a numerical input and a dropdown slider in a way that takes up as
|
||||
* little screen space as possible.
|
||||
*
|
||||
* It allows the user to either enter a floating point value or quickly set the value using a slider
|
||||
*
|
||||
* One signal is emitted when the value changes. The signal is even emitted when the slider
|
||||
* is moving. The second argument of the signal however tells you if the value is final or not. A
|
||||
* final value is produced by entering a value numerically or by releasing the slider.
|
||||
*
|
||||
* The input of the numerical line edit is constrained to numbers and decimal signs.
|
||||
*/
|
||||
class KoSliderCombo : public QComboBox
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for the widget, where value is set to 0
|
||||
*
|
||||
* @param parent parent QWidget
|
||||
*/
|
||||
explicit KoSliderCombo(QWidget *parent = 0);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~KoSliderCombo();
|
||||
|
||||
/**
|
||||
* The precision of values given as the number of digits after the period.
|
||||
* default is 2
|
||||
*/
|
||||
qreal decimals() const;
|
||||
|
||||
/**
|
||||
* The minimum value that can be entered.
|
||||
* default is 0
|
||||
*/
|
||||
qreal minimum() const;
|
||||
|
||||
/**
|
||||
* The maximum value that can be entered.
|
||||
* default is 100
|
||||
*/
|
||||
qreal maximum() const;
|
||||
|
||||
/**
|
||||
* Sets the precision of the entered values.
|
||||
* @param number the number of digits after the period
|
||||
*/
|
||||
|
||||
void setDecimals(int number);
|
||||
|
||||
/**
|
||||
* Sets the minimum value that can be entered.
|
||||
* @param min the minimum value
|
||||
*/
|
||||
void setMinimum(qreal min);
|
||||
|
||||
/**
|
||||
* Sets the maximum value that can be entered.
|
||||
* @param max the maximum value
|
||||
*/
|
||||
void setMaximum(qreal max);
|
||||
|
||||
/**
|
||||
* The value shown.
|
||||
*/
|
||||
qreal value() const;
|
||||
|
||||
virtual QSize minimumSizeHint() const; ///< reimplemented from QComboBox
|
||||
virtual QSize sizeHint() const; ///< reimplemented from QComboBox
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
* The value actually set is forced to be within the legal range: minimum <= value <= maximum
|
||||
* @param value the new value
|
||||
*/
|
||||
void setValue(qreal value);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted every time the value changes (by calling setValue() or
|
||||
* by user interaction).
|
||||
* @param value the new value
|
||||
* @param final if the value is final ie not produced during sliding (on slider release it's final)
|
||||
*/
|
||||
void valueChanged(qreal value, bool final);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *); ///< reimplemented from QComboBox
|
||||
virtual void hideEvent(QHideEvent *); ///< reimplemented from QComboBox
|
||||
virtual void changeEvent(QEvent *e); ///< reimplemented from QComboBox
|
||||
virtual void mousePressEvent(QMouseEvent *e); ///< reimplemented from QComboBox
|
||||
virtual void keyPressEvent(QKeyEvent *e); ///< reimplemented from QComboBox
|
||||
virtual void wheelEvent(QWheelEvent *e); ///< reimplemented from QComboBox
|
||||
|
||||
private:
|
||||
Q_PRIVATE_SLOT(d, void sliderValueChanged(int value))
|
||||
Q_PRIVATE_SLOT(d, void sliderReleased())
|
||||
Q_PRIVATE_SLOT(d, void lineEditFinished())
|
||||
|
||||
class KoSliderComboPrivate;
|
||||
KoSliderComboPrivate * const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,551 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) *
|
||||
* Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "abstractclipitem.h"
|
||||
#include "customtrackscene.h"
|
||||
#include "kdenlivesettings.h"
|
||||
|
||||
#include <KDebug>
|
||||
#include <KLocale>
|
||||
#include <KGlobalSettings>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QToolTip>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QParallelAnimationGroup>
|
||||
|
||||
AbstractClipItem::AbstractClipItem(const ItemInfo &info, const QRectF& rect, double fps) :
|
||||
QObject()
|
||||
, QGraphicsRectItem(rect)
|
||||
, m_info(info)
|
||||
, m_editedKeyframe(-1)
|
||||
, m_selectedKeyframe(0)
|
||||
, m_keyframeFactor(1)
|
||||
, m_keyframeOffset(0)
|
||||
, m_keyframeDefault(0)
|
||||
, m_visibleParam(0)
|
||||
, m_fps(fps)
|
||||
, m_isMainSelectedClip(false)
|
||||
{
|
||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
AbstractClipItem::~AbstractClipItem()
|
||||
{
|
||||
}
|
||||
|
||||
void AbstractClipItem::closeAnimation()
|
||||
{
|
||||
#if QT_VERSION >= 0x040600
|
||||
if (!isEnabled()) return;
|
||||
setEnabled(false);
|
||||
setFlag(QGraphicsItem::ItemIsSelectable, false);
|
||||
if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
|
||||
// animation disabled
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
QPropertyAnimation *closeAnimation = new QPropertyAnimation(this, "rect");
|
||||
QPropertyAnimation *closeAnimation2 = new QPropertyAnimation(this, "opacity");
|
||||
closeAnimation->setDuration(200);
|
||||
closeAnimation2->setDuration(200);
|
||||
QRectF r = rect();
|
||||
QRectF r2 = r;
|
||||
r2.setLeft(r.left() + r.width() / 2);
|
||||
r2.setTop(r.top() + r.height() / 2);
|
||||
r2.setWidth(1);
|
||||
r2.setHeight(1);
|
||||
closeAnimation->setStartValue(r);
|
||||
closeAnimation->setEndValue(r2);
|
||||
closeAnimation->setEasingCurve(QEasingCurve::InQuad);
|
||||
closeAnimation2->setStartValue(1.0);
|
||||
closeAnimation2->setEndValue(0.0);
|
||||
QParallelAnimationGroup *group = new QParallelAnimationGroup;
|
||||
connect(group, SIGNAL(finished()), this, SLOT(deleteLater()));
|
||||
group->addAnimation(closeAnimation);
|
||||
group->addAnimation(closeAnimation2);
|
||||
group->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
#endif
|
||||
}
|
||||
|
||||
ItemInfo AbstractClipItem::info() const
|
||||
{
|
||||
ItemInfo info = m_info;
|
||||
info.cropStart = cropStart();
|
||||
info.endPos = endPos();
|
||||
return info;
|
||||
}
|
||||
|
||||
int AbstractClipItem::defaultZValue() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
GenTime AbstractClipItem::endPos() const
|
||||
{
|
||||
return m_info.startPos + m_info.cropDuration;
|
||||
}
|
||||
|
||||
int AbstractClipItem::track() const
|
||||
{
|
||||
return m_info.track;
|
||||
}
|
||||
|
||||
GenTime AbstractClipItem::cropStart() const
|
||||
{
|
||||
return m_info.cropStart;
|
||||
}
|
||||
|
||||
GenTime AbstractClipItem::cropDuration() const
|
||||
{
|
||||
return m_info.cropDuration;
|
||||
}
|
||||
|
||||
void AbstractClipItem::setCropStart(const GenTime &pos)
|
||||
{
|
||||
m_info.cropStart = pos;
|
||||
}
|
||||
|
||||
void AbstractClipItem::updateItem()
|
||||
{
|
||||
m_info.track = (int)(scenePos().y() / KdenliveSettings::trackheight());
|
||||
m_info.startPos = GenTime((int) scenePos().x(), m_fps);
|
||||
}
|
||||
|
||||
void AbstractClipItem::updateRectGeometry()
|
||||
{
|
||||
setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
|
||||
}
|
||||
|
||||
void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChange*/)
|
||||
{
|
||||
GenTime durationDiff = GenTime(posx, m_fps) - m_info.startPos;
|
||||
if (durationDiff == GenTime()) return;
|
||||
|
||||
if (type() == AVWIDGET && hasSizeLimit && (cropStart() + durationDiff < GenTime())) {
|
||||
durationDiff = GenTime() - cropStart();
|
||||
} else if (durationDiff >= cropDuration()) {
|
||||
return;
|
||||
/*if (cropDuration() > GenTime(3, m_fps)) durationDiff = GenTime(3, m_fps);
|
||||
else return;*/
|
||||
}
|
||||
m_info.startPos += durationDiff;
|
||||
|
||||
// set to true if crop from start is negative (possible for color clips, images as they have no size limit)
|
||||
bool negCropStart = false;
|
||||
if (type() == AVWIDGET) {
|
||||
m_info.cropStart += durationDiff;
|
||||
if (m_info.cropStart < GenTime())
|
||||
negCropStart = true;
|
||||
}
|
||||
|
||||
m_info.cropDuration -= durationDiff;
|
||||
setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
|
||||
moveBy(durationDiff.frames(m_fps), 0);
|
||||
|
||||
if (m_info.startPos != GenTime(posx, m_fps)) {
|
||||
//kDebug() << "////// WARNING, DIFF IN XPOS: " << pos().x() << " == " << m_info.startPos.frames(m_fps);
|
||||
GenTime diff = m_info.startPos - GenTime(posx, m_fps);
|
||||
|
||||
if (type() == AVWIDGET)
|
||||
m_info.cropStart += diff;
|
||||
|
||||
m_info.cropDuration -= diff;
|
||||
setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
|
||||
//kDebug()<<"// NEW START: "<<m_startPos.frames(25)<<", NW DUR: "<<m_cropDuration.frames(25);
|
||||
}
|
||||
|
||||
// set crop from start to 0 (isn't relevant as this only happens for color clips, images)
|
||||
if (negCropStart)
|
||||
m_info.cropStart = GenTime();
|
||||
|
||||
//kDebug() << "-- NEW CLIP=" << startPos().frames(25) << "-" << endPos().frames(25);
|
||||
//setRect((double) m_startPos.frames(m_fps) * scale, rect().y(), (double) m_cropDuration.frames(m_fps) * scale, rect().height());
|
||||
|
||||
/* if (durationDiff < GenTime()) {
|
||||
QList <QGraphicsItem *> collisionList = collidingItems(Qt::IntersectsItemBoundingRect);
|
||||
for (int i = 0; i < collisionList.size(); ++i) {
|
||||
QGraphicsItem *item = collisionList.at(i);
|
||||
if (item->type() == type() && item->pos().x() < pos().x()) {
|
||||
kDebug() << "///////// COLLISION DETECTED!!!!!!!!!";
|
||||
GenTime diff = ((AbstractClipItem *)item)->endPos() + GenTime(1, m_fps) - m_startPos;
|
||||
setRect(0, 0, (m_cropDuration - diff).frames(m_fps) - 0.02, rect().height());
|
||||
setPos((m_startPos + diff).frames(m_fps), pos().y());
|
||||
m_startPos += diff;
|
||||
if (type() == AVWIDGET) m_cropStart += diff;
|
||||
m_cropDuration = m_cropDuration - diff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void AbstractClipItem::resizeEnd(int posx, bool /*emitChange*/)
|
||||
{
|
||||
GenTime durationDiff = GenTime(posx, m_fps) - endPos();
|
||||
if (durationDiff == GenTime()) return;
|
||||
if (cropDuration() + durationDiff <= GenTime()) {
|
||||
durationDiff = GenTime() - (cropDuration() - GenTime(3, m_fps));
|
||||
}
|
||||
|
||||
m_info.cropDuration += durationDiff;
|
||||
m_info.endPos += durationDiff;
|
||||
|
||||
setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
|
||||
if (durationDiff > GenTime()) {
|
||||
QList <QGraphicsItem *> collisionList = collidingItems(Qt::IntersectsItemBoundingRect);
|
||||
bool fixItem = false;
|
||||
for (int i = 0; i < collisionList.size(); ++i) {
|
||||
if (!collisionList.at(i)->isEnabled()) continue;
|
||||
QGraphicsItem *item = collisionList.at(i);
|
||||
if (item->type() == type() && item->pos().x() > pos().x()) {
|
||||
//kDebug() << "///////// COLLISION DETECTED!!!!!!!!!";
|
||||
//kDebug() << "///////// CURRENT: " << startPos().frames(25) << "x" << endPos().frames(25) << ", RECT: " << rect() << "-" << pos();
|
||||
//kDebug() << "///////// COLLISION: " << ((AbstractClipItem *)item)->startPos().frames(25) << "x" << ((AbstractClipItem *)item)->endPos().frames(25) << ", RECT: " << ((AbstractClipItem *)item)->rect() << "-" << item->pos();
|
||||
GenTime diff = ((AbstractClipItem *)item)->startPos() - startPos();
|
||||
if (fixItem == false || diff < m_info.cropDuration) {
|
||||
fixItem = true;
|
||||
m_info.cropDuration = diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fixItem) setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
|
||||
}
|
||||
}
|
||||
|
||||
GenTime AbstractClipItem::startPos() const
|
||||
{
|
||||
return m_info.startPos;
|
||||
}
|
||||
|
||||
void AbstractClipItem::setTrack(int track)
|
||||
{
|
||||
m_info.track = track;
|
||||
}
|
||||
|
||||
double AbstractClipItem::fps() const
|
||||
{
|
||||
return m_fps;
|
||||
}
|
||||
|
||||
void AbstractClipItem::updateFps(double fps)
|
||||
{
|
||||
m_fps = fps;
|
||||
setPos((qreal) startPos().frames(m_fps), pos().y());
|
||||
updateRectGeometry();
|
||||
}
|
||||
|
||||
GenTime AbstractClipItem::maxDuration() const
|
||||
{
|
||||
return m_maxDuration;
|
||||
}
|
||||
|
||||
void AbstractClipItem::drawKeyFrames(QPainter *painter, const QTransform &transformation, bool limitedKeyFrames)
|
||||
{
|
||||
if (m_keyframes.count() < 1)
|
||||
return;
|
||||
QRectF br = rect();
|
||||
double maxw = br.width() / cropDuration().frames(m_fps);
|
||||
double maxh = br.height() / 100.0 * m_keyframeFactor;
|
||||
double start = cropStart().frames(m_fps);
|
||||
double x1, y1, x2, y2;
|
||||
bool antialiasing = painter->renderHints() & QPainter::Antialiasing;
|
||||
|
||||
// draw line showing default value
|
||||
bool active = isSelected() || (parentItem() && parentItem()->isSelected());
|
||||
if (active) {
|
||||
x1 = br.x();
|
||||
x2 = br.right();
|
||||
if (limitedKeyFrames) {
|
||||
QMap<int, int>::const_iterator end = m_keyframes.constEnd();
|
||||
--end;
|
||||
x2 = x1 + maxw * (end.key() - start);
|
||||
x1 += maxw * (m_keyframes.constBegin().key() - start);
|
||||
}
|
||||
y1 = br.bottom() - (m_keyframeDefault - m_keyframeOffset) * maxh;
|
||||
QLineF l(x1, y1, x2, y1);
|
||||
QLineF l2 = transformation.map(l);
|
||||
painter->setPen(QColor(168, 168, 168, 180));
|
||||
painter->drawLine(l2);
|
||||
painter->setPen(QColor(108, 108, 108, 180));
|
||||
painter->drawLine(l2.translated(0, 1));
|
||||
painter->setPen(QColor(Qt::white));
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
}
|
||||
|
||||
// draw keyframes
|
||||
QMap<int, int>::const_iterator i = m_keyframes.constBegin();
|
||||
QColor color(Qt::blue);
|
||||
QLineF l2;
|
||||
x1 = br.x() + maxw * (i.key() - start);
|
||||
y1 = br.bottom() - (i.value() - m_keyframeOffset) * maxh;
|
||||
|
||||
|
||||
|
||||
// make sure line begins with clip beginning
|
||||
if (!limitedKeyFrames && i.key() != start) {
|
||||
QLineF l(br.x(), y1, x1, y1);
|
||||
l2 = transformation.map(l);
|
||||
painter->drawLine(l2);
|
||||
}
|
||||
while (i != m_keyframes.constEnd()) {
|
||||
if (i.key() == m_editedKeyframe)
|
||||
color = QColor(Qt::red);
|
||||
else
|
||||
color = QColor(Qt::blue);
|
||||
++i;
|
||||
if (i == m_keyframes.constEnd() && m_keyframes.count() != 1)
|
||||
break;
|
||||
|
||||
if (m_keyframes.count() == 1) {
|
||||
x2 = br.right();
|
||||
y2 = y1;
|
||||
} else {
|
||||
x2 = br.x() + maxw * (i.key() - start);
|
||||
y2 = br.bottom() - (i.value() - m_keyframeOffset) * maxh;
|
||||
}
|
||||
QLineF l(x1, y1, x2, y2);
|
||||
l2 = transformation.map(l);
|
||||
painter->drawLine(l2);
|
||||
if (active) {
|
||||
const QRectF frame(l2.x1() - 3, l2.y1() - 3, 6, 6);
|
||||
painter->fillRect(frame, color);
|
||||
}
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
|
||||
// make sure line ends at clip end
|
||||
if (!limitedKeyFrames && x1 != br.right()) {
|
||||
QLineF l(x1, y1, br.right(), y1);
|
||||
painter->drawLine(transformation.map(l));
|
||||
}
|
||||
|
||||
if (active && m_keyframes.count() > 1) {
|
||||
const QRectF frame(l2.x2() - 3, l2.y2() - 3, 6, 6);
|
||||
painter->fillRect(frame, color);
|
||||
}
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, antialiasing);
|
||||
}
|
||||
|
||||
int AbstractClipItem::mouseOverKeyFrames(QPointF pos, double maxOffset)
|
||||
{
|
||||
const QRectF br = sceneBoundingRect();
|
||||
double maxw = br.width() / cropDuration().frames(m_fps);
|
||||
double maxh = br.height() / 100.0 * m_keyframeFactor;
|
||||
if (m_keyframes.count() > 0) {
|
||||
QMap<int, int>::const_iterator i = m_keyframes.constBegin();
|
||||
double x1;
|
||||
double y1;
|
||||
while (i != m_keyframes.constEnd()) {
|
||||
x1 = br.x() + maxw * (i.key() - cropStart().frames(m_fps));
|
||||
y1 = br.bottom() - (i.value() - m_keyframeOffset) * maxh;
|
||||
if (qAbs(pos.x() - x1) < maxOffset && qAbs(pos.y() - y1) < 10) {
|
||||
setToolTip('[' + QString::number((GenTime(i.key(), m_fps) - cropStart()).seconds(), 'f', 2) + i18n("seconds") + ", " + QString::number(i.value(), 'f', 1) + ']');
|
||||
return i.key();
|
||||
} else if (x1 > pos.x()) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
setToolTip(QString());
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AbstractClipItem::updateSelectedKeyFrame()
|
||||
{
|
||||
if (m_editedKeyframe == -1)
|
||||
return;
|
||||
QRectF br = sceneBoundingRect();
|
||||
double maxw = br.width() / cropDuration().frames(m_fps);
|
||||
double maxh = br.height() / 100.0 * m_keyframeFactor;
|
||||
update(br.x() + maxw *(m_selectedKeyframe - cropStart().frames(m_fps)) - 3, br.bottom() - (m_keyframes.value(m_selectedKeyframe) - m_keyframeOffset) * maxh - 3, 12, 12);
|
||||
m_selectedKeyframe = m_editedKeyframe;
|
||||
update(br.x() + maxw *(m_selectedKeyframe - cropStart().frames(m_fps)) - 3, br.bottom() - (m_keyframes.value(m_selectedKeyframe) - m_keyframeOffset) * maxh - 3, 12, 12);
|
||||
}
|
||||
|
||||
int AbstractClipItem::editedKeyFramePos() const
|
||||
{
|
||||
return m_editedKeyframe;
|
||||
}
|
||||
|
||||
double AbstractClipItem::editedKeyFrameValue() const
|
||||
{
|
||||
return m_keyframes.value(m_editedKeyframe);
|
||||
}
|
||||
|
||||
int AbstractClipItem::selectedKeyFramePos() const
|
||||
{
|
||||
return m_selectedKeyframe;
|
||||
}
|
||||
|
||||
double AbstractClipItem::selectedKeyFrameValue() const
|
||||
{
|
||||
return m_keyframes.value(m_selectedKeyframe);
|
||||
}
|
||||
|
||||
void AbstractClipItem::updateKeyFramePos(const GenTime &pos, const double value)
|
||||
{
|
||||
if (!m_keyframes.contains(m_editedKeyframe))
|
||||
return;
|
||||
int newpos = (int) pos.frames(m_fps);
|
||||
int min = (int) cropStart().frames(m_fps) - 1;
|
||||
int max = (int)(cropStart() + cropDuration()).frames(m_fps);
|
||||
QMap<int, int>::const_iterator i = m_keyframes.constBegin();
|
||||
while (i.key() < m_editedKeyframe) {
|
||||
min = qMax(i.key(), min);
|
||||
++i;
|
||||
}
|
||||
i = m_keyframes.constEnd() - 1;
|
||||
while (i.key() > m_editedKeyframe) {
|
||||
max = qMin(i.key(), max);
|
||||
--i;
|
||||
}
|
||||
if (newpos <= min)
|
||||
newpos = min + 1;
|
||||
if (newpos >= max)
|
||||
newpos = max - 1;
|
||||
|
||||
double newval = qMax(value, 0.0);
|
||||
newval = qMin(newval, 100.0);
|
||||
newval = newval / m_keyframeFactor + m_keyframeOffset;
|
||||
if (m_editedKeyframe != newpos)
|
||||
m_keyframes.remove(m_editedKeyframe);
|
||||
m_keyframes[newpos] = (int) newval;
|
||||
m_editedKeyframe = newpos;
|
||||
update();
|
||||
}
|
||||
|
||||
double AbstractClipItem::keyFrameFactor() const
|
||||
{
|
||||
return m_keyframeFactor;
|
||||
}
|
||||
|
||||
int AbstractClipItem::keyFrameNumber() const
|
||||
{
|
||||
return m_keyframes.count();
|
||||
}
|
||||
|
||||
int AbstractClipItem::checkForSingleKeyframe()
|
||||
{
|
||||
// Check if we have only one keyframe
|
||||
if (!m_keyframes.isEmpty() && m_keyframes.count() == 1) {
|
||||
int min = (int) cropStart().frames(m_fps);
|
||||
int max = (int)(cropStart() + cropDuration()).frames(m_fps) - 1;
|
||||
if (m_keyframes.contains(min)) {
|
||||
// Add keyframe at end of clip to allow inserting a new keframe in between
|
||||
m_keyframes[max] = m_keyframes.value(min);
|
||||
return m_keyframes.value(min);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AbstractClipItem::addKeyFrame(const GenTime &pos, const double value)
|
||||
{
|
||||
QRectF br = sceneBoundingRect();
|
||||
double maxh = 100.0 / br.height() / m_keyframeFactor;
|
||||
int newval = (br.bottom() - value) * maxh + m_keyframeOffset;
|
||||
//kDebug() << "Rect: " << br << "/ SCENE: " << sceneBoundingRect() << ", VALUE: " << value << ", MAX: " << maxh << ", NEWVAL: " << newval;
|
||||
int newpos = (int) pos.frames(m_fps) ;
|
||||
m_keyframes[newpos] = newval;
|
||||
m_selectedKeyframe = newpos;
|
||||
update();
|
||||
return newval;
|
||||
}
|
||||
|
||||
bool AbstractClipItem::hasKeyFrames() const
|
||||
{
|
||||
return !m_keyframes.isEmpty();
|
||||
}
|
||||
|
||||
/*QRect AbstractClipItem::visibleRect() {
|
||||
QRect rectInView;
|
||||
if (scene()->views().size() > 0) {
|
||||
rectInView = scene()->views()[0]->viewport()->rect();
|
||||
rectInView.moveTo(scene()->views()[0]->horizontalScrollBar()->value(), scene()->views()[0]->verticalScrollBar()->value());
|
||||
rectInView.adjust(-10, -10, 10, 10);//make view rect 10 pixel greater on each site, or repaint after scroll event
|
||||
//kDebug() << scene()->views()[0]->viewport()->rect() << " " << scene()->views()[0]->horizontalScrollBar()->value();
|
||||
}
|
||||
return rectInView;
|
||||
}*/
|
||||
|
||||
CustomTrackScene* AbstractClipItem::projectScene()
|
||||
{
|
||||
if (scene())
|
||||
return static_cast <CustomTrackScene*>(scene());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AbstractClipItem::setItemLocked(bool locked)
|
||||
{
|
||||
if (locked)
|
||||
setSelected(false);
|
||||
|
||||
setFlag(QGraphicsItem::ItemIsMovable, !locked);
|
||||
setFlag(QGraphicsItem::ItemIsSelectable, !locked);
|
||||
}
|
||||
|
||||
bool AbstractClipItem::isItemLocked() const
|
||||
{
|
||||
return !(flags() & (QGraphicsItem::ItemIsSelectable));
|
||||
}
|
||||
|
||||
// virtual
|
||||
void AbstractClipItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
|
||||
{
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
// User want to do a rectangle selection, so ignore the event to pass it to the view
|
||||
event->ignore();
|
||||
} else {
|
||||
QGraphicsItem::mousePressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
int AbstractClipItem::itemHeight()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AbstractClipItem::itemOffset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AbstractClipItem::setMainSelectedClip(bool selected)
|
||||
{
|
||||
if (selected == m_isMainSelectedClip) return;
|
||||
m_isMainSelectedClip = selected;
|
||||
update();
|
||||
}
|
||||
|
||||
bool AbstractClipItem::isMainSelectedClip()
|
||||
{
|
||||
return m_isMainSelectedClip;
|
||||
}
|
||||
|
||||
|
||||
#include "abstractclipitem.moc"
|
||||
@@ -1,136 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) *
|
||||
* Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ABSTRACTCLIPITEM
|
||||
#define ABSTRACTCLIPITEM
|
||||
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QGraphicsWidget>
|
||||
|
||||
#if QT_VERSION >= 0x040600
|
||||
#include <QPropertyAnimation>
|
||||
#endif
|
||||
|
||||
#include "definitions.h"
|
||||
#include "gentime.h"
|
||||
|
||||
class CustomTrackScene;
|
||||
class QGraphicsSceneMouseEvent;
|
||||
|
||||
class AbstractClipItem : public QObject, public QGraphicsRectItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QRectF rect READ rect WRITE setRect)
|
||||
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
|
||||
|
||||
public:
|
||||
AbstractClipItem(const ItemInfo &info, const QRectF& rect, double fps);
|
||||
virtual ~ AbstractClipItem();
|
||||
void updateSelectedKeyFrame();
|
||||
|
||||
/** @brief Move the selected keyframe (does not influence the effect, only the display in timeline).
|
||||
* @param pos new Position
|
||||
* @param value new Value */
|
||||
void updateKeyFramePos(const GenTime &pos, const double value);
|
||||
int checkForSingleKeyframe();
|
||||
int addKeyFrame(const GenTime &pos, const double value);
|
||||
bool hasKeyFrames() const;
|
||||
int editedKeyFramePos() const;
|
||||
int selectedKeyFramePos() const;
|
||||
double selectedKeyFrameValue() const;
|
||||
double editedKeyFrameValue() const;
|
||||
double keyFrameFactor() const;
|
||||
/** @brief Returns the number of keyframes the selected effect has. */
|
||||
int keyFrameNumber() const;
|
||||
ItemInfo info() const;
|
||||
CustomTrackScene* projectScene();
|
||||
void updateRectGeometry();
|
||||
void updateItem();
|
||||
void setItemLocked(bool locked);
|
||||
bool isItemLocked() const;
|
||||
void closeAnimation();
|
||||
|
||||
virtual OPERATIONTYPE operationMode(const QPointF &pos) = 0;
|
||||
virtual GenTime startPos() const ;
|
||||
virtual void setTrack(int track);
|
||||
virtual GenTime endPos() const ;
|
||||
virtual int defaultZValue() const ;
|
||||
virtual int track() const ;
|
||||
virtual GenTime cropStart() const ;
|
||||
virtual GenTime cropDuration() const ;
|
||||
/** @brief Return the current item's height */
|
||||
static int itemHeight();
|
||||
/** @brief Return the current item's vertical offset
|
||||
* For example transitions are drawn at 1/3 of track height */
|
||||
static int itemOffset();
|
||||
|
||||
/** @brief Resizes the clip from the start.
|
||||
* @param posx Absolute position of new in point
|
||||
* @param hasSizeLimit (optional) Whether the clip has a maximum size */
|
||||
virtual void resizeStart(int posx, bool hasSizeLimit = true, bool emitChange = true);
|
||||
|
||||
/** @brief Resizes the clip from the end.
|
||||
* @param posx Absolute position of new out point */
|
||||
virtual void resizeEnd(int posx, bool emitChange = true);
|
||||
virtual double fps() const;
|
||||
virtual void updateFps(double fps);
|
||||
virtual GenTime maxDuration() const;
|
||||
virtual void setCropStart(const GenTime &pos);
|
||||
|
||||
/** @brief Set this clip as the main selected clip (or not). */
|
||||
void setMainSelectedClip(bool selected);
|
||||
/** @brief Is this clip selected as the main clip. */
|
||||
bool isMainSelectedClip();
|
||||
|
||||
protected:
|
||||
ItemInfo m_info;
|
||||
/** The position of the current keyframe when it has moved */
|
||||
int m_editedKeyframe;
|
||||
/** The position of the current keyframe before it was moved */
|
||||
int m_selectedKeyframe;
|
||||
/* GenTime m_cropStart;
|
||||
GenTime m_cropDuration;
|
||||
GenTime m_startPos;*/
|
||||
GenTime m_maxDuration;
|
||||
QMap <int, int> m_keyframes;
|
||||
/** @brief Strech factor so that keyframes display on the full clip height. */
|
||||
double m_keyframeFactor;
|
||||
/** @brief Offset factor so that keyframes minimum value are displaed at the bottom of the clip. */
|
||||
double m_keyframeOffset;
|
||||
/** @brief Default reset value for keyframe. */
|
||||
double m_keyframeDefault;
|
||||
/** The (keyframe) parameter that is visible and editable in timeline (on the clip) */
|
||||
int m_visibleParam;
|
||||
double m_fps;
|
||||
/** @brief True if this is the last clip the user selected */
|
||||
bool m_isMainSelectedClip;
|
||||
/** @brief Draw the keyframes of a clip
|
||||
* @param painter The painter device for the clip
|
||||
* @param limitedKeyFrames The keyframes can be of type "keyframe" or "simplekeyframe". In the
|
||||
* "simplekeyframe" type, the effect always starts on clip start and ends on clip end. With the
|
||||
* "keyframe" type, the effect starts on the first keyframe and ends on the last keyframe
|
||||
*/
|
||||
void drawKeyFrames(QPainter *painter, const QTransform &transformation, bool limitedKeyFrames);
|
||||
int mouseOverKeyFrames(QPointF pos, double maxOffset);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent * event);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,558 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) *
|
||||
* Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "abstractgroupitem.h"
|
||||
#include "abstractclipitem.h"
|
||||
#include "kdenlivesettings.h"
|
||||
#include "customtrackscene.h"
|
||||
#include "customtrackview.h"
|
||||
|
||||
#include <KDebug>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
#include <QDomDocument>
|
||||
#include <QMimeData>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
|
||||
|
||||
AbstractGroupItem::AbstractGroupItem(double /* fps */) :
|
||||
QObject(),
|
||||
QGraphicsItemGroup()
|
||||
{
|
||||
setZValue(1);
|
||||
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
|
||||
#if QT_VERSION >= 0x040600
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
||||
#endif
|
||||
setAcceptDrops(true);
|
||||
m_resizeInfos = QList <ItemInfo>();
|
||||
}
|
||||
|
||||
int AbstractGroupItem::type() const
|
||||
{
|
||||
return GROUPWIDGET;
|
||||
}
|
||||
|
||||
int AbstractGroupItem::track() const
|
||||
{
|
||||
//return (int)(scenePos().y() / KdenliveSettings::trackheight());
|
||||
int topTrack = -1;
|
||||
QList<QGraphicsItem *> children = childItems();
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() == GROUPWIDGET) {
|
||||
children.append(children.at(i)->childItems());
|
||||
continue;
|
||||
}
|
||||
AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
|
||||
if (item && (topTrack == -1 || topTrack > item->track())) {
|
||||
topTrack = item->track();
|
||||
}
|
||||
}
|
||||
return topTrack;
|
||||
}
|
||||
|
||||
void AbstractGroupItem::setItemLocked(bool locked)
|
||||
{
|
||||
if (locked)
|
||||
setSelected(false);
|
||||
|
||||
setFlag(QGraphicsItem::ItemIsMovable, !locked);
|
||||
setFlag(QGraphicsItem::ItemIsSelectable, !locked);
|
||||
|
||||
foreach (QGraphicsItem *child, childItems())
|
||||
((AbstractClipItem *)child)->setItemLocked(locked);
|
||||
}
|
||||
|
||||
bool AbstractGroupItem::isItemLocked() const
|
||||
{
|
||||
return !(flags() & (QGraphicsItem::ItemIsSelectable));
|
||||
}
|
||||
|
||||
CustomTrackScene* AbstractGroupItem::projectScene()
|
||||
{
|
||||
if (scene()) return static_cast <CustomTrackScene*>(scene());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QPainterPath AbstractGroupItem::clipGroupSpacerShape(const QPointF &offset) const
|
||||
{
|
||||
return spacerGroupShape(AVWIDGET, offset);
|
||||
}
|
||||
|
||||
QPainterPath AbstractGroupItem::clipGroupShape(const QPointF &offset) const
|
||||
{
|
||||
return groupShape(AVWIDGET, offset);
|
||||
}
|
||||
|
||||
QPainterPath AbstractGroupItem::transitionGroupShape(const QPointF &offset) const
|
||||
{
|
||||
return groupShape(TRANSITIONWIDGET, offset);
|
||||
}
|
||||
|
||||
QPainterPath AbstractGroupItem::groupShape(GRAPHICSRECTITEM type, const QPointF &offset) const
|
||||
{
|
||||
QPainterPath path;
|
||||
QList<QGraphicsItem *> children = childItems();
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() == (int)type) {
|
||||
QRectF r(children.at(i)->sceneBoundingRect());
|
||||
r.translate(offset);
|
||||
path.addRect(r);
|
||||
} else if (children.at(i)->type() == GROUPWIDGET) {
|
||||
QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
|
||||
for (int j = 0; j < subchildren.count(); j++) {
|
||||
if (subchildren.at(j)->type() == (int)type) {
|
||||
QRectF r(subchildren.at(j)->sceneBoundingRect());
|
||||
r.translate(offset);
|
||||
path.addRect(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
QPainterPath AbstractGroupItem::spacerGroupShape(GRAPHICSRECTITEM type, const QPointF &offset) const
|
||||
{
|
||||
QPainterPath path;
|
||||
QList<QGraphicsItem *> children = childItems();
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() == (int)type) {
|
||||
QRectF r(children.at(i)->sceneBoundingRect());
|
||||
r.translate(offset);
|
||||
r.setRight(scene()->width());
|
||||
path.addRect(r);
|
||||
} else if (children.at(i)->type() == GROUPWIDGET) {
|
||||
QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
|
||||
for (int j = 0; j < subchildren.count(); j++) {
|
||||
if (subchildren.at(j)->type() == (int)type) {
|
||||
QRectF r(subchildren.at(j)->sceneBoundingRect());
|
||||
r.translate(offset);
|
||||
r.setRight(scene()->width());
|
||||
path.addRect(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void AbstractGroupItem::addItem(QGraphicsItem * item)
|
||||
{
|
||||
addToGroup(item);
|
||||
item->setFlag(QGraphicsItem::ItemIsMovable, false);
|
||||
}
|
||||
|
||||
void AbstractGroupItem::removeItem(QGraphicsItem * item)
|
||||
{
|
||||
removeFromGroup(item);
|
||||
}
|
||||
|
||||
void AbstractGroupItem::fixItemRect()
|
||||
{
|
||||
QPointF start = boundingRect().topLeft();
|
||||
if (start != QPointF(0, 0)) {
|
||||
translate(0 - start.x(), 0 - start.y());
|
||||
setPos(start);
|
||||
}
|
||||
}
|
||||
|
||||
/*ItemInfo AbstractGroupItem::info() const {
|
||||
ItemInfo itemInfo;
|
||||
itemInfo.startPos = m_startPos;
|
||||
itemInfo.track = m_track;
|
||||
return itemInfo;
|
||||
}*/
|
||||
|
||||
// virtual
|
||||
void AbstractGroupItem::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *)
|
||||
{
|
||||
QColor bgcolor(100, 100, 200, 100);
|
||||
QRectF bound = option->exposedRect.adjusted(0, 0, 1, 1);
|
||||
p->setClipRect(bound);
|
||||
p->setBrush(bgcolor);
|
||||
QPen pen = p->pen();
|
||||
pen.setColor(QColor(200, 90, 90));
|
||||
pen.setStyle(Qt::DashLine);
|
||||
pen.setWidthF(0.0);
|
||||
p->setPen(pen);
|
||||
p->drawRoundedRect(boundingRect().adjusted(0, 0, -1, 0), 3, 3);
|
||||
}
|
||||
|
||||
//virtual
|
||||
QVariant AbstractGroupItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == QGraphicsItem::ItemSelectedChange) {
|
||||
if (value.toBool()) setZValue(10);
|
||||
else setZValue(1);
|
||||
}
|
||||
if (change == ItemPositionChange && scene() && parentItem() == 0) {
|
||||
// calculate new position.
|
||||
const int trackHeight = KdenliveSettings::trackheight();
|
||||
QPointF start = sceneBoundingRect().topLeft();
|
||||
QPointF newPos = value.toPointF();
|
||||
int xpos = projectScene()->getSnapPointForPos((int)(start.x() + newPos.x() - pos().x()), KdenliveSettings::snaptopoints());
|
||||
|
||||
xpos = qMax(xpos, 0);
|
||||
//kDebug()<<"GRP XPOS:"<<xpos<<", START:"<<start.x()<<",NEW:"<<newPos.x()<<"; SCENE:"<<scenePos().x()<<",POS:"<<pos().x();
|
||||
newPos.setX((int)(pos().x() + xpos - (int) start.x()));
|
||||
QStringList lockedTracks = property("locked_tracks").toStringList();
|
||||
int proposedTrack = (property("y_absolute").toInt() + newPos.y()) / trackHeight;
|
||||
// Check if top item is a clip or a transition
|
||||
int offset = 0;
|
||||
int topTrack = -1;
|
||||
QList<int> groupTracks;
|
||||
QList<QGraphicsItem *> children = childItems();
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
int currentTrack = 0;
|
||||
if (children.at(i)->type() == AVWIDGET || children.at(i)->type() == TRANSITIONWIDGET) {
|
||||
currentTrack = static_cast <AbstractClipItem*> (children.at(i))->track();
|
||||
if (!groupTracks.contains(currentTrack)) groupTracks.append(currentTrack);
|
||||
}
|
||||
else if (children.at(i)->type() == GROUPWIDGET) {
|
||||
currentTrack = static_cast <AbstractGroupItem*> (children.at(i))->track();
|
||||
}
|
||||
else continue;
|
||||
if (children.at(i)->type() == AVWIDGET) {
|
||||
if (topTrack == -1 || currentTrack <= topTrack) {
|
||||
offset = 0;
|
||||
topTrack = currentTrack;
|
||||
}
|
||||
} else if (children.at(i)->type() == TRANSITIONWIDGET) {
|
||||
if (topTrack == -1 || currentTrack < topTrack) {
|
||||
offset = (int)(trackHeight / 3 * 2 - 1);
|
||||
topTrack = currentTrack;
|
||||
}
|
||||
} else if (children.at(i)->type() == GROUPWIDGET) {
|
||||
QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
|
||||
bool clipGroup = false;
|
||||
for (int j = 0; j < subchildren.count(); j++) {
|
||||
if (subchildren.at(j)->type() == AVWIDGET || subchildren.at(j)->type() == TRANSITIONWIDGET) {
|
||||
int subTrack = static_cast <AbstractClipItem*> (subchildren.at(j))->track();
|
||||
if (!groupTracks.contains(subTrack)) groupTracks.append(subTrack);
|
||||
clipGroup = true;
|
||||
}
|
||||
}
|
||||
if (clipGroup) {
|
||||
if (topTrack == -1 || currentTrack <= topTrack) {
|
||||
offset = 0;
|
||||
topTrack = currentTrack;
|
||||
}
|
||||
} else {
|
||||
if (topTrack == -1 || currentTrack < topTrack) {
|
||||
offset = (int)(trackHeight / 3 * 2 - 1);
|
||||
topTrack = currentTrack;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check no clip in the group goes outside of existing tracks
|
||||
int maximumTrack = projectScene()->tracksCount() - 1;
|
||||
int groupHeight = 0;
|
||||
for (int i = 0; i < groupTracks.count(); ++i) {
|
||||
int offset = groupTracks.at(i) - topTrack;
|
||||
if (offset > groupHeight) groupHeight = offset;
|
||||
}
|
||||
maximumTrack -= groupHeight;
|
||||
proposedTrack = qMin(proposedTrack, maximumTrack);
|
||||
proposedTrack = qMax(proposedTrack, 0);
|
||||
int groupOffset = proposedTrack - topTrack;
|
||||
if (!lockedTracks.isEmpty()) {
|
||||
for (int i = 0; i < groupTracks.count(); ++i) {
|
||||
if (lockedTracks.contains(QString::number(groupTracks.at(i) + groupOffset))) {
|
||||
return pos();
|
||||
}
|
||||
}
|
||||
}
|
||||
newPos.setY((int)((proposedTrack) * trackHeight) + offset);
|
||||
//if (newPos == start) return start;
|
||||
|
||||
/*if (newPos.x() < 0) {
|
||||
// If group goes below 0, adjust position to 0
|
||||
return QPointF(pos().x() - start.x(), pos().y());
|
||||
}*/
|
||||
|
||||
QList<QGraphicsItem*> collidingItems;
|
||||
QPainterPath shape;
|
||||
if (projectScene()->editMode() == NORMALEDIT) {
|
||||
shape = clipGroupShape(newPos - pos());
|
||||
collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
|
||||
collidingItems.removeAll(this);
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() == GROUPWIDGET) {
|
||||
QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
|
||||
for (int j = 0; j < subchildren.count(); j++) {
|
||||
collidingItems.removeAll(subchildren.at(j));
|
||||
}
|
||||
}
|
||||
collidingItems.removeAll(children.at(i));
|
||||
}
|
||||
}
|
||||
if (!collidingItems.isEmpty()) {
|
||||
bool forwardMove = xpos > start.x();
|
||||
int offset = 0;
|
||||
for (int i = 0; i < collidingItems.count(); ++i) {
|
||||
QGraphicsItem *collision = collidingItems.at(i);
|
||||
if (collision->type() == AVWIDGET) {
|
||||
// Collision
|
||||
if (newPos.y() != pos().y()) {
|
||||
// Track change results in collision, restore original position
|
||||
return pos();
|
||||
}
|
||||
AbstractClipItem *item = static_cast <AbstractClipItem *>(collision);
|
||||
if (forwardMove) {
|
||||
// Moving forward, determine best pos
|
||||
QPainterPath clipPath;
|
||||
clipPath.addRect(item->sceneBoundingRect());
|
||||
QPainterPath res = shape.intersected(clipPath);
|
||||
offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
|
||||
} else {
|
||||
// Moving backward, determine best pos
|
||||
QPainterPath clipPath;
|
||||
clipPath.addRect(item->sceneBoundingRect());
|
||||
QPainterPath res = shape.intersected(clipPath);
|
||||
offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset > 0) {
|
||||
if (forwardMove) {
|
||||
newPos.setX(newPos.x() - offset);
|
||||
} else {
|
||||
newPos.setX(newPos.x() + offset);
|
||||
}
|
||||
// If there is still a collision after our position adjust, restore original pos
|
||||
collidingItems = scene()->items(clipGroupShape(newPos - pos()), Qt::IntersectsItemShape);
|
||||
collidingItems.removeAll(this);
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() == GROUPWIDGET) {
|
||||
QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
|
||||
for (int j = 0; j < subchildren.count(); j++) {
|
||||
collidingItems.removeAll(subchildren.at(j));
|
||||
}
|
||||
}
|
||||
collidingItems.removeAll(children.at(i));
|
||||
}
|
||||
for (int i = 0; i < collidingItems.count(); ++i)
|
||||
if (collidingItems.at(i)->type() == AVWIDGET) return pos();
|
||||
}
|
||||
}
|
||||
|
||||
if (projectScene()->editMode() == NORMALEDIT) {
|
||||
shape = transitionGroupShape(newPos - pos());
|
||||
collidingItems = scene()->items(shape, Qt::IntersectsItemShape);
|
||||
collidingItems.removeAll(this);
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() == GROUPWIDGET) {
|
||||
QList<QGraphicsItem *> subchildren = children.at(i)->childItems();
|
||||
for (int j = 0; j < subchildren.count(); j++) {
|
||||
collidingItems.removeAll(subchildren.at(j));
|
||||
}
|
||||
}
|
||||
collidingItems.removeAll(children.at(i));
|
||||
}
|
||||
}
|
||||
if (collidingItems.isEmpty()) return newPos;
|
||||
else {
|
||||
bool forwardMove = xpos > start.x();
|
||||
int offset = 0;
|
||||
for (int i = 0; i < collidingItems.count(); ++i) {
|
||||
QGraphicsItem *collision = collidingItems.at(i);
|
||||
if (collision->type() == TRANSITIONWIDGET) {
|
||||
// Collision
|
||||
if (newPos.y() != pos().y()) {
|
||||
// Track change results in collision, restore original position
|
||||
return pos();
|
||||
}
|
||||
AbstractClipItem *item = static_cast <AbstractClipItem *>(collision);
|
||||
if (forwardMove) {
|
||||
// Moving forward, determine best pos
|
||||
QPainterPath clipPath;
|
||||
clipPath.addRect(item->sceneBoundingRect());
|
||||
QPainterPath res = shape.intersected(clipPath);
|
||||
offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
|
||||
} else {
|
||||
// Moving backward, determine best pos
|
||||
QPainterPath clipPath;
|
||||
clipPath.addRect(item->sceneBoundingRect());
|
||||
QPainterPath res = shape.intersected(clipPath);
|
||||
offset = qMax(offset, (int)(res.boundingRect().width() + 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset > 0) {
|
||||
if (forwardMove) {
|
||||
newPos.setX(newPos.x() - offset);
|
||||
} else {
|
||||
newPos.setX(newPos.x() + offset);
|
||||
}
|
||||
// If there is still a collision after our position adjust, restore original pos
|
||||
collidingItems = scene()->items(transitionGroupShape(newPos - pos()), Qt::IntersectsItemShape);
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
collidingItems.removeAll(children.at(i));
|
||||
}
|
||||
for (int i = 0; i < collidingItems.count(); ++i)
|
||||
if (collidingItems.at(i)->type() == TRANSITIONWIDGET) return pos();
|
||||
}
|
||||
}
|
||||
return newPos;
|
||||
}
|
||||
return QGraphicsItemGroup::itemChange(change, value);
|
||||
}
|
||||
|
||||
//virtual
|
||||
void AbstractGroupItem::dropEvent(QGraphicsSceneDragDropEvent * event)
|
||||
{
|
||||
QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist"));
|
||||
QDomDocument doc;
|
||||
doc.setContent(effects, true);
|
||||
QDomElement e = doc.documentElement();
|
||||
e.setAttribute("kdenlive_ix", 0);
|
||||
CustomTrackView *view = (CustomTrackView *) scene()->views()[0];
|
||||
QPointF dropPos = event->scenePos();
|
||||
QList<QGraphicsItem *> selection = scene()->items(dropPos);
|
||||
AbstractClipItem *dropChild = NULL;
|
||||
for (int i = 0; i < selection.count(); ++i) {
|
||||
if (selection.at(i)->type() == AVWIDGET) {
|
||||
dropChild = (AbstractClipItem *) selection.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (view) view->slotAddGroupEffect(e, this, dropChild);
|
||||
}
|
||||
|
||||
//virtual
|
||||
void AbstractGroupItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
||||
{
|
||||
event->setAccepted(event->mimeData()->hasFormat("kdenlive/effectslist"));
|
||||
}
|
||||
|
||||
void AbstractGroupItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
}
|
||||
|
||||
// virtual
|
||||
void AbstractGroupItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
|
||||
{
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
// User want to do a rectangle selection, so ignore the event to pass it to the view
|
||||
event->ignore();
|
||||
} else {
|
||||
QList <QGraphicsItem *>list = scene()->items(event->scenePos());
|
||||
// only allow group move if we click over an item in the group
|
||||
foreach(const QGraphicsItem *item, list) {
|
||||
if (item->type() == TRANSITIONWIDGET || item->type() == AVWIDGET) {
|
||||
QGraphicsItem::mousePressEvent(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractGroupItem::resizeStart(int diff)
|
||||
{
|
||||
bool info = false;
|
||||
if (m_resizeInfos.isEmpty())
|
||||
info = true;
|
||||
int maximum = diff;
|
||||
QList <QGraphicsItem *> children = childItems();
|
||||
QList <AbstractClipItem *> items;
|
||||
int itemcount = 0;
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
|
||||
if (item && item->type() == AVWIDGET) {
|
||||
items << item;
|
||||
if (info)
|
||||
m_resizeInfos << item->info();
|
||||
item->resizeStart((int)(m_resizeInfos.at(itemcount).startPos.frames(item->fps())) + diff);
|
||||
int itemdiff = (int)(item->startPos() - m_resizeInfos.at(itemcount).startPos).frames(item->fps());
|
||||
if (qAbs(itemdiff) < qAbs(maximum))
|
||||
maximum = itemdiff;
|
||||
++itemcount;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.count(); ++i)
|
||||
items.at(i)->resizeStart((int)(m_resizeInfos.at(i).startPos.frames(items.at(i)->fps())) + maximum);
|
||||
}
|
||||
|
||||
void AbstractGroupItem::resizeEnd(int diff)
|
||||
{
|
||||
bool info = false;
|
||||
if (m_resizeInfos.isEmpty())
|
||||
info = true;
|
||||
int maximum = diff;
|
||||
QList <QGraphicsItem *> children = childItems();
|
||||
QList <AbstractClipItem *> items;
|
||||
int itemcount = 0;
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
|
||||
if (item && item->type() == AVWIDGET) {
|
||||
items << item;
|
||||
if (info)
|
||||
m_resizeInfos << item->info();
|
||||
item->resizeEnd((int)(m_resizeInfos.at(itemcount).endPos.frames(item->fps())) + diff);
|
||||
int itemdiff = (int)(item->endPos() - m_resizeInfos.at(itemcount).endPos).frames(item->fps());
|
||||
if (qAbs(itemdiff) < qAbs(maximum))
|
||||
maximum = itemdiff;
|
||||
++itemcount;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.count(); ++i)
|
||||
items.at(i)->resizeEnd((int)(m_resizeInfos.at(i).endPos.frames(items.at(i)->fps())) + maximum);
|
||||
}
|
||||
|
||||
QList< ItemInfo > AbstractGroupItem::resizeInfos()
|
||||
{
|
||||
return m_resizeInfos;
|
||||
}
|
||||
|
||||
void AbstractGroupItem::clearResizeInfos()
|
||||
{
|
||||
// m_resizeInfos.clear() will crash in some cases for unknown reasons - ttill
|
||||
m_resizeInfos = QList <ItemInfo>();
|
||||
}
|
||||
|
||||
GenTime AbstractGroupItem::duration()
|
||||
{
|
||||
QList <QGraphicsItem *> children = childItems();
|
||||
GenTime start = GenTime(-1.0);
|
||||
GenTime end = GenTime();
|
||||
for (int i = 0; i < children.count(); ++i) {
|
||||
if (children.at(i)->type() != GROUPWIDGET) {
|
||||
AbstractClipItem *item = static_cast <AbstractClipItem *>(children.at(i));
|
||||
if (item) {
|
||||
if (start < GenTime() || item->startPos() < start)
|
||||
start = item->startPos();
|
||||
if (item->endPos() > end)
|
||||
end = item->endPos();
|
||||
}
|
||||
} else {
|
||||
children << children.at(i)->childItems();
|
||||
}
|
||||
}
|
||||
return end - start;
|
||||
}
|
||||
|
||||
#include "abstractgroupitem.moc"
|
||||
@@ -1,80 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) *
|
||||
* Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ABSTRACTGROUPITEM
|
||||
#define ABSTRACTGROUPITEM
|
||||
|
||||
#include "definitions.h"
|
||||
#include "gentime.h"
|
||||
|
||||
#include <QGraphicsItemGroup>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
|
||||
class CustomTrackScene;
|
||||
class QGraphicsSceneMouseEvent;
|
||||
|
||||
class AbstractGroupItem : public QObject , public QGraphicsItemGroup
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AbstractGroupItem(double fps);
|
||||
virtual int type() const;
|
||||
CustomTrackScene* projectScene();
|
||||
void addItem(QGraphicsItem * item);
|
||||
void removeItem(QGraphicsItem * item);
|
||||
int track() const;
|
||||
QPainterPath clipGroupShape(const QPointF &offset) const;
|
||||
QPainterPath clipGroupSpacerShape(const QPointF &offset) const;
|
||||
QPainterPath transitionGroupShape(const QPointF &offset) const;
|
||||
void setItemLocked(bool locked);
|
||||
bool isItemLocked() const;
|
||||
// ItemInfo info() const;
|
||||
|
||||
/** @brief Resizes all clips in this group from start.
|
||||
*@param diff Difference to startPos stored in m_resizeInfos */
|
||||
void resizeStart(int diff);
|
||||
/** @brief Resizes all clips in this group from end.
|
||||
* @param diff Difference to endPos stored in m_resizeInfos */
|
||||
void resizeEnd(int diff);
|
||||
/** @brief Gets m_resizeInfos */
|
||||
QList <ItemInfo> resizeInfos();
|
||||
/** @brief Clears m_resizeInfos */
|
||||
void clearResizeInfos();
|
||||
|
||||
/** @brief Gets the duration (length) of the group. */
|
||||
GenTime duration();
|
||||
|
||||
protected:
|
||||
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
|
||||
virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
|
||||
virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
|
||||
virtual void dropEvent(QGraphicsSceneDragDropEvent *event);
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent * event);
|
||||
|
||||
private:
|
||||
void fixItemRect();
|
||||
QPainterPath groupShape(GRAPHICSRECTITEM type, const QPointF &offset) const;
|
||||
QPainterPath spacerGroupShape(GRAPHICSRECTITEM type, const QPointF &offset) const;
|
||||
/** Stores the original info of the items beeing resized. */
|
||||
QList <ItemInfo> m_resizeInfos;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,183 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "abstractmonitor.h"
|
||||
#include "kdenlivesettings.h"
|
||||
#include "monitormanager.h"
|
||||
|
||||
#include <KDebug>
|
||||
|
||||
#include <QPaintEvent>
|
||||
#include <QDesktopWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
|
||||
AbstractMonitor::AbstractMonitor(Kdenlive::MONITORID id, MonitorManager *manager, QWidget *parent):
|
||||
QWidget(parent),
|
||||
videoSurface(NULL),
|
||||
m_id(id),
|
||||
m_monitorManager(manager)
|
||||
{
|
||||
videoBox = new VideoContainer(this);
|
||||
}
|
||||
|
||||
|
||||
AbstractMonitor::~AbstractMonitor()
|
||||
{
|
||||
delete videoSurface;
|
||||
}
|
||||
|
||||
void AbstractMonitor::createVideoSurface()
|
||||
{
|
||||
QVBoxLayout *lay = new QVBoxLayout;
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
videoSurface = new VideoSurface;
|
||||
lay->addWidget(videoSurface);
|
||||
videoBox->setLayout(lay);
|
||||
}
|
||||
|
||||
bool AbstractMonitor::isActive() const
|
||||
{
|
||||
return m_monitorManager->isActive(m_id);
|
||||
}
|
||||
|
||||
bool AbstractMonitor::slotActivateMonitor(bool forceRefresh)
|
||||
{
|
||||
return m_monitorManager->activateMonitor(m_id, forceRefresh);
|
||||
}
|
||||
|
||||
VideoContainer::VideoContainer(AbstractMonitor* monitor, QWidget *parent) :
|
||||
QFrame(parent)
|
||||
, m_monitor(monitor)
|
||||
{
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
//setEnabled(false);
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void VideoContainer::mouseReleaseEvent(QMouseEvent * event)
|
||||
{
|
||||
if (event->button() != Qt::RightButton) {
|
||||
if (m_monitor->isActive()) {
|
||||
m_monitor->slotPlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void VideoContainer::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
// Exit fullscreen with Esc key
|
||||
if (event->key() == Qt::Key_Escape && isFullScreen()) {
|
||||
switchFullScreen();
|
||||
event->setAccepted(true);
|
||||
} else event->setAccepted(false);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void VideoContainer::wheelEvent(QWheelEvent * event)
|
||||
{
|
||||
m_monitor->slotMouseSeek(event->delta(), event->modifiers() == Qt::ControlModifier);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void VideoContainer::mouseDoubleClickEvent(QMouseEvent * event)
|
||||
{
|
||||
if (!KdenliveSettings::openglmonitors())
|
||||
switchFullScreen();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void VideoContainer::switchFullScreen()
|
||||
{
|
||||
// TODO: disable screensaver?
|
||||
Qt::WindowFlags flags = windowFlags();
|
||||
if (!isFullScreen()) {
|
||||
// Check if we ahave a multiple monitor setup
|
||||
setUpdatesEnabled(false);
|
||||
#if QT_VERSION >= 0x040600
|
||||
int monitors = QApplication::desktop()->screenCount();
|
||||
#else
|
||||
int monitors = QApplication::desktop()->numScreens();
|
||||
#endif
|
||||
if (monitors > 1) {
|
||||
QRect screenres;
|
||||
// Move monitor widget to the second screen (one screen for Kdenlive, the other one for the Monitor widget
|
||||
int currentScreen = QApplication::desktop()->screenNumber(this);
|
||||
if (currentScreen < monitors - 1)
|
||||
screenres = QApplication::desktop()->screenGeometry(currentScreen + 1);
|
||||
else
|
||||
screenres = QApplication::desktop()->screenGeometry(currentScreen - 1);
|
||||
move(QPoint(screenres.x(), screenres.y()));
|
||||
resize(screenres.width(), screenres.height());
|
||||
}
|
||||
|
||||
m_baseFlags = flags & (Qt::Window | Qt::SubWindow);
|
||||
flags |= Qt::Window;
|
||||
flags ^= Qt::SubWindow;
|
||||
setWindowFlags(flags);
|
||||
#ifdef Q_WS_X11
|
||||
// This works around a bug with Compiz
|
||||
// as the window must be visible before we can set the state
|
||||
show();
|
||||
raise();
|
||||
setWindowState(windowState() | Qt::WindowFullScreen); // set
|
||||
#else
|
||||
setWindowState(windowState() | Qt::WindowFullScreen); // set
|
||||
setUpdatesEnabled(true);
|
||||
show();
|
||||
#endif
|
||||
setEnabled(true);
|
||||
} else {
|
||||
setUpdatesEnabled(false);
|
||||
flags ^= (Qt::Window | Qt::SubWindow); //clear the flags...
|
||||
flags |= m_baseFlags; //then we reset the flags (window and subwindow)
|
||||
setWindowFlags(flags);
|
||||
setWindowState(windowState() ^ Qt::WindowFullScreen); // reset
|
||||
setUpdatesEnabled(true);
|
||||
setEnabled(false);
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
VideoSurface::VideoSurface(QWidget* parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
// MonitorRefresh is used as container for the SDL display (it's window id is passed to SDL)
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
//setUpdatesEnabled(false);
|
||||
}
|
||||
|
||||
void VideoSurface::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
//WARNING: This might trigger unnecessary refreshes from MLT's producer, but without this,
|
||||
// as soon as monitor is covered by a popup menu or another window, image is corrupted.
|
||||
emit refreshMonitor();
|
||||
}
|
||||
|
||||
|
||||
#include "abstractmonitor.moc"
|
||||
@@ -1,138 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ABSTRACTMONITOR_H
|
||||
#define ABSTRACTMONITOR_H
|
||||
|
||||
#include "definitions.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QWidget>
|
||||
#include <QImage>
|
||||
#include <QFrame>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class MonitorManager;
|
||||
class VideoContainer;
|
||||
|
||||
class AbstractRender: public QObject
|
||||
{
|
||||
Q_OBJECT public:
|
||||
|
||||
/** @brief Build an abstract MLT Renderer
|
||||
* @param name A unique identifier for this renderer
|
||||
* @param winid The parent widget identifier (required for SDL display). Set to 0 for OpenGL rendering
|
||||
* @param profile The MLT profile used for the renderer (default one will be used if empty). */
|
||||
explicit AbstractRender(Kdenlive::MONITORID name, QWidget *parent = 0)
|
||||
: QObject(parent),
|
||||
sendFrameForAnalysis(false),
|
||||
analyseAudio(false),
|
||||
m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Destroy the MLT Renderer. */
|
||||
virtual ~AbstractRender() {}
|
||||
|
||||
/** @brief This property is used to decide if the renderer should convert it's frames to QImage for use in other Kdenlive widgets. */
|
||||
bool sendFrameForAnalysis;
|
||||
|
||||
/** @brief This property is used to decide if the renderer should send audio data for monitoring. */
|
||||
bool analyseAudio;
|
||||
|
||||
const QString &name() const {return m_name;}
|
||||
|
||||
/** @brief Someone needs us to send again a frame. */
|
||||
virtual void sendFrameUpdate() = 0;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
|
||||
signals:
|
||||
/** @brief The renderer refreshed the current frame. */
|
||||
void frameUpdated(const QImage &);
|
||||
|
||||
/** @brief This signal contains the audio of the current frame. */
|
||||
void audioSamplesSignal(const QVector<int16_t>&,int,int,int);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class VideoSurface : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VideoSurface(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
void refreshMonitor();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent ( QPaintEvent * event );
|
||||
};
|
||||
|
||||
|
||||
class AbstractMonitor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AbstractMonitor(Kdenlive::MONITORID id, MonitorManager *manager, QWidget *parent = 0);
|
||||
Kdenlive::MONITORID id() {return m_id;}
|
||||
virtual ~AbstractMonitor();
|
||||
virtual AbstractRender *abstractRender() = 0;
|
||||
bool isActive() const;
|
||||
VideoContainer *videoBox;
|
||||
VideoSurface *videoSurface;
|
||||
void createVideoSurface();
|
||||
|
||||
|
||||
public slots:
|
||||
virtual void stop() = 0;
|
||||
virtual void start() = 0;
|
||||
virtual void slotPlay() = 0;
|
||||
virtual void slotMouseSeek(int eventDelta, bool fast) = 0;
|
||||
bool slotActivateMonitor(bool forceRefresh = false);
|
||||
virtual void slotSwitchFullScreen() = 0;
|
||||
|
||||
protected:
|
||||
Kdenlive::MONITORID m_id;
|
||||
MonitorManager *m_monitorManager;
|
||||
};
|
||||
|
||||
class VideoContainer : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VideoContainer(AbstractMonitor *monitor, QWidget *parent = 0);
|
||||
void switchFullScreen();
|
||||
|
||||
protected:
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent * event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
virtual void wheelEvent(QWheelEvent * event);
|
||||
|
||||
private:
|
||||
Qt::WindowFlags m_baseFlags;
|
||||
AbstractMonitor *m_monitor;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef ARCHIVEWIDGET_H
|
||||
#define ARCHIVEWIDGET_H
|
||||
|
||||
|
||||
#include "ui_archivewidget_ui.h"
|
||||
#include "docclipbase.h"
|
||||
|
||||
#include <kio/global.h>
|
||||
#include <KIO/CopyJob>
|
||||
#include <KTemporaryFile>
|
||||
#include <kdeversion.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
|
||||
|
||||
class KJob;
|
||||
class KArchive;
|
||||
|
||||
/**
|
||||
* @class ArchiveWidget
|
||||
* @brief A widget allowing to archive a project (copy all project files to a new location)
|
||||
* @author Jean-Baptiste Mardelle
|
||||
*/
|
||||
|
||||
#if KDE_IS_VERSION(4,7,0)
|
||||
class KMessageWidget;
|
||||
#endif
|
||||
|
||||
class ArchiveWidget : public QDialog, public Ui::ArchiveWidget_UI
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ArchiveWidget(const QString &projectName, const QDomDocument &doc, const QList <DocClipBase*> &list, const QStringList &luma_list, QWidget * parent = 0);
|
||||
// Constructor for extracting widget
|
||||
explicit ArchiveWidget(const KUrl &url, QWidget * parent = 0);
|
||||
~ArchiveWidget();
|
||||
|
||||
QString extractedProjectFile() const;
|
||||
|
||||
private slots:
|
||||
void slotCheckSpace();
|
||||
bool slotStartArchiving(bool firstPass = true);
|
||||
void slotArchivingFinished(KJob *job = NULL, bool finished = false);
|
||||
void slotArchivingProgress(KJob *, qulonglong);
|
||||
virtual void done ( int r );
|
||||
bool closeAccepted();
|
||||
void createArchive();
|
||||
void slotArchivingProgress(int);
|
||||
void slotArchivingFinished(bool result);
|
||||
void slotStartExtracting();
|
||||
void doExtracting();
|
||||
void slotExtractingFinished();
|
||||
void slotExtractProgress();
|
||||
void slotGotProgress(KJob*);
|
||||
void openArchiveForExtraction();
|
||||
void slotDisplayMessage(const QString &icon, const QString &text);
|
||||
void slotJobResult(bool success, const QString &text);
|
||||
void slotProxyOnly(int onlyProxy);
|
||||
|
||||
protected:
|
||||
virtual void closeEvent ( QCloseEvent * e );
|
||||
|
||||
private:
|
||||
KIO::filesize_t m_requestedSize;
|
||||
KIO::CopyJob *m_copyJob;
|
||||
QMap <KUrl, KUrl> m_duplicateFiles;
|
||||
QMap <KUrl, KUrl> m_replacementList;
|
||||
QString m_name;
|
||||
QDomDocument m_doc;
|
||||
KTemporaryFile *m_temp;
|
||||
bool m_abortArchive;
|
||||
QFuture<void> m_archiveThread;
|
||||
QStringList m_foldersList;
|
||||
QMap <QString, QString> m_filesList;
|
||||
bool m_extractMode;
|
||||
KUrl m_extractUrl;
|
||||
QString m_projectName;
|
||||
QTimer *m_progressTimer;
|
||||
KArchive *m_extractArchive;
|
||||
int m_missingClips;
|
||||
|
||||
#if KDE_IS_VERSION(4,7,0)
|
||||
KMessageWidget *m_infoMessage;
|
||||
#endif
|
||||
|
||||
/** @brief Generate tree widget subitems from a string list of urls. */
|
||||
void generateItems(QTreeWidgetItem *parentItem, const QStringList &items);
|
||||
/** @brief Generate tree widget subitems from a map of clip ids / urls. */
|
||||
void generateItems(QTreeWidgetItem *parentItem, const QMap<QString, QString> &items);
|
||||
/** @brief Replace urls in project file. */
|
||||
bool processProjectFile();
|
||||
|
||||
signals:
|
||||
void archivingFinished(bool);
|
||||
void archiveProgress(int);
|
||||
void extractingFinished();
|
||||
void showMessage(const QString &, const QString &);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
set(kdenlive_SRCS
|
||||
${kdenlive_SRCS}
|
||||
audioscopes/abstractaudioscopewidget.cpp
|
||||
audioscopes/audiospectrum.cpp
|
||||
audioscopes/spectrogram.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -1,8 +0,0 @@
|
||||
set(kdenlive_SRCS
|
||||
${kdenlive_SRCS}
|
||||
beziercurve/beziersplineeditor.cpp
|
||||
beziercurve/beziersplinewidget.cpp
|
||||
beziercurve/bpoint.cpp
|
||||
beziercurve/cubicbezierspline.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -1,499 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "beziersplineeditor.h"
|
||||
#include "kdenlivesettings.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
|
||||
BezierSplineEditor::BezierSplineEditor(QWidget* parent) :
|
||||
QWidget(parent)
|
||||
, m_mode(ModeNormal)
|
||||
, m_zoomLevel(0)
|
||||
, m_gridLines(3)
|
||||
, m_showAllHandles(true)
|
||||
, m_pixmapCache(NULL)
|
||||
, m_pixmapIsDirty(true)
|
||||
, m_currentPointIndex(-1)
|
||||
, m_currentPointType(PTypeP)
|
||||
, m_grabOffsetX(0)
|
||||
, m_grabOffsetY(0)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
setMinimumSize(150, 150);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
BezierSplineEditor::~BezierSplineEditor()
|
||||
{
|
||||
delete m_pixmapCache;
|
||||
}
|
||||
|
||||
CubicBezierSpline BezierSplineEditor::spline() const
|
||||
{
|
||||
return m_spline;
|
||||
}
|
||||
|
||||
void BezierSplineEditor::setSpline(const CubicBezierSpline& spline)
|
||||
{
|
||||
m_spline = spline;
|
||||
m_currentPointIndex = -1;
|
||||
m_mode = ModeNormal;
|
||||
emit currentPoint(BPoint());
|
||||
emit modified();
|
||||
update();
|
||||
}
|
||||
|
||||
BPoint BezierSplineEditor::getCurrentPoint()
|
||||
{
|
||||
if (m_currentPointIndex >= 0)
|
||||
return m_spline.getPoint(m_currentPointIndex);
|
||||
else
|
||||
return BPoint();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::updateCurrentPoint(const BPoint& p, bool final)
|
||||
{
|
||||
if (m_currentPointIndex >= 0) {
|
||||
m_spline.setPoint(m_currentPointIndex, p);
|
||||
// during validation the point might have changed
|
||||
emit currentPoint(m_spline.getPoint(m_currentPointIndex));
|
||||
if (final)
|
||||
emit modified();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void BezierSplineEditor::setPixmap(const QPixmap& pixmap)
|
||||
{
|
||||
m_pixmap = pixmap;
|
||||
m_pixmapIsDirty = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::slotZoomIn()
|
||||
{
|
||||
m_zoomLevel = qMax(m_zoomLevel-1, 0);
|
||||
m_pixmapIsDirty = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::slotZoomOut()
|
||||
{
|
||||
m_zoomLevel = qMin(m_zoomLevel+1, 3);
|
||||
m_pixmapIsDirty = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::setShowAllHandles(bool show)
|
||||
{
|
||||
if (m_showAllHandles != show) {
|
||||
m_showAllHandles = show;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
int BezierSplineEditor::gridLines() const
|
||||
{
|
||||
return m_gridLines;
|
||||
}
|
||||
|
||||
void BezierSplineEditor::setGridLines(int lines)
|
||||
{
|
||||
m_gridLines = qBound(0, lines, 8);
|
||||
update();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter p(this);
|
||||
|
||||
/*
|
||||
* Zoom
|
||||
*/
|
||||
int wWidth = width() - 1;
|
||||
int wHeight = height() - 1;
|
||||
int offsetX = 1/8. * m_zoomLevel * wWidth;
|
||||
int offsetY = 1/8. * m_zoomLevel * wHeight;
|
||||
wWidth -= 2 * offsetX;
|
||||
wHeight -= 2 * offsetY;
|
||||
|
||||
p.translate(offsetX, offsetY);
|
||||
|
||||
/*
|
||||
* Background
|
||||
*/
|
||||
p.fillRect(rect().translated(-offsetX, -offsetY), palette().background());
|
||||
if (!m_pixmap.isNull()) {
|
||||
if (m_pixmapIsDirty || !m_pixmapCache) {
|
||||
if (m_pixmapCache)
|
||||
delete m_pixmapCache;
|
||||
m_pixmapCache = new QPixmap(wWidth + 1, wHeight + 1);
|
||||
QPainter cachePainter(m_pixmapCache);
|
||||
|
||||
cachePainter.scale(1.0*(wWidth+1) / m_pixmap.width(), 1.0*(wHeight+1) / m_pixmap.height());
|
||||
cachePainter.drawPixmap(0, 0, m_pixmap);
|
||||
m_pixmapIsDirty = false;
|
||||
}
|
||||
p.drawPixmap(0, 0, *m_pixmapCache);
|
||||
}
|
||||
|
||||
|
||||
p.setPen(QPen(Qt::gray, 1, Qt::SolidLine));
|
||||
|
||||
/*
|
||||
* Borders
|
||||
*/
|
||||
if (m_zoomLevel != 0) {
|
||||
p.drawRect(0, 0, wWidth, wHeight);
|
||||
}
|
||||
|
||||
/*
|
||||
* Grid
|
||||
*/
|
||||
if (m_gridLines != 0) {
|
||||
double stepH = wWidth / (double)(m_gridLines + 1);
|
||||
double stepV = wHeight / (double)(m_gridLines + 1);
|
||||
for (int i = 1; i <= m_gridLines; ++i) {
|
||||
p.drawLine(QLineF(i * stepH, 0, i * stepH, wHeight));
|
||||
p.drawLine(QLineF(0, i * stepV, wWidth, i * stepV));
|
||||
}
|
||||
}
|
||||
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
/*
|
||||
* Standard line
|
||||
*/
|
||||
p.drawLine(QLineF(0, wHeight, wWidth, 0));
|
||||
|
||||
|
||||
/*
|
||||
* Prepare Spline, Points
|
||||
*/
|
||||
int max = m_spline.points().count() - 1;
|
||||
if (max < 1)
|
||||
return;
|
||||
BPoint point(m_spline.getPoint(0, wWidth, wHeight, true));
|
||||
|
||||
/*
|
||||
* Spline
|
||||
*/
|
||||
BPoint next;
|
||||
|
||||
QPainterPath splinePath(QPointF(point.p.x(), point.p.y()));
|
||||
for (int i = 0; i < max; ++i) {
|
||||
point = m_spline.getPoint(i, wWidth, wHeight, true);
|
||||
next = m_spline.getPoint(i + 1, wWidth, wHeight, true);
|
||||
splinePath.cubicTo(point.h2, next.h1, next.p);
|
||||
}
|
||||
p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
|
||||
p.drawPath(splinePath);
|
||||
|
||||
|
||||
/*
|
||||
* Points + Handles
|
||||
*/
|
||||
p.setPen(QPen(Qt::red, 1, Qt::SolidLine));
|
||||
|
||||
QPolygonF handle = QPolygonF() << QPointF(0, -3) << QPointF(3, 0) << QPointF(0, 3) << QPointF(-3, 0);
|
||||
#if QT_VERSION < 0x040600
|
||||
QPolygonF tmp;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i <= max; ++i) {
|
||||
point = m_spline.getPoint(i, wWidth, wHeight, true);
|
||||
|
||||
if (i == m_currentPointIndex) {
|
||||
// selected point: fill p and handles
|
||||
p.setBrush(QBrush(QColor(Qt::red), Qt::SolidPattern));
|
||||
// connect p and handles with lines
|
||||
if (i != 0)
|
||||
p.drawLine(QLineF(point.h1.x(), point.h1.y(), point.p.x(),point.p.y()));
|
||||
if (i != max)
|
||||
p.drawLine(QLineF(point.p.x(), point.p.y(), point.h2.x(), point.h2.y()));
|
||||
}
|
||||
|
||||
p.drawEllipse(QRectF(point.p.x() - 3,
|
||||
point.p.y() - 3, 6, 6));
|
||||
if (i != 0 && (i == m_currentPointIndex || m_showAllHandles)) {
|
||||
#if QT_VERSION >= 0x040600
|
||||
p.drawConvexPolygon(handle.translated(point.h1.x(), point.h1.y()));
|
||||
#else
|
||||
tmp = handle;
|
||||
tmp.translate(point.h1.x(), point.h1.y());
|
||||
p.drawConvexPolygon(tmp);
|
||||
#endif
|
||||
}
|
||||
if (i != max && (i == m_currentPointIndex || m_showAllHandles)) {
|
||||
#if QT_VERSION >= 0x040600
|
||||
p.drawConvexPolygon(handle.translated(point.h2.x(), point.h2.y()));
|
||||
#else
|
||||
tmp = handle;
|
||||
tmp.translate(point.h2.x(), point.h2.y());
|
||||
p.drawConvexPolygon(tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( i == m_currentPointIndex)
|
||||
p.setBrush(QBrush(Qt::NoBrush));
|
||||
}
|
||||
}
|
||||
|
||||
void BezierSplineEditor::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
m_pixmapIsDirty = true;
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void BezierSplineEditor::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
int wWidth = width() - 1;
|
||||
int wHeight = height() - 1;
|
||||
int offsetX = 1/8. * m_zoomLevel * wWidth;
|
||||
int offsetY = 1/8. * m_zoomLevel * wHeight;
|
||||
wWidth -= 2 * offsetX;
|
||||
wHeight -= 2 * offsetY;
|
||||
|
||||
double x = (event->pos().x() - offsetX) / (double)(wWidth);
|
||||
double y = 1.0 - (event->pos().y() - offsetY) / (double)(wHeight);
|
||||
|
||||
point_types selectedPoint;
|
||||
int closestPointIndex = nearestPointInRange(QPointF(x, y), wWidth, wHeight, &selectedPoint);
|
||||
|
||||
if (event->button() == Qt::RightButton && closestPointIndex > 0 && closestPointIndex < m_spline.points().count() - 1 && selectedPoint == PTypeP) {
|
||||
m_spline.removePoint(closestPointIndex);
|
||||
setCursor(Qt::ArrowCursor);
|
||||
m_mode = ModeNormal;
|
||||
if (closestPointIndex < m_currentPointIndex)
|
||||
--m_currentPointIndex;
|
||||
update();
|
||||
if (m_currentPointIndex >= 0)
|
||||
emit currentPoint(m_spline.getPoint(m_currentPointIndex));
|
||||
else
|
||||
emit currentPoint(BPoint());
|
||||
emit modified();
|
||||
return;
|
||||
} else if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (closestPointIndex < 0) {
|
||||
m_currentPointIndex = m_spline.addPoint(BPoint(QPointF(x-0.05, y-0.05),
|
||||
QPointF(x, y),
|
||||
QPointF(x+0.05, y+0.05)));
|
||||
m_currentPointType = PTypeP;
|
||||
} else {
|
||||
m_currentPointIndex = closestPointIndex;
|
||||
m_currentPointType = selectedPoint;
|
||||
}
|
||||
|
||||
BPoint point = m_spline.getPoint(m_currentPointIndex);
|
||||
|
||||
m_grabPOriginal = point;
|
||||
if (m_currentPointIndex > 0)
|
||||
m_grabPPrevious = m_spline.getPoint(m_currentPointIndex - 1);
|
||||
if (m_currentPointIndex < m_spline.points().count() - 1)
|
||||
m_grabPNext = m_spline.getPoint(m_currentPointIndex + 1);
|
||||
m_grabOffsetX = point[(int)m_currentPointType].x() - x;
|
||||
m_grabOffsetY = point[(int)m_currentPointType].y() - y;
|
||||
|
||||
point[(int)m_currentPointType] = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
|
||||
|
||||
m_spline.setPoint(m_currentPointIndex, point);
|
||||
|
||||
m_mode = ModeDrag;
|
||||
|
||||
emit currentPoint(point);
|
||||
update();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() != Qt::LeftButton)
|
||||
return;
|
||||
|
||||
setCursor(Qt::ArrowCursor);
|
||||
m_mode = ModeNormal;
|
||||
|
||||
emit modified();
|
||||
}
|
||||
|
||||
void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
int wWidth = width() - 1;
|
||||
int wHeight = height() - 1;
|
||||
int offsetX = 1/8. * m_zoomLevel * wWidth;
|
||||
int offsetY = 1/8. * m_zoomLevel * wHeight;
|
||||
wWidth -= 2 * offsetX;
|
||||
wHeight -= 2 * offsetY;
|
||||
|
||||
double x = (event->pos().x() - offsetX) / (double)(wWidth);
|
||||
double y = 1.0 - (event->pos().y() - offsetY) / (double)(wHeight);
|
||||
|
||||
if (m_mode == ModeNormal) {
|
||||
// If no point is selected set the the cursor shape if on top
|
||||
point_types type;
|
||||
int nearestPointIndex = nearestPointInRange(QPointF(x, y), wWidth, wHeight, &type);
|
||||
|
||||
if (nearestPointIndex < 0)
|
||||
setCursor(Qt::ArrowCursor);
|
||||
else
|
||||
setCursor(Qt::CrossCursor);
|
||||
} else {
|
||||
// Else, drag the selected point
|
||||
setCursor(Qt::CrossCursor);
|
||||
|
||||
x += m_grabOffsetX;
|
||||
y += m_grabOffsetY;
|
||||
|
||||
double leftX = 0.;
|
||||
double rightX = 1.;
|
||||
BPoint point = m_spline.getPoint(m_currentPointIndex);
|
||||
switch (m_currentPointType) {
|
||||
case PTypeH1:
|
||||
rightX = point.p.x();
|
||||
if (m_currentPointIndex == 0)
|
||||
leftX = -4;
|
||||
else
|
||||
leftX = m_spline.getPoint(m_currentPointIndex - 1).p.x();
|
||||
|
||||
x = qBound(leftX, x, rightX);
|
||||
point.setH1(QPointF(x, y));
|
||||
break;
|
||||
|
||||
case PTypeP:
|
||||
if (m_currentPointIndex == 0)
|
||||
rightX = 0.0;
|
||||
else if (m_currentPointIndex == m_spline.points().count() - 1)
|
||||
leftX = 1.0;
|
||||
|
||||
x = qBound(leftX, x, rightX);
|
||||
y = qBound(0., y, 1.);
|
||||
|
||||
// handles might have changed because we neared another point
|
||||
// try to restore
|
||||
point.h1 = m_grabPOriginal.h1;
|
||||
point.h2 = m_grabPOriginal.h2;
|
||||
// and move by same offset
|
||||
// (using update handle in point.setP won't work because the offset between new and old point is very small)
|
||||
point.h1 += QPointF(x, y) - m_grabPOriginal.p;
|
||||
point.h2 += QPointF(x, y) - m_grabPOriginal.p;
|
||||
|
||||
point.setP(QPointF(x, y), false);
|
||||
break;
|
||||
|
||||
case PTypeH2:
|
||||
leftX = point.p.x();
|
||||
if (m_currentPointIndex == m_spline.points().count() - 1)
|
||||
rightX = 5;
|
||||
else
|
||||
rightX = m_spline.getPoint(m_currentPointIndex + 1).p.x();
|
||||
|
||||
x = qBound(leftX, x, rightX);
|
||||
point.setH2(QPointF(x, y));
|
||||
};
|
||||
|
||||
int index = m_currentPointIndex;
|
||||
m_currentPointIndex = m_spline.setPoint(m_currentPointIndex, point);
|
||||
|
||||
if (m_currentPointType == PTypeP) {
|
||||
// we might have changed the handles of other points
|
||||
// try to restore
|
||||
if (index == m_currentPointIndex) {
|
||||
if (m_currentPointIndex > 0)
|
||||
m_spline.setPoint(m_currentPointIndex - 1, m_grabPPrevious);
|
||||
if (m_currentPointIndex < m_spline.points().count() -1)
|
||||
m_spline.setPoint(m_currentPointIndex + 1, m_grabPNext);
|
||||
} else {
|
||||
if (m_currentPointIndex < index) {
|
||||
m_spline.setPoint(index, m_grabPPrevious);
|
||||
m_grabPNext = m_grabPPrevious;
|
||||
if (m_currentPointIndex > 0)
|
||||
m_grabPPrevious = m_spline.getPoint(m_currentPointIndex - 1);
|
||||
} else {
|
||||
m_spline.setPoint(index, m_grabPNext);
|
||||
m_grabPPrevious = m_grabPNext;
|
||||
if (m_currentPointIndex < m_spline.points().count() - 1)
|
||||
m_grabPNext = m_spline.getPoint(m_currentPointIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit currentPoint(point);
|
||||
if (KdenliveSettings::dragvalue_directupdate())
|
||||
emit modified();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void BezierSplineEditor::mouseDoubleClickEvent(QMouseEvent* /*event*/)
|
||||
{
|
||||
if (m_currentPointIndex >= 0) {
|
||||
BPoint p = m_spline.getPoint(m_currentPointIndex);
|
||||
p.handlesLinked = !p.handlesLinked;
|
||||
m_spline.setPoint(m_currentPointIndex, p);
|
||||
emit currentPoint(p);
|
||||
}
|
||||
}
|
||||
|
||||
void BezierSplineEditor::leaveEvent(QEvent* event)
|
||||
{
|
||||
QWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
int BezierSplineEditor::nearestPointInRange(const QPointF &p, int wWidth, int wHeight, BezierSplineEditor::point_types* sel)
|
||||
{
|
||||
double nearestDistanceSquared = 1000;
|
||||
point_types selectedPoint = PTypeP;
|
||||
int nearestIndex = -1;
|
||||
int i = 0;
|
||||
|
||||
double distanceSquared;
|
||||
// find out distance using the Pythagorean theorem
|
||||
foreach(const BPoint & point, m_spline.points()) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
distanceSquared = pow(point[j].x() - p.x(), 2) + pow(point[j].y() - p.y(), 2);
|
||||
if (distanceSquared < nearestDistanceSquared) {
|
||||
nearestIndex = i;
|
||||
nearestDistanceSquared = distanceSquared;
|
||||
selectedPoint = (point_types)j;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if (nearestIndex >= 0 && (nearestIndex == m_currentPointIndex || selectedPoint == PTypeP || m_showAllHandles)) {
|
||||
// a point was found and it is not a hidden handle
|
||||
BPoint point = m_spline.getPoint(nearestIndex);
|
||||
if (qAbs(p.x() - point[(int)selectedPoint].x()) * wWidth < 5 && qAbs(p.y() - point[(int)selectedPoint].y()) * wHeight < 5) {
|
||||
*sel = selectedPoint;
|
||||
return nearestIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include "beziersplineeditor.moc"
|
||||
@@ -1,110 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef BEZIERSPLINEEDITOR_H
|
||||
#define BEZIERSPLINEEDITOR_H
|
||||
|
||||
#include "cubicbezierspline.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QWidget>
|
||||
|
||||
class BezierSplineEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BezierSplineEditor(QWidget* parent = 0);
|
||||
~BezierSplineEditor();
|
||||
|
||||
CubicBezierSpline spline() const;
|
||||
void setSpline(const CubicBezierSpline &spline);
|
||||
|
||||
/** @brief Returns the selected point or else BPoint. */
|
||||
BPoint getCurrentPoint();
|
||||
|
||||
/** @brief Replaces current point with @param p (index stays the same).
|
||||
* @param final (default = true) emit signal modified? */
|
||||
void updateCurrentPoint(const BPoint &p, bool final = true);
|
||||
|
||||
/** @brief Number of lines used in grid. */
|
||||
int gridLines() const;
|
||||
|
||||
/** @brief Sets the number of grid lines to draw (in one direction) to @param lines. */
|
||||
void setGridLines(int lines);
|
||||
|
||||
/** @brief Sets the background pixmap to @param pixmap. */
|
||||
void setPixmap(const QPixmap &pixmap);
|
||||
|
||||
/** @brief Sets the property showAllHandles to @param show.
|
||||
*
|
||||
* showAllHandles: Whether to show only handles for the selected point for all points. */
|
||||
void setShowAllHandles(bool show);
|
||||
|
||||
public slots:
|
||||
void slotZoomIn();
|
||||
void slotZoomOut();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent * event);
|
||||
void mouseMoveEvent(QMouseEvent * event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
void leaveEvent(QEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
CubicBezierSpline m_spline;
|
||||
enum modes { ModeDrag, ModeNormal };
|
||||
enum point_types { PTypeH1, PTypeP, PTypeH2 };
|
||||
modes m_mode;
|
||||
int m_zoomLevel;
|
||||
int m_gridLines;
|
||||
/** Whether to show handles for all points or only for the selected one. */
|
||||
bool m_showAllHandles;
|
||||
/** Background */
|
||||
QPixmap m_pixmap;
|
||||
/** A copy of m_pixmap but scaled to fit the size of the edit region */
|
||||
QPixmap *m_pixmapCache;
|
||||
/** Whether we have to regenerate the pixmap cache because the pixmap or the size of the edit region changed. */
|
||||
bool m_pixmapIsDirty;
|
||||
|
||||
int m_currentPointIndex;
|
||||
point_types m_currentPointType;
|
||||
double m_grabOffsetX;
|
||||
double m_grabOffsetY;
|
||||
/** selected point before it was modified by dragging (at the time of the mouse press) */
|
||||
BPoint m_grabPOriginal;
|
||||
/** point with the index currentPointIndex + 1 at the time of the mouse press */
|
||||
BPoint m_grabPNext;
|
||||
/** point with the index currentPointIndex - 1 at the time of the mouse press */
|
||||
BPoint m_grabPPrevious;
|
||||
|
||||
/** @brief Finds the point nearest to @param p and returns it's index.
|
||||
* @param sel Is filled with the type of the closest point (h1, p, h2)
|
||||
*
|
||||
* If no point is near enough -1 is returned. */
|
||||
int nearestPointInRange(const QPointF &p, int wWidth, int wHeight, point_types *sel);
|
||||
|
||||
signals:
|
||||
void modified();
|
||||
void currentPoint(const BPoint &p);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,215 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "beziersplinewidget.h"
|
||||
#include "colortools.h"
|
||||
#include "dragvalue.h"
|
||||
#include "kdenlivesettings.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <KIcon>
|
||||
#include <KLocale>
|
||||
|
||||
|
||||
BezierSplineWidget::BezierSplineWidget(const QString& spline, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_mode(ModeRGB),
|
||||
m_showPixmap(true)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->addWidget(&m_edit);
|
||||
QWidget *widget = new QWidget(this);
|
||||
m_ui.setupUi(widget);
|
||||
layout->addWidget(widget);
|
||||
|
||||
m_ui.buttonLinkHandles->setIcon(KIcon("insert-link"));
|
||||
m_ui.buttonZoomIn->setIcon(KIcon("zoom-in"));
|
||||
m_ui.buttonZoomOut->setIcon(KIcon("zoom-out"));
|
||||
m_ui.buttonGridChange->setIcon(KIcon("view-grid"));
|
||||
m_ui.buttonShowPixmap->setIcon(QIcon(QPixmap::fromImage(ColorTools::rgbCurvePlane(QSize(16, 16), ColorTools::COL_Luma, 0.8))));
|
||||
m_ui.buttonResetSpline->setIcon(KIcon("view-refresh"));
|
||||
m_ui.buttonShowAllHandles->setIcon(KIcon("draw-bezier-curves"));
|
||||
m_ui.widgetPoint->setEnabled(false);
|
||||
|
||||
m_pX = new DragValue(i18n("In"), 0, 3, 0, 1, -1, QString(), false, this);
|
||||
m_pX->setStep(0.001);
|
||||
m_pY = new DragValue(i18n("Out"), 0, 3, 0, 1, -1, QString(), false, this);
|
||||
m_pY->setStep(0.001);
|
||||
m_h1X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, this);
|
||||
m_h1X->setStep(0.001);
|
||||
m_h1Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, this);
|
||||
m_h1Y->setStep(0.001);
|
||||
m_h2X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, this);
|
||||
m_h2X->setStep(0.001);
|
||||
m_h2Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, this);
|
||||
m_h2Y->setStep(0.001);
|
||||
|
||||
m_ui.layoutP->addWidget(m_pX);
|
||||
m_ui.layoutP->addWidget(m_pY);
|
||||
m_ui.layoutH1->addWidget(new QLabel(i18n("Handle 1:")));
|
||||
m_ui.layoutH1->addWidget(m_h1X);
|
||||
m_ui.layoutH1->addWidget(m_h1Y);
|
||||
m_ui.layoutH2->addWidget(new QLabel(i18n("Handle 2:")));
|
||||
m_ui.layoutH2->addWidget(m_h2X);
|
||||
m_ui.layoutH2->addWidget(m_h2Y);
|
||||
|
||||
CubicBezierSpline s;
|
||||
s.fromString(spline);
|
||||
m_edit.setSpline(s);
|
||||
|
||||
connect(&m_edit, SIGNAL(modified()), this, SIGNAL(modified()));
|
||||
connect(&m_edit, SIGNAL(currentPoint(BPoint)), this, SLOT(slotUpdatePointEntries(BPoint)));
|
||||
|
||||
connect(m_pX, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointP(double,bool)));
|
||||
connect(m_pY, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointP(double,bool)));
|
||||
connect(m_h1X, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH1(double,bool)));
|
||||
connect(m_h1Y, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH1(double,bool)));
|
||||
connect(m_h2X, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH2(double,bool)));
|
||||
connect(m_h2Y, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH2(double,bool)));
|
||||
|
||||
connect(m_ui.buttonLinkHandles, SIGNAL(toggled(bool)), this, SLOT(slotSetHandlesLinked(bool)));
|
||||
connect(m_ui.buttonZoomIn, SIGNAL(clicked()), &m_edit, SLOT(slotZoomIn()));
|
||||
connect(m_ui.buttonZoomOut, SIGNAL(clicked()), &m_edit, SLOT(slotZoomOut()));
|
||||
connect(m_ui.buttonGridChange, SIGNAL(clicked()), this, SLOT(slotGridChange()));
|
||||
connect(m_ui.buttonShowPixmap, SIGNAL(toggled(bool)), this, SLOT(slotShowPixmap(bool)));
|
||||
connect(m_ui.buttonResetSpline, SIGNAL(clicked()), this, SLOT(slotResetSpline()));
|
||||
connect(m_ui.buttonShowAllHandles, SIGNAL(toggled(bool)), this, SLOT(slotShowAllHandles(bool)));
|
||||
|
||||
m_edit.setGridLines(KdenliveSettings::bezier_gridlines());
|
||||
m_ui.buttonShowPixmap->setChecked(KdenliveSettings::bezier_showpixmap());
|
||||
slotShowPixmap(m_ui.buttonShowPixmap->isChecked());
|
||||
m_ui.buttonShowAllHandles->setChecked(KdenliveSettings::bezier_showallhandles());
|
||||
}
|
||||
|
||||
QString BezierSplineWidget::spline() const
|
||||
{
|
||||
return m_edit.spline().toString();
|
||||
}
|
||||
|
||||
void BezierSplineWidget::setMode(BezierSplineWidget::CurveModes mode)
|
||||
{
|
||||
if (m_mode != mode) {
|
||||
m_mode = mode;
|
||||
if (m_showPixmap)
|
||||
slotShowPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotGridChange()
|
||||
{
|
||||
m_edit.setGridLines((m_edit.gridLines() + 1) % 9);
|
||||
KdenliveSettings::setBezier_gridlines(m_edit.gridLines());
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotShowPixmap(bool show)
|
||||
{
|
||||
if (m_showPixmap != show) {
|
||||
m_showPixmap = show;
|
||||
KdenliveSettings::setBezier_showpixmap(show);
|
||||
if (show && (int)m_mode < 6)
|
||||
m_edit.setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(m_edit.size(), (ColorTools::ColorsRGB)((int)m_mode), 1, palette().background().color().rgb())));
|
||||
else if (show && m_mode == ModeHue)
|
||||
m_edit.setPixmap(QPixmap::fromImage(ColorTools::hsvCurvePlane(m_edit.size(), QColor::fromHsv(200, 200, 200), ColorTools::COM_H, ColorTools::COM_H)));
|
||||
else
|
||||
m_edit.setPixmap(QPixmap());
|
||||
}
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotUpdatePointEntries(const BPoint &p)
|
||||
{
|
||||
blockSignals(true);
|
||||
if (p == BPoint()) {
|
||||
m_ui.widgetPoint->setEnabled(false);
|
||||
} else {
|
||||
m_ui.widgetPoint->setEnabled(true);
|
||||
m_pX->blockSignals(true);
|
||||
m_pY->blockSignals(true);
|
||||
m_h1X->blockSignals(true);
|
||||
m_h1Y->blockSignals(true);
|
||||
m_h2X->blockSignals(true);
|
||||
m_h2Y->blockSignals(true);
|
||||
m_pX->setValue(p.p.x());
|
||||
m_pY->setValue(p.p.y());
|
||||
m_h1X->setValue(p.h1.x());
|
||||
m_h1Y->setValue(p.h1.y());
|
||||
m_h2X->setValue(p.h2.x());
|
||||
m_h2Y->setValue(p.h2.y());
|
||||
m_pX->blockSignals(false);
|
||||
m_pY->blockSignals(false);
|
||||
m_h1X->blockSignals(false);
|
||||
m_h1Y->blockSignals(false);
|
||||
m_h2X->blockSignals(false);
|
||||
m_h2Y->blockSignals(false);
|
||||
m_ui.buttonLinkHandles->setChecked(p.handlesLinked);
|
||||
}
|
||||
blockSignals(false);
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotUpdatePointP(double value, bool final)
|
||||
{
|
||||
Q_UNUSED(value)
|
||||
|
||||
BPoint p = m_edit.getCurrentPoint();
|
||||
|
||||
p.setP(QPointF(m_pX->value(), m_pY->value()));
|
||||
|
||||
m_edit.updateCurrentPoint(p, final);
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotUpdatePointH1(double value, bool final)
|
||||
{
|
||||
Q_UNUSED(value)
|
||||
|
||||
BPoint p = m_edit.getCurrentPoint();
|
||||
|
||||
p.setH1(QPointF(m_h1X->value(), m_h1Y->value()));
|
||||
|
||||
m_edit.updateCurrentPoint(p, final);
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotUpdatePointH2(double value, bool final)
|
||||
{
|
||||
Q_UNUSED(value)
|
||||
|
||||
BPoint p = m_edit.getCurrentPoint();
|
||||
|
||||
p.setH2(QPointF(m_h2X->value(), m_h2Y->value()));
|
||||
|
||||
m_edit.updateCurrentPoint(p, final);
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotSetHandlesLinked(bool linked)
|
||||
{
|
||||
BPoint p = m_edit.getCurrentPoint();
|
||||
p.handlesLinked = linked;
|
||||
m_edit.updateCurrentPoint(p);
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotResetSpline()
|
||||
{
|
||||
m_edit.setSpline(CubicBezierSpline());
|
||||
}
|
||||
|
||||
void BezierSplineWidget::slotShowAllHandles(bool show)
|
||||
{
|
||||
m_edit.setShowAllHandles(show);
|
||||
KdenliveSettings::setBezier_showallhandles(show);
|
||||
}
|
||||
|
||||
#include "beziersplinewidget.moc"
|
||||
@@ -1,92 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef BEZIERSPLINEWIDGET_H
|
||||
#define BEZIERSPLINEWIDGET_H
|
||||
|
||||
#include "cubicbezierspline.h"
|
||||
#include "beziersplineeditor.h"
|
||||
#include "ui_bezierspline_ui.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class DragValue;
|
||||
|
||||
class BezierSplineWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** @brief Sets up the UI and sets the spline to @param spline. */
|
||||
explicit BezierSplineWidget(const QString &spline, QWidget* parent = 0);
|
||||
|
||||
/** @brief Returns the current spline. */
|
||||
QString spline() const;
|
||||
|
||||
/** The curvemodes refer to the usage of the spline.
|
||||
* As this widget is currently only used for frei0r.curves the modes are the channels this filter accepts. */
|
||||
enum CurveModes { ModeRed, ModeGreen, ModeBlue, ModeAlpha, ModeLuma, ModeRGB, ModeHue, ModeSaturation };
|
||||
|
||||
/** @brief Sets the mode to @param mode and updates the editors background pixmap if necessary. */
|
||||
void setMode(CurveModes mode);
|
||||
|
||||
private slots:
|
||||
/** @brief Sets the spinboxes for modifing the selected point to @param p. */
|
||||
void slotUpdatePointEntries(const BPoint &p);
|
||||
|
||||
/** @brief Updates the spline if the current point's p was modified using the spinboxes.
|
||||
* @param value (optional) not used, neccessary to be able to connect to DragValue's valueChanged.
|
||||
* @param final (default = true) emit signal modified? */
|
||||
void slotUpdatePointP(double value = 1, bool final = true);
|
||||
/** @brief Updates the spline if the current point's h1 was modified using the spinboxes.
|
||||
* @param value (optional) not used, neccessary to be able to connect to DragValue's valueChanged.
|
||||
* @param final (default = true) emit signal modified? */
|
||||
void slotUpdatePointH1(double value = 1, bool final = true);
|
||||
/** @brief Updates the spline if the current point's h2 was modified using the spinboxes.
|
||||
* @param value (optional) not used, neccessary to be able to connect to DragValue's valueChanged.
|
||||
* @param final (default = true) emit signal modified? */
|
||||
void slotUpdatePointH2(double value = 1, bool final = true);
|
||||
|
||||
/** @brief Increases the number of lines in the editor's grid. If there are already 8 lines the number is set to 0. */
|
||||
void slotGridChange();
|
||||
/** @brief Turns showing the background pixmap in the editor on/off. */
|
||||
void slotShowPixmap(bool show = true);
|
||||
/** @brief Resets the current spline. */
|
||||
void slotResetSpline();
|
||||
/** @brief Linkes the handles. This will always make them stay in one line through p. */
|
||||
void slotSetHandlesLinked(bool linked);
|
||||
|
||||
void slotShowAllHandles(bool show);
|
||||
|
||||
private:
|
||||
Ui::BezierSpline_UI m_ui;
|
||||
DragValue *m_pX;
|
||||
DragValue *m_pY;
|
||||
DragValue *m_h1X;
|
||||
DragValue *m_h1Y;
|
||||
DragValue *m_h2X;
|
||||
DragValue *m_h2Y;
|
||||
BezierSplineEditor m_edit;
|
||||
CurveModes m_mode;
|
||||
bool m_showPixmap;
|
||||
|
||||
signals:
|
||||
void modified();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,99 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "bpoint.h"
|
||||
|
||||
|
||||
BPoint::BPoint() :
|
||||
h1(QPointF(-1, -1)),
|
||||
p(QPointF(-1, -1)),
|
||||
h2(QPointF(-1, -1)),
|
||||
handlesLinked(true)
|
||||
{
|
||||
}
|
||||
|
||||
BPoint::BPoint(const QPointF &handle1, const QPointF &point, const QPointF &handle2) :
|
||||
h1(handle1),
|
||||
p(point),
|
||||
h2(handle2)
|
||||
{
|
||||
autoSetLinked();
|
||||
}
|
||||
|
||||
QPointF &BPoint::operator[](int i)
|
||||
{
|
||||
return i == 0 ? h1 : (i == 1 ? p : h2);
|
||||
}
|
||||
|
||||
const QPointF &BPoint::operator[](int i) const
|
||||
{
|
||||
return i == 0 ? h1 : (i == 1 ? p : h2);
|
||||
}
|
||||
|
||||
bool BPoint::operator==(const BPoint& point) const
|
||||
{
|
||||
return point.h1 == h1 &&
|
||||
point.p == p &&
|
||||
point.h2 == h2;
|
||||
}
|
||||
|
||||
void BPoint::setP(const QPointF &point, bool updateHandles)
|
||||
{
|
||||
QPointF offset = point - p;
|
||||
p = point;
|
||||
if (updateHandles) {
|
||||
h1 += offset;
|
||||
h2 += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void BPoint::setH1(const QPointF &handle1)
|
||||
{
|
||||
h1 = handle1;
|
||||
if (handlesLinked) {
|
||||
qreal angle = QLineF(h1, p).angle();
|
||||
QLineF l = QLineF(p, h2);
|
||||
l.setAngle(angle);
|
||||
h2 = l.p2();
|
||||
}
|
||||
}
|
||||
|
||||
void BPoint::setH2(const QPointF &handle2)
|
||||
{
|
||||
h2 = handle2;
|
||||
if (handlesLinked) {
|
||||
qreal angle = QLineF(h2, p).angle();
|
||||
QLineF l = QLineF(p, h1);
|
||||
l.setAngle(angle);
|
||||
h1 = l.p2();
|
||||
}
|
||||
}
|
||||
|
||||
void BPoint::keepInRange(qreal xMin, qreal xMax)
|
||||
{
|
||||
Q_UNUSED(xMin)
|
||||
Q_UNUSED(xMax)
|
||||
}
|
||||
|
||||
void BPoint::autoSetLinked()
|
||||
{
|
||||
// sometimes the angle is returned as 360°
|
||||
// due to rounding problems the angle is sometimes not quite 0
|
||||
qreal angle = QLineF(h1, p).angleTo(QLineF(p, h2));
|
||||
handlesLinked = angle < 1e-3 || qRound(angle) == 360;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef BPOINT_H
|
||||
#define BPOINT_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
/**
|
||||
* @brief Represents a point in a cubic Bézier spline.
|
||||
*/
|
||||
|
||||
class BPoint
|
||||
{
|
||||
public:
|
||||
/** @brief Sets the point to -1, -1 to mark it as unusable (until point + handles have proper values) */
|
||||
BPoint();
|
||||
/** @brief Sets up according to the params. Linking detecting is done using autoSetLinked(). */
|
||||
BPoint(const QPointF &handle1, const QPointF &point, const QPointF &handle2);
|
||||
|
||||
/** @brief Returns h1 if i = 0, p if i = 1, h2 if i = 2. */
|
||||
QPointF &operator[](int i);
|
||||
/** @brief Returns h1 if i = 0, p if i = 1, h2 if i = 2. */
|
||||
const QPointF &operator[](int i) const;
|
||||
bool operator==(const BPoint &point) const;
|
||||
|
||||
/** @brief Sets p to @param point.
|
||||
* @param updateHandles (default = true) Whether to make sure the handles keep their position relative to p. */
|
||||
void setP(const QPointF &point, bool updateHandles = true);
|
||||
|
||||
/** @brief Sets h1 to @param handle1.
|
||||
*
|
||||
* If handlesLinked is true h2 is updated. */
|
||||
void setH1(const QPointF &handle1);
|
||||
|
||||
/** @brief Sets h2 to @param handle2.
|
||||
*
|
||||
* If handlesLinked is true h1 is updated. */
|
||||
void setH2(const QPointF &handle2);
|
||||
void keepInRange(qreal xMin, qreal xMax);
|
||||
|
||||
/** @brief Sets handlesLinked to true if the handles are in a linked state (line through h1, p, h2) otherwise to false. */
|
||||
void autoSetLinked();
|
||||
|
||||
/** handle 1 */
|
||||
QPointF h1;
|
||||
/** point */
|
||||
QPointF p;
|
||||
/** handle 2 */
|
||||
QPointF h2;
|
||||
|
||||
/** handles are linked to achieve a natural locking spline => PH1 = -r*PH2 ; a line can be drawn through h1, p, h2 */
|
||||
bool handlesLinked;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,152 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "cubicbezierspline.h"
|
||||
#include <KDebug>
|
||||
|
||||
/** @brief For sorting a Bezier spline. Whether a is before b. */
|
||||
static bool pointLessThan(const BPoint &a, const BPoint &b)
|
||||
{
|
||||
return a.p.x() < b.p.x();
|
||||
}
|
||||
|
||||
CubicBezierSpline::CubicBezierSpline(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_points.append(BPoint(QPointF(0, 0), QPointF(0, 0), QPointF(.1, .1)));
|
||||
m_points.append(BPoint(QPointF(.9, .9), QPointF(1, 1), QPointF(1, 1)));
|
||||
}
|
||||
|
||||
CubicBezierSpline::CubicBezierSpline(const CubicBezierSpline& spline, QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_points = spline.m_points;
|
||||
}
|
||||
|
||||
CubicBezierSpline& CubicBezierSpline::operator=(const CubicBezierSpline& spline)
|
||||
{
|
||||
m_points = spline.m_points;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CubicBezierSpline::fromString(const QString& spline)
|
||||
{
|
||||
m_points.clear();
|
||||
|
||||
const QStringList bpoints = spline.split(QLatin1Char('|'));
|
||||
foreach(const QString &bpoint, bpoints) {
|
||||
const QStringList points = bpoint.split(QLatin1Char('#'));
|
||||
QList <QPointF> values;
|
||||
foreach(const QString &point, points) {
|
||||
QStringList xy = point.split(QLatin1Char(';'));
|
||||
if (xy.count() == 2)
|
||||
values.append(QPointF(xy.at(0).toDouble(), xy.at(1).toDouble()));
|
||||
}
|
||||
if (values.count() == 3) {
|
||||
m_points.append(BPoint(values.at(0), values.at(1), values.at(2)));
|
||||
}
|
||||
}
|
||||
|
||||
keepSorted();
|
||||
validatePoints();
|
||||
}
|
||||
|
||||
QString CubicBezierSpline::toString() const
|
||||
{
|
||||
QStringList spline;
|
||||
QLocale locale;
|
||||
foreach(const BPoint &p, m_points) {
|
||||
spline << QString("%1;%2#%3;%4#%5;%6").arg(locale.toString(p.h1.x())).arg(locale.toString(p.h1.y()))
|
||||
.arg(locale.toString(p.p.x())).arg(locale.toString(p.p.y()))
|
||||
.arg(locale.toString(p.h2.x())).arg(locale.toString(p.h2.y()));
|
||||
}
|
||||
return spline.join("|");
|
||||
}
|
||||
|
||||
int CubicBezierSpline::setPoint(int ix, const BPoint& point)
|
||||
{
|
||||
m_points[ix] = point;
|
||||
keepSorted();
|
||||
validatePoints();
|
||||
return indexOf(point); // in case it changed
|
||||
}
|
||||
|
||||
QList <BPoint> CubicBezierSpline::points() const
|
||||
{
|
||||
return m_points;
|
||||
}
|
||||
|
||||
void CubicBezierSpline::removePoint(int ix)
|
||||
{
|
||||
m_points.removeAt(ix);
|
||||
}
|
||||
|
||||
int CubicBezierSpline::addPoint(const BPoint& point)
|
||||
{
|
||||
m_points.append(point);
|
||||
keepSorted();
|
||||
validatePoints();
|
||||
return indexOf(point);
|
||||
}
|
||||
|
||||
BPoint CubicBezierSpline::getPoint(int ix, int normalisedWidth, int normalisedHeight, bool invertHeight)
|
||||
{
|
||||
BPoint p = m_points.at(ix);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
p[i].rx() *= normalisedWidth;
|
||||
p[i].ry() *= normalisedHeight;
|
||||
if (invertHeight)
|
||||
p[i].ry() = normalisedHeight - p[i].y();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void CubicBezierSpline::validatePoints()
|
||||
{
|
||||
BPoint p1, p2;
|
||||
for (int i = 0; i < m_points.count() - 1; ++i) {
|
||||
p1 = m_points.at(i);
|
||||
p2 = m_points.at(i+1);
|
||||
p1.h2.setX(qBound(p1.p.x(), p1.h2.x(), p2.p.x()));
|
||||
p2.h1.setX(qBound(p1.p.x(), p2.h1.x(), p2.p.x()));
|
||||
m_points[i] = p1;
|
||||
m_points[i+1] = p2;
|
||||
}
|
||||
}
|
||||
|
||||
void CubicBezierSpline::keepSorted()
|
||||
{
|
||||
qSort(m_points.begin(), m_points.end(), pointLessThan);
|
||||
}
|
||||
|
||||
int CubicBezierSpline::indexOf(const BPoint& p)
|
||||
{
|
||||
if (m_points.indexOf(p) == -1) {
|
||||
// point changed during validation process
|
||||
for (int i = 0; i < m_points.count(); ++i) {
|
||||
// this condition should be sufficient, too
|
||||
if (m_points.at(i).p == p.p)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
return m_points.indexOf(p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include "cubicbezierspline.moc"
|
||||
@@ -1,79 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* This file is part of Kdenlive (www.kdenlive.org). *
|
||||
* *
|
||||
* Kdenlive is free software: you can 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. *
|
||||
* *
|
||||
* Kdenlive is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef CUBICBEZIERSPLINE_H
|
||||
#define CUBICBEZIERSPLINE_H
|
||||
|
||||
#include "bpoint.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
|
||||
class CubicBezierSpline : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CubicBezierSpline(QObject* parent = 0);
|
||||
CubicBezierSpline(const CubicBezierSpline &spline, QObject* parent = 0);
|
||||
CubicBezierSpline& operator=(const CubicBezierSpline &spline);
|
||||
|
||||
/** @brief Loads the points from the string @param spline.
|
||||
*
|
||||
* x, y values have to be separated with a ';'
|
||||
* handles and points with a '#'
|
||||
* and the nodes with a '|'
|
||||
* So that you get: h1x;h1y#px;py#h2x;h2y|h1x;h1y#... */
|
||||
void fromString(const QString &spline);
|
||||
/** @brief Returns the points stoed in a string.
|
||||
*
|
||||
* x, y values have are separated with a ';'
|
||||
* handles and points with a '#'
|
||||
* and the nodes with a '|'
|
||||
* So that you get: h1x;h1y#px;py#h2x;h2y|h1x;h1y#... */
|
||||
QString toString() const;
|
||||
|
||||
/** @brief Returns a list of the points defining the spline. */
|
||||
QList <BPoint> points() const;
|
||||
|
||||
/** @brief Sets the point at index @param ix to @param point and returns its index (it might have changed during validation). */
|
||||
int setPoint(int ix, const BPoint &point);
|
||||
/** @brief Adds @param point and returns its index. */
|
||||
int addPoint(const BPoint &point);
|
||||
/** @brief Removes the point at @param ix. */
|
||||
void removePoint(int ix);
|
||||
|
||||
/** @brief Returns the point at @param ix.
|
||||
* @param ix Index of the point
|
||||
* @param normalisedWidth (default = 1) Will be multiplied will all x values to change the range from 0-1 into another one
|
||||
* @param normalisedHeight (default = 1) Will be multiplied will all y values to change the range from 0-1 into another one
|
||||
* @param invertHeight (default = false) true => y = 0 is at the very top
|
||||
*/
|
||||
BPoint getPoint(int ix, int normalisedWidth = 1, int normalisedHeight = 1, bool invertHeight = false);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void validatePoints();
|
||||
void keepSorted();
|
||||
int indexOf(const BPoint &p);
|
||||
|
||||
QList <BPoint> m_points;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,136 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "choosecolorwidget.h"
|
||||
#include "colorpickerwidget.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include <KColorButton>
|
||||
#include <KLocalizedString>
|
||||
#include <kdeversion.h>
|
||||
#include <KDebug>
|
||||
|
||||
static QColor stringToColor(QString strColor)
|
||||
{
|
||||
bool ok = false;
|
||||
QColor color("black");
|
||||
int intval = 0;
|
||||
if (strColor.startsWith("0x")) {
|
||||
if (strColor.length() == 10) {
|
||||
// 0xRRGGBBAA
|
||||
intval = strColor.toUInt(&ok, 16);
|
||||
color.setRgb( ( intval >> 24 ) & 0xff, // r
|
||||
( intval >> 16 ) & 0xff, // g
|
||||
( intval >> 8 ) & 0xff, // b
|
||||
( intval ) & 0xff ); // a
|
||||
} else {
|
||||
// 0xRRGGBB, 0xRGB
|
||||
color.setNamedColor(strColor.replace(0, 2, "#"));
|
||||
}
|
||||
} else {
|
||||
if (strColor.length() == 9) {
|
||||
// #AARRGGBB
|
||||
strColor = strColor.replace('#', "0x");
|
||||
intval = strColor.toUInt(&ok, 16);
|
||||
color.setRgb( ( intval >> 16 ) & 0xff, // r
|
||||
( intval >> 8 ) & 0xff, // g
|
||||
( intval ) & 0xff, // b
|
||||
( intval >> 24 ) & 0xff ); // a
|
||||
} else if (strColor.length() == 8) {
|
||||
// 0xRRGGBB
|
||||
strColor = strColor.replace('#', "0x");
|
||||
color.setNamedColor(strColor);
|
||||
} else {
|
||||
// #RRGGBB, #RGB
|
||||
color.setNamedColor(strColor);
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static QString colorToString(const QColor &color, bool alpha)
|
||||
{
|
||||
QString colorStr;
|
||||
QTextStream stream(&colorStr);
|
||||
stream << "0x";
|
||||
stream.setIntegerBase(16);
|
||||
stream.setFieldWidth(2);
|
||||
stream.setFieldAlignment(QTextStream::AlignRight);
|
||||
stream.setPadChar('0');
|
||||
stream << color.red() << color.green() << color.blue();
|
||||
if (alpha) {
|
||||
stream << color.alpha();
|
||||
} else {
|
||||
// MLT always wants 0xRRGGBBAA format
|
||||
stream << "ff";
|
||||
}
|
||||
return colorStr;
|
||||
}
|
||||
|
||||
ChooseColorWidget::ChooseColorWidget(const QString &text, const QString &color, bool alphaEnabled, QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
QLabel *label = new QLabel(text, this);
|
||||
|
||||
QWidget *rightSide = new QWidget(this);
|
||||
QHBoxLayout *rightSideLayout = new QHBoxLayout(rightSide);
|
||||
rightSideLayout->setContentsMargins(0, 0, 0, 0);
|
||||
rightSideLayout->setSpacing(0);
|
||||
|
||||
m_button = new KColorButton(stringToColor(color), rightSide);
|
||||
#if KDE_IS_VERSION(4,5,0)
|
||||
if (alphaEnabled) m_button->setAlphaChannelEnabled(alphaEnabled);
|
||||
#endif
|
||||
// m_button->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
ColorPickerWidget *picker = new ColorPickerWidget(rightSide);
|
||||
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(rightSide);
|
||||
rightSideLayout->addWidget(m_button);
|
||||
rightSideLayout->addWidget(picker, 0, Qt::AlignRight);
|
||||
|
||||
connect(picker, SIGNAL(colorPicked(QColor)), this, SLOT(setColor(QColor)));
|
||||
connect(picker, SIGNAL(displayMessage(QString,int)), this, SIGNAL(displayMessage(QString,int)));
|
||||
connect(picker, SIGNAL(disableCurrentFilter(bool)), this, SIGNAL(disableCurrentFilter(bool)));
|
||||
connect(m_button, SIGNAL(changed(QColor)), this, SIGNAL(modified()));
|
||||
}
|
||||
|
||||
QString ChooseColorWidget::getColor() const
|
||||
{
|
||||
bool alphaChannel = false;
|
||||
#if KDE_IS_VERSION(4,5,0)
|
||||
alphaChannel = m_button->isAlphaChannelEnabled();
|
||||
#endif
|
||||
return colorToString(m_button->color(), alphaChannel);
|
||||
}
|
||||
|
||||
void ChooseColorWidget::setColor(const QColor& color)
|
||||
{
|
||||
m_button->setColor(color);
|
||||
}
|
||||
|
||||
#include "choosecolorwidget.moc"
|
||||
@@ -1,62 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Till Theato (root@ttill.de) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef CHOOSECOLORWIDGET_H
|
||||
#define CHOOSECOLORWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class KColorButton;
|
||||
|
||||
/**
|
||||
* @class ChooseColorWidget
|
||||
* @brief Provides options to choose a color.
|
||||
* @author Till Theato
|
||||
*/
|
||||
|
||||
class ChooseColorWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/** @brief Sets up the widget.
|
||||
* @param text (optional) What the color will be used for
|
||||
* @param color (optional) initial color
|
||||
* @param alphaEnabled (optional) Should transparent colors be enabled */
|
||||
explicit ChooseColorWidget(const QString &text = QString(), const QString &color = "0xffffffff", bool alphaEnabled = false, QWidget* parent = 0);
|
||||
|
||||
/** @brief Gets the choosen color. */
|
||||
QString getColor() const;
|
||||
|
||||
private:
|
||||
KColorButton *m_button;
|
||||
|
||||
private slots:
|
||||
/** @brief Updates the different color choosing options to have all selected @param color. */
|
||||
void setColor(const QColor &color);
|
||||
|
||||
signals:
|
||||
/** @brief Emitted whenever a different color was choosen. */
|
||||
void modified();
|
||||
void displayMessage(const QString&, int);
|
||||
/** @brief When user wants to pick a color, it's better to disable filter so we get proper color values. */
|
||||
void disableCurrentFilter(bool);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,177 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
|
||||
* *
|
||||
* This program is free software; you can 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; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "clipdurationdialog.h"
|
||||
#include "clipitem.h"
|
||||
|
||||
#include <KDebug>
|
||||
#include <KMessageBox>
|
||||
#include <KGlobalSettings>
|
||||
|
||||
#include <QWheelEvent>
|
||||
|
||||
ClipDurationDialog::ClipDurationDialog(AbstractClipItem *clip, const Timecode &tc, const GenTime &min, const GenTime &max, QWidget * parent):
|
||||
QDialog(parent),
|
||||
m_clip(clip),
|
||||
m_min(min),
|
||||
m_max(max)
|
||||
{
|
||||
setFont(KGlobalSettings::toolBarFont());
|
||||
setupUi(this);
|
||||
|
||||
m_pos = new TimecodeDisplay(tc);
|
||||
m_cropStart = new TimecodeDisplay(tc);
|
||||
m_dur = new TimecodeDisplay(tc);
|
||||
m_cropEnd = new TimecodeDisplay(tc);
|
||||
|
||||
clip_position_box->addWidget(m_pos);
|
||||
crop_start_box->addWidget(m_cropStart);
|
||||
clip_duration_box->addWidget(m_dur);
|
||||
crop_end_box->addWidget(m_cropEnd);
|
||||
|
||||
bool allowCrop = true;
|
||||
if (clip->type() == AVWIDGET) {
|
||||
ClipItem *item = static_cast <ClipItem *>(clip);
|
||||
const int t = item->clipType();
|
||||
if (t == COLOR || t == IMAGE || t == TEXT)
|
||||
allowCrop = false;
|
||||
}
|
||||
|
||||
if (!allowCrop || clip->type() == TRANSITIONWIDGET) {
|
||||
m_cropStart->setHidden(true);
|
||||
crop_label->hide();
|
||||
m_cropEnd->setHidden(true),
|
||||
end_label->hide();
|
||||
}
|
||||
|
||||
m_crop = m_clip->cropStart();
|
||||
|
||||
m_pos->setValue(m_clip->startPos());
|
||||
m_dur->setValue(m_clip->cropDuration());
|
||||
m_cropStart->setValue(m_clip->cropStart());
|
||||
m_cropEnd->setValue(m_clip->maxDuration() - m_clip->cropDuration() - m_clip->cropStart());
|
||||
|
||||
connect(m_pos, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotCheckStart()));
|
||||
connect(m_dur, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotCheckDuration()));
|
||||
connect(m_cropStart, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotCheckCrop()));
|
||||
connect(m_cropEnd, SIGNAL(timeCodeEditingFinished()), this, SLOT(slotCheckEnd()));
|
||||
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
ClipDurationDialog::~ClipDurationDialog()
|
||||
{
|
||||
delete m_pos;
|
||||
delete m_dur;
|
||||
delete m_cropStart;
|
||||
delete m_cropEnd;
|
||||
}
|
||||
|
||||
void ClipDurationDialog::slotCheckStart()
|
||||
{
|
||||
GenTime start = m_pos->gentime();
|
||||
GenTime duration = m_dur->gentime();
|
||||
if (m_min != GenTime() && start < m_min)
|
||||
m_pos->setValue(m_min);
|
||||
else if (m_max != GenTime() && start + duration > m_max)
|
||||
m_pos->setValue(m_max - duration);
|
||||
}
|
||||
|
||||
void ClipDurationDialog::slotCheckDuration()
|
||||
{
|
||||
GenTime start = m_pos->gentime();
|
||||
GenTime duration = m_dur->gentime();
|
||||
GenTime cropStart = m_cropStart->gentime();
|
||||
GenTime maxDuration;
|
||||
|
||||
if (m_clip->maxDuration() == GenTime())
|
||||
maxDuration = m_max;
|
||||
else
|
||||
maxDuration = m_max == GenTime() ? start + m_clip->maxDuration() - cropStart : qMin(m_max, start + m_clip->maxDuration() - cropStart);
|
||||
|
||||
if (maxDuration != GenTime() && start + duration > maxDuration) {
|
||||
m_dur->blockSignals(true);
|
||||
m_dur->setValue(maxDuration - start);
|
||||
m_dur->blockSignals(false);
|
||||
}
|
||||
|
||||
m_cropEnd->blockSignals(true);
|
||||
m_cropEnd->setValue(m_clip->maxDuration() - m_dur->gentime() - cropStart);
|
||||
m_cropEnd->blockSignals(false);
|
||||
}
|
||||
|
||||
void ClipDurationDialog::slotCheckCrop()
|
||||
{
|
||||
GenTime duration = m_dur->gentime();
|
||||
GenTime cropStart = m_cropStart->gentime();
|
||||
GenTime maxDuration = m_clip->maxDuration();
|
||||
|
||||
GenTime diff = cropStart - m_crop;
|
||||
if ((diff > GenTime() && diff < duration) || diff < GenTime()) {
|
||||
duration -= diff;
|
||||
} else {
|
||||
m_cropStart->setValue(m_crop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxDuration != GenTime() && cropStart + duration > maxDuration) {
|
||||
m_cropStart->setValue(m_crop);
|
||||
} else {
|
||||
m_crop = cropStart;
|
||||
m_dur->blockSignals(true);
|
||||
m_dur->setValue(duration);
|
||||
m_dur->blockSignals(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ClipDurationDialog::slotCheckEnd()
|
||||
{
|
||||
GenTime cropStart = m_cropStart->gentime();
|
||||
GenTime cropEnd = m_cropEnd->gentime();
|
||||
GenTime duration = m_clip->maxDuration() - cropEnd - cropStart;
|
||||
|
||||
if (duration >= GenTime()) {
|
||||
m_dur->setValue(duration);
|
||||
slotCheckDuration();
|
||||
} else {
|
||||
m_cropEnd->blockSignals(true);
|
||||
m_cropEnd->setValue(m_clip->maxDuration() - m_dur->gentime() - cropStart);
|
||||
m_cropEnd->blockSignals(false);
|
||||
}
|
||||
}
|
||||
|
||||
GenTime ClipDurationDialog::startPos() const
|
||||
{
|
||||
return m_pos->gentime();
|
||||
}
|
||||
|
||||
GenTime ClipDurationDialog::cropStart() const
|
||||
{
|
||||
return m_cropStart->gentime();
|
||||
}
|
||||
|
||||
GenTime ClipDurationDialog::duration() const
|
||||
{
|
||||
return m_dur->gentime();
|
||||
}
|
||||
|
||||
#include "clipdurationdialog.moc"
|
||||
|
||||
|
||||