OpenShot Video Editor  2.0.0
transition.js
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Transition directives (draggable & resizable functionality)
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 // Init Variables
31 var dragging = false;
32 var resize_disabled = false;
36 var out_of_bounds = false;
38 
39 // Treats element as a transition
40 // 1: can be dragged
41 // 2: can be resized
42 // 3: class change when hovered over
43 var dragLog = null;
44 
45 App.directive('tlTransition', function(){
46  return {
47  scope: "@",
48  link: function(scope, element, attrs){
49 
50  //handle resizability of transition
51  element.resizable({
52  handles: "e, w",
53  minWidth: 1,
54  start: function(e, ui) {
55  dragging = true;
56  resize_disabled = false;
57 
58  //determine which side is being changed
59  var parentOffset = element.offset();
60  var mouseLoc = e.pageX - parentOffset.left;
61  if (mouseLoc < 5) {
62  dragLoc = 'left';
63  } else {
64  dragLoc = 'right';
65  }
66 
67  // Does this bounding box overlap a locked track?
68  var vert_scroll_offset = $("#scrolling_tracks").scrollTop();
69  var track_top = (parseInt(element.position().top) + parseInt(vert_scroll_offset));
70  var track_bottom = (parseInt(element.position().top) + parseInt(element.height()) + parseInt(vert_scroll_offset));
71  if (hasLockedTrack(scope, track_top, track_bottom))
72  resize_disabled = true;
73 
74  // Hide keyframe points
75  element.find('.point_icon').hide()
76 
77  },
78  stop: function(e, ui) {
79  dragging = false;
80 
81  if (resize_disabled) {
82  // disabled, do nothing
83  resize_disabled = false;
84  return;
85  }
86 
87  // Make the keyframe points visible again
88  element.find('.point_icon').show()
89 
90  //get amount changed in width
91  var delta_x = ui.originalSize.width - ui.size.width;
92  var delta_time = delta_x/scope.pixelsPerSecond;
93 
94  //change the transition end/start based on which side was dragged
95  new_left = scope.transition.position;
96  new_right = (scope.transition.end - scope.transition.start);
97 
98  if (dragLoc == 'left'){
99  //changing the start of the transition
100  new_left += delta_time;
101  if (new_left < 0) new_left = 0; // prevent less than zero
102  } else {
103  new_right -= delta_time;
104  }
105 
106  //apply the new start, end and length to the transition's scope
107  scope.$apply(function(){
108 
109  if (dragLoc == 'right'){
110  scope.transition.end = new_right;
111  }
112  if (dragLoc == 'left'){
113  scope.transition.position = new_left;
114  scope.transition.end -= delta_time;
115  }
116 
117  // update transition in Qt (very important =)
118  if (scope.Qt)
119  timeline.update_transition_data(JSON.stringify(scope.transition));
120 
121  });
122 
123  dragLoc = null;
124 
125  },
126  resize: function(e, ui) {
127 
128  if (resize_disabled) {
129  // disabled, keep the item the same size
130  $(this).css(ui.originalPosition);
131  $(this).width(ui.originalSize.width);
132  return;
133  }
134 
135  // get amount changed in width
136  var delta_x = ui.originalSize.width - ui.size.width;
137  var delta_time = Math.round(delta_x/scope.pixelsPerSecond);
138 
139  // change the transition end/start based on which side was dragged
140  new_left = scope.transition.position;
141  new_right = (scope.transition.end - scope.transition.start);
142 
143  if (dragLoc == 'left'){
144  // changing the start of the transition
145  new_left += delta_time;
146  if (new_left < 0) {
147  ui.element.width(ui.size.width + (new_left * scope.pixelsPerSecond));
148  ui.element.css("left", ui.position.left - (new_left * scope.pixelsPerSecond));
149  } else {
150  ui.element.width(ui.size.width);
151  }
152  } else {
153  // changing the end of the transitions
154  new_right -= delta_time;
155  ui.element.width(ui.size.width);
156  }
157 
158  },
159 
160  });
161 
162  //handle hover over on the transition
163  element.hover(
164  function () {
165  if (!dragging)
166  {
167  element.addClass( "highlight_transition", 200, "easeInOutCubic" );
168  }
169  },
170  function () {
171  if (!dragging)
172  {
173  element.removeClass( "highlight_transition", 200, "easeInOutCubic" );
174  }
175  }
176  );
177 
178 
179  //handle draggability of transition
180  element.draggable({
181  snap: ".track", // snaps to a track
182  snapMode: "inner",
183  snapTolerance: 20,
184  scroll: true,
185  revert: 'invalid',
186  start: function(event, ui) {
187  previous_drag_position = null;
188  dragging = true;
189  if (!element.hasClass('ui-selected'))
190  {
191  // Clear previous selections?
192  var clear_selections = false;
193  if ($(".ui-selected").length > 0)
194  clear_selections = true;
195 
196  // SelectClip, SelectTransition
197  var id = $(this).attr("id");
198  if (element.hasClass('clip')) {
199  // Select this clip, unselect all others
200  scope.SelectTransition("", clear_selections);
201  scope.SelectClip(id, clear_selections);
202 
203  } else if (element.hasClass('transition')) {
204  // Select this transition, unselect all others
205  scope.SelectClip("", clear_selections);
206  scope.SelectTransition(id, clear_selections);
207  }
208  }
209 
210  // Apply scope up to this point
211  scope.$apply(function(){});
212 
213  var vert_scroll_offset = $("#scrolling_tracks").scrollTop();
214  var horz_scroll_offset = $("#scrolling_tracks").scrollLeft();
216 
217  bounding_box = {};
218 
219  // Init all other selected transitions (prepare to drag them)
220  $(".ui-selected").each(function(){
221  start_transitions[$(this).attr('id')] = {"top": $(this).position().top + vert_scroll_offset,
222  "left": $(this).position().left + horz_scroll_offset};
223  move_transitions[$(this).attr('id')] = {"top": $(this).position().top + vert_scroll_offset,
224  "left": $(this).position().left + horz_scroll_offset};
225 
226  //send transition to bounding box builder
227  setBoundingBox($(this));
228  });
229 
230  // Does this bounding box overlap a locked track?
231  if (hasLockedTrack(scope, bounding_box.top, bounding_box.bottom))
232  return !event; // yes, do nothing
233 
234  },
235  stop: function(event, ui) {
236 
237  // Ignore transition-menu click
238  $( event.toElement ).one('.transition_menu', function(e){ e.stopImmediatePropagation(); } );
239 
240  // Hide snapline (if any)
241  scope.HideSnapline();
242 
243  // Clear previous drag position
244  previous_drag_position = null;
245  dragging = false;
246 
247  },
248  drag: function(e, ui) {
249  var previous_x = ui.originalPosition.left;
250  var previous_y = ui.originalPosition.top;
251  if (previous_drag_position != null)
252  {
253  // if available, override with previous drag position
254  previous_x = previous_drag_position.left;
255  previous_y = previous_drag_position.top;
256  }
257 
258  // set previous position (for next time around)
259  previous_drag_position = ui.position;
260 
261  // Calculate amount to move transitions
262  var x_offset = ui.position.left - previous_x;
263  var y_offset = ui.position.top - previous_y;
264 
265  // Move the bounding box and apply snapping rules
266  results = moveBoundingBox(scope, previous_x, previous_y, x_offset, y_offset, ui.position.left, ui.position.top);
267  x_offset = results.x_offset;
268  y_offset = results.y_offset;
269 
270  // Update ui object
271  ui.position.left = results.position.left;
272  ui.position.top = results.position.top;
273 
274  // Move all other selected transitions with this one
275  $(".ui-selected").each(function(){
276  var pos = $(this).position();
277  var newY = move_transitions[$(this).attr('id')]["top"] + y_offset;
278  var newX = move_transitions[$(this).attr('id')]["left"] + x_offset;
279 
280  //update the transition location in the array
281  move_transitions[$(this).attr('id')]['top'] = newY;
282  move_transitions[$(this).attr('id')]['left'] = newX;
283 
284  //change the element location
285  $(this).css('left', newX);
286  $(this).css('top', newY);
287 
288  });
289 
290  },
291  revert: function(valid) {
292  if(!valid) {
293  //the drop spot was invalid, so we're going to move all transitions to their original position
294  $(".ui-selected").each(function(){
295  var oldY = start_transitions[$(this).attr('id')]['top'];
296  var oldX = start_transitions[$(this).attr('id')]['left'];
297 
298  $(this).css('left', oldX);
299  $(this).css('top', oldY);
300  });
301  }
302  }
303  });
304 
305 
306  }
307  };
308 });
309 
310 
311 
312 
jQuery fx start
Definition: jquery.js:9518
function getTrackContainerHeight()
Definition: functions.js:41
var track_container_height
Definition: transition.js:37
var resize_disabled
Definition: transition.js:32
var bounding_box
Definition: functions.js:179
function moveBoundingBox(scope, previous_x, previous_y, x_offset, y_offset, left, top)
Definition: functions.js:214
jQuery fx stop
Definition: jquery.js:9524
var move_transitions
Definition: transition.js:35
var App
Definition: app.js:31
function setBoundingBox(item)
Definition: functions.js:182
var a[b] e
Tween propHooks scrollTop
Definition: jquery.js:9274
var start_transitions
Definition: transition.js:34
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 hasLockedTrack(scope, top, bottom)
Definition: functions.js:161
var previous_drag_position
Definition: transition.js:33
var out_of_bounds
Definition: transition.js:36
var dragging
Definition: transition.js:31
var dragLog
Definition: transition.js:43