Skip to content

Commit

Permalink
Improved Tracks (simpler numbering, faster inserting, prevent deletio…
Browse files Browse the repository at this point in the history
…n of locked tracks) (OpenShot#2491)

* Improving track inserting, adding, and deleting, including a more dynamic numbering system, a simpler display system, and much less processing for most insert track operations. Track numbering is spaced out in increments of 1,000,000. Inserting does not need to move clips around, but rather find the mid point of the gap. This works for the first 30 or so inserts, and then when the gap is too small, we start renaming and moving items that are conflicting.

* Clean-up of some indention issues and removing some commented out code

* Prevent removal of 'locked' tracks. User must set track to 'unlocked' state before the delete option is enabled.

* Updating track/layer display in 'Properties' view and 'Add to Timeline' view. We now display labels if any found, and use the same display logic everywhere a track is displayed.
  • Loading branch information
jonoomph authored Dec 30, 2018
1 parent f6c74ef commit c0408c5
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 96 deletions.
1 change: 0 additions & 1 deletion src/classes/project_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ def _set(self, key, values=None, add=False, partial_update=False, remove=False):
# Add or Full Update
# For adds to list perform an insert to index or the end if not specified
if add and isinstance(parent, list):
# log.info("adding to list")
parent.append(values)

# Otherwise, set the given index
Expand Down
1 change: 0 additions & 1 deletion src/classes/ui_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ def init_ui(window):

# Loop through all actions
for action in window.findChildren(QAction):
# log.info('Initializing element: {}'.format(action))
init_element(window, action)
except:
log.info('Failed to initialize an element on {}'.format(window.objectName()))
Expand Down
3 changes: 0 additions & 3 deletions src/classes/updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,6 @@ def update_watchers(self):
# caused by actions.
def get_reverse_action(self, action):
""" Convert an UpdateAction into the opposite type (i.e. 'insert' becomes an 'delete') """

# log.info("Reversing action: {}, {}, {}, {}".format(action.type, action.key, action.values, action.partial_update))
reverse = UpdateAction(action.type, action.key, action.values, action.partial_update)
# On adds, setup remove
if action.type == "insert":
Expand All @@ -256,7 +254,6 @@ def get_reverse_action(self, action):
reverse.old_values = action.values
reverse.values = action.old_values

# log.info("Reversed values: {}, {}, {}, {}".format(reverse.type, reverse.key, reverse.values, reverse.partial_update))
return reverse

def undo(self):
Expand Down
20 changes: 10 additions & 10 deletions src/settings/_default.project
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,37 @@
"profile": "HD 720p 30 fps",
"layers": [
{
"id": "L0",
"id": "L1",
"label" : "",
"number": 0,
"number": 1000000,
"y": 0,
"lock": false
},
{
"id": "L1",
"id": "L2",
"label" : "",
"number": 1,
"number": 2000000,
"y": 0,
"lock": false
},
{
"id": "L2",
"id": "L3",
"label" : "",
"number": 2,
"number": 3000000,
"y": 0,
"lock": false
},
{
"id": "L3",
"id": "L4",
"label" : "",
"number": 3,
"number": 4000000,
"y": 0,
"lock": false
},
{
"id": "L4",
"id": "L5",
"label" : "",
"number": 4,
"number": 5000000,
"y": 0,
"lock": false
}
Expand Down
2 changes: 1 addition & 1 deletion src/timeline/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<div ng-repeat="layer in project.layers.slice().reverse()" id="track_static_{{layer.number}}" ng-right-click="ShowTrackMenu(layer.id)" class="track_name">
<div class="track_top">
<div tl-clip-menu class="track_menu" ng-mousedown="ShowTrackMenu(layer.id)"></div>
<span class="track_label">{{GetTrackName(layer.label, layer.number)}}</span><span ng-show="layer.lock" class="track_lock"></span>
<span class="track_label">{{GetTrackName(layer.label, project.layers.length - $index)}}</span><span ng-show="layer.lock" class="track_lock"></span>
</div>
</div>
<br>
Expand Down
13 changes: 8 additions & 5 deletions src/windows/add_to_timeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"""

import os, math
from operator import itemgetter
from random import shuffle, randint, uniform

from PyQt5.QtWidgets import *
Expand Down Expand Up @@ -481,12 +482,14 @@ def __init__(self, files=None, position=0.0):
self.txtFadeLength.valueChanged.connect(self.updateTotal)
self.txtTransitionLength.valueChanged.connect(self.updateTotal)

# Add all tracks to dropdown
tracks = Track.filter()
for track in reversed(tracks):
# Find display track number
all_tracks = get_app().project.get(["layers"])
display_count = len(all_tracks)
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
# Add to dropdown
track_name = track.data['label'] or _("Track %s") % track.data['number']
self.cmbTrack.addItem(track_name, track.data['number'])
track_name = track.get('label') or _("Track %s") % display_count
self.cmbTrack.addItem(track_name, track.get('number'))
display_count -= 1

# Add all fade options
self.cmbFade.addItem(_('None'), None)
Expand Down
157 changes: 92 additions & 65 deletions src/windows/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import platform
import shutil
import webbrowser
from operator import itemgetter
from uuid import uuid4
from copy import deepcopy
from time import sleep
Expand Down Expand Up @@ -911,7 +912,7 @@ def actionSaveFrame_trigger(self, event):
# Translate object
_ = get_app()._tr

# Prepare to use the status bar
# Prepare to use the status bar
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)

Expand All @@ -925,7 +926,6 @@ def actionSaveFrame_trigger(self, event):
recommended_path = get_app().project.get(["export_path"])

framePath = _("%s/Frame-%05d.png" % (recommended_path, self.preview_thread.current_frame))
#log.info("Saving frame to %" % framePath)

# Ask user to confirm or update framePath
framePath, file_type = QFileDialog.getSaveFileName(self, _("Save Frame..."), framePath, _("Image files (*.png)"))
Expand Down Expand Up @@ -960,21 +960,16 @@ def actionSaveFrame_trigger(self, event):
else:
framePathTime = QDateTime()

# Get and Save the frame (return is void, so we cannot check for success/fail here - must use file modification timestamp)
# Get and Save the frame (return is void, so we cannot check for success/fail here - must use file modification timestamp)
openshot.Timeline.GetFrame(self.timeline_sync.timeline,self.preview_thread.current_frame).Save(framePath, 1.0)

#log.info("orig framePathTime %s" % framePathTime.toString("yyMMdd hh:mm:ss.zzz") )
#log.info("new framePathTime %s" % QFileInfo(framePath).lastModified().toString("yyMMdd hh:mm:ss.zzz") )

# Show message to user
# Show message to user
if os.path.exists(framePath) and (QFileInfo(framePath).lastModified() > framePathTime):
#QMessageBox.information(self, _("Save Frame Successful"), _("Saved image to %s" % framePath))
self.statusBar.showMessage(_("Saved Frame to %s" % framePath), 5000)
else:
#QMessageBox.warning(self, _("Save Frame Failed"), _("Failed to save image to %s" % framePath))
self.statusBar.showMessage( _("Failed to save image to %s" % framePath), 5000)

# Reset the MaxSize to match the preview and reset the preview cache
# Reset the MaxSize to match the preview and reset the preview cache
viewport_rect = self.videoPreview.centeredViewport(self.videoPreview.width(), self.videoPreview.height())
self.timeline_sync.timeline.SetMaxSize(viewport_rect.width(), viewport_rect.height())
self.cache_object.Clear()
Expand All @@ -987,7 +982,8 @@ def actionAddTrack_trigger(self, event):
log.info("actionAddTrack_trigger")

# Get # of tracks
track_number = len(get_app().project.get(["layers"]))
all_tracks = get_app().project.get(["layers"])
track_number = list(reversed(sorted(all_tracks, key=itemgetter('number'))))[0].get("number") + 1000000

# Create new track above existing layer(s)
track = Track()
Expand All @@ -998,7 +994,7 @@ def actionAddTrackAbove_trigger(self, event):
log.info("actionAddTrackAbove_trigger")

# Get # of tracks
max_track_number = len(get_app().project.get(["layers"]))
all_tracks = get_app().project.get(["layers"])
selected_layer_id = self.selected_tracks[0]

# Get selected track data
Expand All @@ -1009,35 +1005,52 @@ def actionAddTrackAbove_trigger(self, event):
return
selected_layer_number = int(existing_track.data["number"])

# Loop through tracks above insert point (in descending order), renumbering layers
for existing_layer in list(reversed(range(selected_layer_number+1, max_track_number))):
existing_track = Track.get(number=existing_layer)
if not existing_track:
# Log error and fail silently, and continue
log.error('No track object found with number: %s' % existing_layer)
continue
existing_track.data["number"] = existing_layer + 1
existing_track.save()

# Loop through clips and transitions for track, moving up to new layer
for clip in Clip.filter(layer=existing_layer):
clip.data["layer"] = int(clip.data["layer"]) + 1
clip.save()
# Get track above selected track (if any)
previous_track_number = 0
track_number_delta = 0
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
if track.get("number") == selected_layer_number:
track_number_delta = previous_track_number - selected_layer_number
break
previous_track_number = track.get("number")

for trans in Transition.filter(layer=existing_layer):
trans.data["layer"] = int(trans.data["layer"]) + 1
trans.save()
# Calculate new track number (based on gap delta)
new_track_number = selected_layer_number + 1000000
if track_number_delta > 2:
# New track number (pick mid point in track number gap)
new_track_number = selected_layer_number + int(round(track_number_delta / 2.0))
else:
# Loop through tracks above insert point
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
if track.get("number") > selected_layer_number:
existing_track = Track.get(number=track.get("number"))
if not existing_track:
# Log error and fail silently, and continue
log.error('No track object found with number: %s' % track.get("number"))
continue
existing_layer = existing_track.data["number"]
existing_track.data["number"] = existing_layer + 1000000
existing_track.save()

# Loop through clips and transitions for track, moving up to new layer
for clip in Clip.filter(layer=existing_layer):
clip.data["layer"] = int(clip.data["layer"]) + 1000000
clip.save()

for trans in Transition.filter(layer=existing_layer):
trans.data["layer"] = int(trans.data["layer"]) + 1000000
trans.save()

# Create new track at vacated layer
track = Track()
track.data = {"number": selected_layer_number+1, "y": 0, "label": "", "lock": False}
track.data = {"number": new_track_number, "y": 0, "label": "", "lock": False}
track.save()

def actionAddTrackBelow_trigger(self, event):
log.info("actionAddTrackBelow_trigger")

# Get # of tracks
max_track_number = len(get_app().project.get(["layers"]))
all_tracks = get_app().project.get(["layers"])
selected_layer_id = self.selected_tracks[0]

# Get selected track data
Expand All @@ -1048,28 +1061,49 @@ def actionAddTrackBelow_trigger(self, event):
return
selected_layer_number = int(existing_track.data["number"])

# Loop through tracks from insert point up (in descending order), renumbering layers
for existing_layer in list(reversed(range(selected_layer_number, max_track_number))):
existing_track = Track.get(number=existing_layer)
if not existing_track:
# Log error and fail silently, and continue
log.error('No track object found with number: %s' % existing_layer)
# Get track below selected track (if any)
next_track_number = 0
track_number_delta = 0
found_track = False
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
if found_track:
next_track_number = track.get("number")
track_number_delta = selected_layer_number - next_track_number
break
if track.get("number") == selected_layer_number:
found_track = True
continue
existing_track.data["number"] = existing_layer + 1
existing_track.save()

# Loop through clips and transitions for track, moving up to new layer
for clip in Clip.filter(layer=existing_layer):
clip.data["layer"] = int(clip.data["layer"]) + 1
clip.save()

for trans in Transition.filter(layer=existing_layer):
trans.data["layer"] = int(trans.data["layer"]) + 1
trans.save()
# Calculate new track number (based on gap delta)
new_track_number = selected_layer_number
if track_number_delta > 2:
# New track number (pick mid point in track number gap)
new_track_number = selected_layer_number - int(round(track_number_delta / 2.0))
else:
# Loop through tracks from insert point and above
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
if track.get("number") >= selected_layer_number:
existing_track = Track.get(number=track.get("number"))
if not existing_track:
# Log error and fail silently, and continue
log.error('No track object found with number: %s' % track.get("number"))
continue
existing_layer = existing_track.data["number"]
existing_track.data["number"] = existing_layer + 1000000
existing_track.save()

# Loop through clips and transitions for track, moving up to new layer
for clip in Clip.filter(layer=existing_layer):
clip.data["layer"] = int(clip.data["layer"]) + 1000000
clip.save()

for trans in Transition.filter(layer=existing_layer):
trans.data["layer"] = int(trans.data["layer"]) + 1000000
trans.save()

# Create new track at vacated layer
track = Track()
track.data = {"number": selected_layer_number, "y": 0, "label": "", "lock": False}
track.data = {"number": new_track_number, "y": 0, "label": "", "lock": False}
track.save()

def actionArrowTool_trigger(self, event):
Expand Down Expand Up @@ -1571,22 +1605,6 @@ def actionRemoveTrack_trigger(self, event):
# Remove track
selected_track.delete()

# Loop through all layers above, and renumber elements (to keep thing in numerical order)
for existing_layer in list(range(selected_track_number + 1, max_track_number)):
# Update existing layer number
track = Track.get(number=existing_layer)
track.data["number"] = existing_layer - 1
track.save()

for clip in Clip.filter(layer=existing_layer):
clip.data["layer"] = int(clip.data["layer"]) - 1
clip.save()

for trans in Transition.filter(layer=existing_layer):
trans.data["layer"] = int(trans.data["layer"]) - 1
trans.save()


# Clear selected track
self.selected_tracks = []

Expand Down Expand Up @@ -1624,7 +1642,16 @@ def actionRenameTrack_trigger(self, event):
# Get details of track
track_id = self.selected_tracks[0]
selected_track = Track.get(id=track_id)
track_name = selected_track.data["label"] or _("Track %s") % selected_track.data["number"]

# Find display track number
all_tracks = get_app().project.get(["layers"])
display_count = len(all_tracks)
for track in reversed(sorted(all_tracks, key=itemgetter('number'))):
if track.get("id") == track_id:
break
display_count -= 1

track_name = selected_track.data["label"] or _("Track %s") % display_count

text, ok = QInputDialog.getText(self, _('Rename Track'), _('Track Name:'), text=track_name)
if ok:
Expand Down
Loading

0 comments on commit c0408c5

Please sign in to comment.