OpenShot Video Editor  2.0.0
track.js
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Track directives (droppable functionality, etc...)
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  * @author Cody Parker <cody@yourcodepro.com>
6  *
7  * @section LICENSE
8  *
9  * Copyright (c) 2008-2014 OpenShot Studios, LLC
10  * <http://www.openshotstudios.com/>. This file is part of
11  * OpenShot Video Editor, an open-source project dedicated to
12  * delivering high quality video editing and animation solutions to the
13  * world. For more information visit <http://www.openshot.org/>.
14  *
15  * OpenShot Video Editor is free software: you can redistribute it
16  * and/or modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation, either version 3 of the
18  * License, or (at your option) any later version.
19  *
20  * OpenShot Video Editor is distributed in the hope that it will be
21  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
27  */
28 
29 
30 // Treats element as a track
31 // 1: allows clips, transitions, and effects to be dropped
32 App.directive('tlTrack', function($timeout) {
33  return {
34  // A = attribute, E = Element, C = Class and M = HTML Comment
35  restrict:'A',
36  link: function(scope, element, attrs) {
37 
38  scope.$watch('project.layers.length', function (val) {
39  if (val) {
40  $timeout(function(){
41  // Update track indexes if tracks change
42  scope.UpdateLayerIndex();
43  scope.playhead_height = $("#track-container").height();
44  $(".playhead-line").height(scope.playhead_height);
45  }, 0);
46 
47  }
48  });
49 
50  //make it accept drops
51  element.droppable({
52  accept: ".droppable",
53  drop:function(event,ui) {
54 
55  // Disabling sorting (until all the updates are completed)
56  scope.enable_sorting = false;
57 
58  var vert_scroll_offset = $("#scrolling_tracks").scrollTop();
59  var horz_scroll_offset = $("#scrolling_tracks").scrollLeft();
60 
61  // Get scrollbar offsets
62  var scrolling_tracks_offset_left = $("#scrolling_tracks").offset().left;
63  var scrolling_tracks_offset_top = $("#scrolling_tracks").offset().top;
64 
65  // Keep track of each dropped clip (to check for missing transitions below, after they have been dropped)
66  var dropped_clips = [];
67  var position_diff = 0; // the time diff to apply to multiple selections (if any)
68 
69  // with each dragged clip, find out which track they landed on
70  // Loop through each selected item, and remove the selection if multiple items are selected
71  // If only 1 item is selected, leave it selected
72  $(".ui-selected").each(function() {
73  var item = $(this);
74 
75  // Remove all selections
76  if ($(".ui-selected").length > 1)
77  {
78  for (var clip_index = 0; clip_index < scope.project.clips.length; clip_index++) {
79  scope.project.clips[clip_index].selected = false;
80  if (scope.Qt)
81  timeline.removeSelection(scope.project.clips[clip_index].id.replace("clip_", ""), "clip");
82  }
83  for (var tran_index = 0; tran_index < scope.project.effects.length; tran_index++) {
84  scope.project.effects[tran_index].selected = false;
85  if (scope.Qt)
86  timeline.removeSelection(scope.project.effects[tran_index].id.replace("transition_", ""), "transition");
87  }
88  }
89 
90  // Determine type of item
91  item_type = null;
92  if (item.hasClass('clip'))
93  item_type = 'clip';
94  else if(item.hasClass('transition'))
95  item_type = 'transition';
96  else
97  // Unknown drop type
98  return;
99 
100  // get the item properties we need
101  item_id = item.attr("id");
102  item_num = item_id.substr(item_id.indexOf("_") + 1);
103  item_middle = item.position().top + (item.height() / 2); // find middle of clip
104  item_left = item.position().left;
105 
106  // Adjust top and left coordinates for scrollbars
107  item_left = parseFloat(item_left + horz_scroll_offset);
108  item_middle = parseFloat(item_middle - scrolling_tracks_offset_top + vert_scroll_offset);
109 
110  // make sure the item isn't dropped off too far to the left
111  if (item_left < 0) item_left = 0;
112 
113  // get track the item was dropped on
114  drop_track_num = findTrackAtLocation(scope, parseInt(item_middle));
115 
116  // if the droptrack was found, update the json
117  if (drop_track_num != -1){
118 
119  // find the item in the json data
120  item_data = null;
121  if (item_type == 'clip')
122  item_data = findElement(scope.project.clips, "id", item_num);
123  else if (item_type == 'transition')
124  item_data = findElement(scope.project.effects, "id", item_num);
125 
126  // set time diff (if not already determined)
127  if (position_diff == 0.0)
128  // once calculated, we want to apply the exact same time diff to each clip/trans
129  position_diff = (item_left / scope.pixelsPerSecond) - item_data.position;
130 
131  // change the clip's track and position in the json data
132  scope.$apply(function(){
133  //set track
134  item_data.layer = drop_track_num;
135  item_data.position += position_diff;
136  });
137 
138  // Resize timeline if it's too small to contain all clips
139  scope.ResizeTimeline();
140 
141  // Keep track of dropped clips (we'll check for missing transitions in a sec)
142  dropped_clips.push(item_data);
143 
144  // update clip in Qt (very important =)
145  if (scope.Qt && item_type == 'clip')
146  timeline.update_clip_data(JSON.stringify(item_data));
147 
148  else if (scope.Qt && item_type == 'transition')
149  timeline.update_transition_data(JSON.stringify(item_data));
150 
151 
152  }
153  });
154 
155  // Add missing transitions (if any)
156  if (dropped_clips.length == 1)
157  // Hack to only add missing transitions if a single clip is being dropped
158  for (var clip_index = 0; clip_index < dropped_clips.length; clip_index++) {
159  var item_data = dropped_clips[clip_index];
160 
161  // Check again for missing transitions
162  missing_transition_details = scope.GetMissingTransitions(item_data);
163  if (scope.Qt && missing_transition_details != null)
164  timeline.add_missing_transition(JSON.stringify(missing_transition_details));
165  }
166 
167  // Clear dropped clips
168  dropped_clips = [];
169 
170  // Re-sort clips
171  scope.enable_sorting = true;
172  scope.SortItems();
173  }
174  });
175  }
176  };
177 });
jQuery fn offset
Definition: jquery.js:9546
function findElement(arr, propName, propValue)
Definition: functions.js:31
var App
Definition: app.js:31
Tween propHooks scrollTop
Definition: jquery.js:9274
jQuery each(["height","width"], function(i, name){jQuery.cssHooks[name]={get:function(elem, computed, extra){if(computed){return elem.offsetWidth===0 &&rdisplayswap.test(jQuery.css(elem,"display"))?jQuery.swap(elem, cssShow, function(){return getWidthOrHeight(elem, name, extra);}):getWidthOrHeight(elem, name, extra);}}, set:function(elem, value, extra){var styles=extra &&getStyles(elem);return setPositiveNumber(elem, value, extra?augmentWidthOrHeight(elem, name, extra, jQuery.support.boxSizing &&jQuery.css(elem,"boxSizing", false, styles)==="border-box", styles):0);}};})
function findTrackAtLocation(scope, top)
Definition: functions.js:140