@@ -1336,13 +1336,50 @@ def actionAddMarker_trigger(self, event):
1336
1336
marker .data = {"position" : position , "icon" : "blue.png" }
1337
1337
marker .save ()
1338
1338
1339
- def actionPreviousMarker_trigger (self , event ):
1340
- log .info ("actionPreviousMarker_trigger" )
1341
1339
1342
- # Calculate current position (in seconds)
1343
- fps = get_app ().project .get ("fps" )
1344
- fps_float = float (fps ["num" ]) / float (fps ["den" ])
1345
- current_position = (self .preview_thread .current_frame - 1 ) / fps_float
1340
+ def findAllMarkerPositions (self ):
1341
+ """Build and return a list of all seekable locations for the currently-selected timeline elements"""
1342
+
1343
+ def getTimelineObjectPositions (obj ):
1344
+ """ Add boundaries & all keyframes of a timeline object (clip, transition...) to all_marker_positions """
1345
+ positions = []
1346
+
1347
+ fps = get_app ().project .get ("fps" )
1348
+ fps_float = float (fps ["num" ]) / float (fps ["den" ])
1349
+
1350
+ clip_start_time = obj .data ["position" ]
1351
+ clip_orig_time = clip_start_time - obj .data ["start" ]
1352
+ clip_stop_time = clip_orig_time + obj .data ["end" ]
1353
+
1354
+ # add clip boundaries
1355
+ positions .append (clip_start_time )
1356
+ positions .append (clip_stop_time )
1357
+
1358
+ # add all keyframes
1359
+ for property in obj .data :
1360
+ try :
1361
+ for point in obj .data [property ]["Points" ] :
1362
+ keyframe_time = (point ["co" ]["X" ]- 1 )/ fps_float - obj .data ["start" ] + obj .data ["position" ]
1363
+ if keyframe_time > clip_start_time and keyframe_time < clip_stop_time :
1364
+ positions .append (keyframe_time )
1365
+ except (TypeError , KeyError ):
1366
+ pass
1367
+
1368
+
1369
+ # Add all Effect keyframes
1370
+ if "effects" in obj .data :
1371
+ for effect_data in obj .data ["effects" ]:
1372
+ for property in effect_data :
1373
+ try :
1374
+ for point in effect_data [property ]["Points" ]:
1375
+ keyframe_time = (point ["co" ]["X" ]- 1 )/ fps_float + clip_orig_time
1376
+ if keyframe_time > clip_start_time and keyframe_time < clip_stop_time :
1377
+ positions .append (keyframe_time )
1378
+ except (TypeError , KeyError ):
1379
+ pass
1380
+
1381
+ return positions
1382
+
1346
1383
all_marker_positions = []
1347
1384
1348
1385
# Get list of marker and important positions (like selected clip bounds)
@@ -1354,16 +1391,28 @@ def actionPreviousMarker_trigger(self, event):
1354
1391
# Get selected object
1355
1392
selected_clip = Clip .get (id = clip_id )
1356
1393
if selected_clip :
1357
- all_marker_positions .append (selected_clip .data ["position" ])
1358
- all_marker_positions .append (selected_clip .data ["position" ] + (selected_clip .data ["end" ] - selected_clip .data ["start" ]))
1394
+ all_marker_positions .extend (getTimelineObjectPositions (selected_clip ))
1359
1395
1360
1396
# Loop through selected transitions (and add key positions)
1361
1397
for tran_id in self .selected_transitions :
1362
1398
# Get selected object
1363
1399
selected_tran = Transition .get (id = tran_id )
1364
1400
if selected_tran :
1365
- all_marker_positions .append (selected_tran .data ["position" ])
1366
- all_marker_positions .append (selected_tran .data ["position" ] + (selected_tran .data ["end" ] - selected_tran .data ["start" ]))
1401
+ all_marker_positions .extend (getTimelineObjectPositions (selected_tran ))
1402
+
1403
+ # remove duplicates
1404
+ all_marker_positions = list (set (all_marker_positions ))
1405
+
1406
+ return all_marker_positions
1407
+
1408
+ def actionPreviousMarker_trigger (self , event ):
1409
+ log .info ("actionPreviousMarker_trigger" )
1410
+
1411
+ # Calculate current position (in seconds)
1412
+ fps = get_app ().project .get ("fps" )
1413
+ fps_float = float (fps ["num" ]) / float (fps ["den" ])
1414
+ current_position = (self .preview_thread .current_frame - 1 ) / fps_float
1415
+ all_marker_positions = self .findAllMarkerPositions ()
1367
1416
1368
1417
# Loop through all markers, and find the closest one to the left
1369
1418
closest_position = None
@@ -1395,27 +1444,7 @@ def actionNextMarker_trigger(self, event):
1395
1444
fps = get_app ().project .get ("fps" )
1396
1445
fps_float = float (fps ["num" ]) / float (fps ["den" ])
1397
1446
current_position = (self .preview_thread .current_frame - 1 ) / fps_float
1398
- all_marker_positions = []
1399
-
1400
- # Get list of marker and important positions (like selected clip bounds)
1401
- for marker in Marker .filter ():
1402
- all_marker_positions .append (marker .data ["position" ])
1403
-
1404
- # Loop through selected clips (and add key positions)
1405
- for clip_id in self .selected_clips :
1406
- # Get selected object
1407
- selected_clip = Clip .get (id = clip_id )
1408
- if selected_clip :
1409
- all_marker_positions .append (selected_clip .data ["position" ])
1410
- all_marker_positions .append (selected_clip .data ["position" ] + (selected_clip .data ["end" ] - selected_clip .data ["start" ]))
1411
-
1412
- # Loop through selected transitions (and add key positions)
1413
- for tran_id in self .selected_transitions :
1414
- # Get selected object
1415
- selected_tran = Transition .get (id = tran_id )
1416
- if selected_tran :
1417
- all_marker_positions .append (selected_tran .data ["position" ])
1418
- all_marker_positions .append (selected_tran .data ["position" ] + (selected_tran .data ["end" ] - selected_tran .data ["start" ]))
1447
+ all_marker_positions = self .findAllMarkerPositions ()
1419
1448
1420
1449
# Loop through all markers, and find the closest one to the right
1421
1450
closest_position = None
@@ -2005,18 +2034,13 @@ def resize_contents(self):
2005
2034
2006
2035
def getDocks (self ):
2007
2036
""" Get a list of all dockable widgets """
2008
- return [self .dockFiles ,
2009
- self .dockTransitions ,
2010
- self .dockEffects ,
2011
- self .dockEmojis ,
2012
- self .dockVideo ,
2013
- self .dockProperties ,
2014
- self .dockTimeline ]
2037
+ return self .findChildren (QDockWidget )
2015
2038
2016
2039
def removeDocks (self ):
2017
2040
""" Remove all dockable widgets on main screen """
2018
2041
for dock in self .getDocks ():
2019
- self .removeDockWidget (dock )
2042
+ if self .dockWidgetArea (dock ) != Qt .NoDockWidgetArea :
2043
+ self .removeDockWidget (dock )
2020
2044
2021
2045
def addDocks (self , docks , area ):
2022
2046
""" Add all dockable widgets to the same dock area on the main screen """
@@ -2026,7 +2050,8 @@ def addDocks(self, docks, area):
2026
2050
def floatDocks (self , is_floating ):
2027
2051
""" Float or Un-Float all dockable widgets above main screen """
2028
2052
for dock in self .getDocks ():
2029
- dock .setFloating (is_floating )
2053
+ if self .dockWidgetArea (dock ) != Qt .NoDockWidgetArea :
2054
+ dock .setFloating (is_floating )
2030
2055
2031
2056
def showDocks (self , docks ):
2032
2057
""" Show all dockable widgets on the main screen """
@@ -2038,20 +2063,17 @@ def showDocks(self, docks):
2038
2063
def freezeDocks (self ):
2039
2064
""" Freeze all dockable widgets on the main screen (prevent them being closed, floated, or moved) """
2040
2065
for dock in self .getDocks ():
2041
- dock .setFeatures (QDockWidget .NoDockWidgetFeatures )
2066
+ if self .dockWidgetArea (dock ) != Qt .NoDockWidgetArea :
2067
+ dock .setFeatures (QDockWidget .NoDockWidgetFeatures )
2042
2068
2043
2069
def unFreezeDocks (self ):
2044
2070
""" Un-freeze all dockable widgets on the main screen (allow them to be closed, floated, or moved, as appropriate) """
2045
2071
for dock in self .getDocks ():
2046
- if dock is self .dockTimeline :
2047
- dock .setFeatures (QDockWidget .DockWidgetFloatable | QDockWidget .DockWidgetMovable )
2048
- else :
2049
- dock .setFeatures (QDockWidget .DockWidgetClosable | QDockWidget .DockWidgetFloatable | QDockWidget .DockWidgetMovable )
2050
-
2051
- def hideDocks (self ):
2052
- """ Hide all dockable widgets on the main screen """
2053
- for dock in self .getDocks ():
2054
- dock .hide ()
2072
+ if self .dockWidgetArea (dock ) != Qt .NoDockWidgetArea :
2073
+ if dock is self .dockTimeline :
2074
+ dock .setFeatures (QDockWidget .DockWidgetFloatable | QDockWidget .DockWidgetMovable )
2075
+ else :
2076
+ dock .setFeatures (QDockWidget .DockWidgetClosable | QDockWidget .DockWidgetFloatable | QDockWidget .DockWidgetMovable )
2055
2077
2056
2078
def actionSimple_View_trigger (self , event ):
2057
2079
""" Switch to the default / simple view """
@@ -2490,15 +2512,15 @@ def resizeEvent(self, event):
2490
2512
def showEvent (self , event ):
2491
2513
""" Have any child windows follow main-window state """
2492
2514
QMainWindow .showEvent (self , event )
2493
- for child in self .findChildren ( QDockWidget ):
2515
+ for child in self .getDocks ( ):
2494
2516
if child .isFloating () and child .isEnabled ():
2495
2517
child .raise_ ()
2496
2518
child .show ()
2497
2519
2498
2520
def hideEvent (self , event ):
2499
2521
""" Have any child windows hide with main window """
2500
2522
QMainWindow .hideEvent (self , event )
2501
- for child in self .findChildren ( QDockWidget ):
2523
+ for child in self .getDocks ( ):
2502
2524
if child .isFloating () and child .isVisible ():
2503
2525
child .hide ()
2504
2526
@@ -2558,34 +2580,21 @@ def InitCacheSettings(self):
2558
2580
self .cache_object = new_cache_object
2559
2581
2560
2582
def FrameExported (self , title_message , start_frame , end_frame , current_frame ):
2561
- """Connect to Unity launcher (for Linux )"""
2583
+ """Update progress in Unity Launcher (if connected )"""
2562
2584
try :
2563
- if sys .platform == "linux" and self .has_launcher :
2564
- if not self .unity_launchers :
2565
- # Get launcher only once
2566
- import gi
2567
- gi .require_version ('Unity' , '7.0' )
2568
- from gi .repository import Unity
2569
- self .unity_launchers .append (Unity .LauncherEntry .get_for_desktop_id ("openshot-qt.desktop" ))
2570
- self .unity_launchers .append (Unity .LauncherEntry .get_for_desktop_id ("appimagekit-openshot-qt.desktop" ))
2571
-
2572
- # Set progress and show progress bar
2573
- for launcher in self .unity_launchers :
2574
- launcher .set_property ("progress" , current_frame / (end_frame - start_frame ))
2575
- launcher .set_property ("progress_visible" , True )
2576
-
2585
+ # Set progress and show progress bar
2586
+ self .unity_launcher .set_property ("progress" , current_frame / (end_frame - start_frame ))
2587
+ self .unity_launcher .set_property ("progress_visible" , True )
2577
2588
except Exception :
2578
2589
# Just ignore
2579
- self . has_launcher = False
2590
+ pass
2580
2591
2581
2592
def ExportFinished (self , path ):
2582
- """Export has completed """
2593
+ """Show completion in Unity Launcher (if connected) """
2583
2594
try :
2584
- if sys .platform == "linux" and self .has_launcher :
2585
- for launcher in self .unity_launchers :
2586
- # Set progress on Unity launcher and hide progress bar
2587
- launcher .set_property ("progress" , 0.0 )
2588
- launcher .set_property ("progress_visible" , False )
2595
+ # Set progress on Unity launcher and hide progress bar
2596
+ self .unity_launcher .set_property ("progress" , 0.0 )
2597
+ self .unity_launcher .set_property ("progress_visible" , False )
2589
2598
except Exception :
2590
2599
pass
2591
2600
@@ -2843,11 +2852,20 @@ def __init__(self, mode=None):
2843
2852
self .tutorial_manager = TutorialManager (self )
2844
2853
2845
2854
# Connect to Unity DBus signal (if linux)
2846
- if sys .platform == "linux" :
2847
- self .unity_launchers = []
2848
- self .has_launcher = True
2849
- self .ExportFrame .connect (self .FrameExported )
2850
- self .ExportEnded .connect (self .ExportFinished )
2855
+ self .unity_launcher = None
2856
+ if "linux" in sys .platform :
2857
+ try :
2858
+ # Get connection to Unity Launcher
2859
+ import gi
2860
+ gi .require_version ('Unity' , '7.0' )
2861
+ from gi .repository import Unity
2862
+ self .unity_launcher = Unity .LauncherEntry .get_for_desktop_id (info .DESKTOP_ID )
2863
+ except Exception :
2864
+ # Guess we're not on Ubuntu
2865
+ pass
2866
+ else :
2867
+ self .ExportFrame .connect (self .FrameExported )
2868
+ self .ExportEnded .connect (self .ExportFinished )
2851
2869
2852
2870
# Save settings
2853
2871
s .save ()
0 commit comments