#	OpenShot Video Editor is a program that creates, modifies, and edits video files.
#   Copyright (C) 2009  Jonathan Thomas
#
#	This file is part of OpenShot Video Editor (http://launchpad.net/openshot/).
#
#	OpenShot Video Editor 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 3 of the License, or
#	(at your option) any later version.
#
#	OpenShot Video Editor 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 OpenShot Video Editor.  If not, see <http://www.gnu.org/licenses/>.

import os, sys
import gtk, goocanvas
import xml.dom.minidom as xml

from classes import clip, files, marker, timeline, track
# init the foreign language
from language import Language_Init

########################################################################
class sequence:
	"""A sequence contains tracks and clips that make up a scene (aka sequence).  Currently, Openshot
	only contains a single sequence, but soon it will have the ability to create many sequences."""

	#----------------------------------------------------------------------
	def __init__(self, seq_name, project):
		"""Constructor"""

		# Add language support
		translator = Language_Init.Translator(project)
		_ = translator.lang.gettext

		# init variables for sequence
		self.name = seq_name
		self.length = 600.0		   # length in seconds of sequence.  This controls how wide to render the tracks.
		self.project = project	  # reference to current project
		self.scale = 8.0		   # this represents how many seconds per tick mark
		self.tick_pixels = 100	  # number of pixels between each tick mark
		self.play_head_position = 0.0 # position of the play head in seconds

		# init the tracks on the sequence
		self.tracks = []
		self.tracks.append(track.track(_("Track %s") % 2, self))
		self.tracks.append(track.track(_("Track %s") % 1, self))

		# init markers
		self.markers = []

		# reference to play_head goocanvas group
		self.play_head = None
		self.ruler_time = None
		self.play_head_line = None
		self.enable_animated_playhead = True


	def AddMarker(self, marker_name, position_on_track):

		# loop through existing markers (check for duplicates)
		for exiting_marker in self.markers:
			if exiting_marker.position_on_track == position_on_track:
				return

		# Create marker object
		m = marker.marker(marker_name, position_on_track, self)

		# Add to Marker Collection
		self.markers.append(m)

		# re-order marker collection (to keep them in order of their positions)
		self.reorder_markers()

		# mark project as modified
		self.project.set_project_modified(is_modified=True, refresh_xml=True, type=_("Added marker"))

		return m



	def get_marker(self, direction, current_position):


		# check for markers
		if len(self.markers) == 0:
			return None

		if direction == "left":

			# loop through all markers (check for duplicates)
			possible_match = None
			for m in self.markers:

				if m.position_on_track < current_position - 0.20:
					possible_match = m

			# return the match
			return possible_match

		else:
			# right

			# loop through all markers (check for duplicates)
			for m in self.markers:

				if m.position_on_track > current_position + 0.20:
					# return the match
					return m


		# no markers found
		return None



	def AddTrack(self, track_name, position="above", existing_track=None):


		# Add another track
		if existing_track:
			index_existing_track = self.tracks.index(existing_track)
			# insert next to an existing track
			if position == "above":
				self.tracks.insert(index_existing_track, track.track(track_name, self))
			else:
				self.tracks.insert(index_existing_track + 1, track.track(track_name, self))

		else:
			# insert at top of tracks
			self.tracks.insert(0, track.track(track_name, self))

		# mark project as modified
		self.project.set_project_modified(is_modified=True, refresh_xml=True, type=_("Added Track"))


	def rename_track(self, current_track, new_name):
		current_track.name = new_name

		# mark project as modified
		self.project.set_project_modified(is_modified=True, refresh_xml=True, type=_("Renamed track"))


	def get_pixels_per_second(self):
		# calculate the number of pixels per second, based on the scale of the timeline
		return float(self.tick_pixels) / float(self.scale)	   


	def Render(self):

		# Clear the canvases
		self.project.form.MyCanvas_Left.set_root_item(goocanvas.Group())
		self.project.form.TimelineCanvas_Left.set_root_item(goocanvas.Group())
		self.project.form.MyCanvas.set_root_item(goocanvas.Group())
		self.project.form.TimelineCanvas_Right.set_root_item(goocanvas.Group())

		# Render Ruler
		self.RenderRuler()

		# Render Markers
		self.RenderMarkers()

		# loop through each track
		for MyTrack in self.tracks:

			# Render track			
			MyTrack.Render()


		# loop through each track
		for MyTrack in self.tracks:

			# loop through each transition, from the bottom up
			for MyTran in MyTrack.transitions:

				# Render track			
				MyTran.Render()



	def GenerateXML(self, dom, xmlParentNode):

		# get frames per second
		fps = self.project.fps()

		multitrack = dom.createElement("multitrack")
		xmlParentNode.appendChild(multitrack)

		# create fake background track (i.e. black background)
		bg_track = track.track("Background Track", self)
		bg_track.parent = self
		bg_end_time = self.Calculate_Length()
		bg_image = files.OpenShotFile(self.project)
		bg_image.name = os.path.join(self.project.IMAGE_DIR, "black.png")
		bg_image.length = bg_end_time
		bg_image.max_frames = round(bg_end_time * fps)

		# set remaining length
		remaining_length = bg_end_time
		position = 0.0
		current_length = 0.0

		# Add the background black clip in sections (5 minute (i.e. 300 seconds) sections)
		while remaining_length > 0.0:
			# calculate length of this section
			if remaining_length > 300.0:
				current_length = 300.0
				remaining_length -= 300.0
			else:
				current_length = remaining_length
				remaining_length = 0.0

			bg_clip = clip.clip("Background Clip", "Gold", position, 0.0, current_length, bg_track, bg_image)
			bg_clip.distort = True
			bg_clip.fill = True
			bg_track.clips.append(bg_clip)

			# calculate position for next section
			position += current_length

		# add XML for background track
		bg_track.GenerateXML(dom, multitrack, fps=fps)

		# loop through each track, from the bottom up
		for MyTrack in reversed(self.tracks):

			# Render track			
			MyTrack.GenerateXML(dom, multitrack, fps=fps)


	def Calculate_Length(self):
		""" Determine the length of this sequence """
		longest_clip = 0.1
		fps = self.project.fps()

		# loop through each track, from the bottom up
		for MyTrack in self.tracks:

			# loop through each clip
			for MyClip in MyTrack.clips:

				# calculate end of clip
				end_of_clip = MyClip.position_on_track + MyClip.length()

				if end_of_clip > longest_clip:
					longest_clip = end_of_clip

		# return longest clip
		return longest_clip + 0.1

	#----------------------------------------------------------------------
	def RenderRuler(self):
		"""This adds a track to the canvas with 3 images: a left, middle, and right"""

		# get the pixels per second from the parent sequence
		pixels_per_second = self.get_pixels_per_second()

		# determine position of playhead
		time = timeline.timeline().get_friendly_time(self.play_head_position * 1000) 

		# Get theme settings
		theme = self.project.theme
		theme_settings = self.project.theme_settings.settings

		# set the top coordinate of this track to the bottom coordinate of the last track
		x = theme_settings["timeline"]["ruler"]["x"]	  
		y_top = theme_settings["timeline"]["ruler"]["y"]

		# determine the height of the timeline
		imgTrack_Track = gtk.image_new_from_file("%s/openshot/themes/%s/Track_Middle.png" % (self.project.form.openshot_path, theme))
		imgTrack_Track_Height = imgTrack_Track.get_pixbuf().get_height()
		timeline_heigth = len(self.tracks) * imgTrack_Track_Height + (len(self.tracks) * theme_settings["track"]["padding"]) + 10

		# get a reference to the 2 main canvas objects & theme
		theme = self.project.theme
		canvas_timeline = self.project.form.MyCanvas
		canvas_timeline_left = self.project.form.MyCanvas_Left
		canvas_left = self.project.form.TimelineCanvas_Left
		canvas_right = self.project.form.TimelineCanvas_Right

		# Add an item to the goocanvas
		root_left = canvas_left.get_root_item ()
		root_right = canvas_right.get_root_item ()

		# Load all 3 images
		imgTrack_Left = gtk.image_new_from_file("%s/openshot/themes/%s/ruler_left.png" % (self.project.form.openshot_path, theme))
		imgTrack_Middle = gtk.image_new_from_file("%s/openshot/themes/%s/ruler_middle.png" % (self.project.form.openshot_path, theme))
		imgTrack_Right = gtk.image_new_from_file("%s/openshot/themes/%s/ruler_right.png" % (self.project.form.openshot_path, theme))	   
		imgTrack_Tick = gtk.image_new_from_file("%s/openshot/themes/%s/ruler_tick.png" % (self.project.form.openshot_path, theme))	   

		# Get Height and Width of Images 
		imgTrack_Left_Height = imgTrack_Left.get_pixbuf().get_height()
		imgTrack_Left_Width = imgTrack_Left.get_pixbuf().get_width()
		imgTrack_Right_Width = imgTrack_Right.get_pixbuf().get_width()		

		# Get Size of Window (to determine how wide the middle image should be streched)
		Size_Of_Middle = int(pixels_per_second * self.length)

		# resize the canvas height and width
		new_size_of_middle = Size_Of_Middle + 200
		if new_size_of_middle > 32000:
			# do not let the size of the canvas exceed 32,000... or cairo will throw an error
			new_size_of_middle = 32000

		canvas_timeline.set_bounds (0, 0, new_size_of_middle, timeline_heigth)
		self.project.form.hscrollbar2.set_range(0, new_size_of_middle)
		self.project.form.vscrollbar2.set_range(0, timeline_heigth)
		self.project.form.on_hscrollbar2_value_changed(self.project.form.hscrollbar2)

		# Get the height of the RULER
		ruler_height = theme_settings["timeline"]["ruler"]["height"]
		left_canvas_width = theme_settings["track"]["track_name_text"]["w"]

		# Resize the LEFT RULER
		canvas_timeline_left.set_bounds (0, 0, left_canvas_width, timeline_heigth)
		canvas_left.set_bounds (0, 0, left_canvas_width, ruler_height)
		canvas_left.set_size_request (0, ruler_height)
		self.project.form.timelineWindowLeft.set_size_request (left_canvas_width, ruler_height)
		self.project.form.scrolledwindow_Left.set_size_request (left_canvas_width, 0)

		# Resize the RIGHT RULER
		canvas_right.set_bounds (0, 0, new_size_of_middle + 16, ruler_height)
		canvas_right.set_size_request (0, ruler_height)
		self.project.form.timelinewindowRight.set_size_request (0, ruler_height)

		# Resize RULER Hbox (which holds both the LEFT and RIGHT windows)
		self.project.form.hbox5.set_size_request (0, ruler_height)

		# Resize Middle pixbuf
		middlePixBuf = imgTrack_Middle.get_pixbuf()
		pixbuf_list = self.split_images(middlePixBuf, imgTrack_Left_Height, Size_Of_Middle)

		# Create Group (for the track)
		GroupTrack = goocanvas.Group (parent = root_right)

		# Add Left Image to Group
		image1 = goocanvas.Image (parent = root_left,
				                  pixbuf = imgTrack_Left.get_pixbuf(),
				                  x = x,
				                  y = y_top)

		# Add Middle Image to Group (this can be multiple image tiled together
		pixbuf_x = 0
		for pixbuf in pixbuf_list:
			# get width of this pixbuf
			pixbuf_width = pixbuf.get_width()

			image2 = goocanvas.Image (parent = GroupTrack,
						              pixbuf = pixbuf,
						              x = pixbuf_x,
						              y = y_top)  

			# increment the x
			pixbuf_x = pixbuf_x + pixbuf_width


		# Add Middle Image to Group
		image3 = goocanvas.Image (parent = GroupTrack,
				                  pixbuf = imgTrack_Right.get_pixbuf(),
				                  x = Size_Of_Middle - 1,
				                  y = y_top)

		# Add Playhead position text
		self.ruler_time = goocanvas.Text (parent = root_left,
				                          text = theme_settings["timeline"]["playhead_text"]["font"] % (time[2], time[3], time[4], time[5]),
				                          antialias = True,
				                          use_markup = True,
				                          x = x + theme_settings["timeline"]["playhead_text"]["x"],
				                          y = y_top + theme_settings["timeline"]["playhead_text"]["y"])

		# Resize tick marks for ruler
		tickPixBuf = imgTrack_Tick.get_pixbuf()
		big_tickPixBuf = tickPixBuf.scale_simple(1, theme_settings["timeline"]["ruler"]["large_tick"]["h"], gtk.gdk.INTERP_NEAREST)
		medium_tickPixBuf = tickPixBuf.scale_simple(1, theme_settings["timeline"]["ruler"]["medium_tick"]["h"], gtk.gdk.INTERP_NEAREST)
		small_tickPixBuf = tickPixBuf.scale_simple(1, theme_settings["timeline"]["ruler"]["small_tick"]["h"], gtk.gdk.INTERP_NEAREST)

		# loop through each tick mark
		number_of_ticks = int(self.length / self.scale)
		ruler_pixels = ((float(self.length) / float(self.scale)) * self.tick_pixels)
		if ruler_pixels > 32000:
			ruler_pixels = 32000

		tick = 0
		end_of_timeline = False

		while end_of_timeline == False:

			# increment tick
			tick = tick + 1

			# get the formatted time code
			milliseconds = (tick * self.scale) * 1000
			time = timeline.timeline().get_friendly_time(milliseconds)

			if (tick * self.tick_pixels + 16) < ruler_pixels:

				# Add Text to the Track
				text1 = goocanvas.Text (parent = GroupTrack,
								        text = theme_settings["timeline"]["ruler"]["time_text"]["font"] % (time[2], time[3], time[4], time[5]),
								        antialias = True,
								        use_markup = True,
								        x = (tick * self.tick_pixels) - theme_settings["timeline"]["ruler"]["time_text"]["x"],
								        y = y_top + theme_settings["timeline"]["ruler"]["time_text"]["y"])				

				# Add BIG TICK Image to Group
				image5 = goocanvas.Image (parent = GroupTrack,
								          pixbuf = big_tickPixBuf,
								          x = (tick * self.tick_pixels),
								          y = y_top + theme_settings["timeline"]["ruler"]["large_tick"]["y"])


			# determine # of minor ticks.  The longer the timeline, the less
			# ticks can be added do to performance reasons.
			number_of_minor_ticks = 6
			if (number_of_ticks * 10) > 1500:
				number_of_minor_ticks = 2

			# Add Minor ticks
			big_tick_x = ((tick - 1) * self.tick_pixels)
			minor_tick_increment = self.tick_pixels / number_of_minor_ticks

			# loop through minor ticks, and add them to the canvas
			for minor_tick in range(1, number_of_minor_ticks):

				# Resize minor tick pixbuf
				tickPixBuf = None
				minor_y_adjustment = theme_settings["timeline"]["ruler"]["small_tick"]["y"]
				if minor_tick == int(number_of_minor_ticks / 2):
					minor_y_adjustment = theme_settings["timeline"]["ruler"]["medium_tick"]["y"]
					tickPixBuf = medium_tickPixBuf
				else:
					tickPixBuf = small_tickPixBuf

				# don't extend past the ruler
				if (big_tick_x + int(minor_tick_increment * minor_tick)) < ruler_pixels:

					# Add minor tick Image to Group
					image5 = goocanvas.Image (parent = GroupTrack,
										      pixbuf = tickPixBuf,
										      x = big_tick_x + int(minor_tick_increment * minor_tick),
										      y = y_top + minor_y_adjustment)
				else:
					end_of_timeline = True
					break

		# Connect signals to ruler to allow drag and drop
		GroupTrack.connect ("button_press_event", self.on_ruler_press)
		GroupTrack.connect ("motion_notify_event", self.on_ruler_motion)
		GroupTrack.connect ("button_release_event", self.on_ruler_release)




	def on_ruler_press(self, item, target, event):

		# enable animated playhead
		self.enable_animated_playhead = True

		if event.button == 1:
			new_x = event.x

			# get the pixels per second from the parent sequence
			pixels_per_second = self.get_pixels_per_second()

			# calculate playhead position
			play_head_position = new_x / pixels_per_second

			if play_head_position < 0:
				play_head_position = 0

			# update video frame
			self.update_video(play_head_position)



	def on_ruler_motion(self, item, target, event):
		#print "on_ruler_motion"

		if (event.state & gtk.gdk.BUTTON1_MASK):
			new_x = event.x

			# disable animated playhead
			self.enable_animated_playhead = False

			# get the pixels per second from the parent sequence
			pixels_per_second = self.get_pixels_per_second()

			# calculate playhead position
			play_head_position = new_x / pixels_per_second

			if play_head_position < 0:
				play_head_position = 0

			# update video frame
			self.update_video(play_head_position)

	def on_ruler_release(self, item, target, event):

		# enable animated playhead
		self.enable_animated_playhead = True

	#----------------------------------------------------------------------
	def RenderMarkers(self):

		# loop through all markers (check for duplicates)
		for m in self.markers:

			# render the marker
			m.Render()



	def reorder_markers(self):
		# get a list of all clips on this track
		self.markers.sort(self.compare_marker)



	def compare_marker(self, marker1, marker2):
		if marker1.position_on_track > marker2.position_on_track:
			return 1
		elif marker1.position_on_track == marker2.position_on_track:
			return 0
		else:
			return -1


	#----------------------------------------------------------------------
	def RenderPlayHead(self):
		"""This adds the playhead to the canvas, and the play head position line"""

		# Get theme settings
		theme_settings = self.project.theme_settings.settings

		# get the pixels per second from the parent sequence
		pixels_per_second = self.get_pixels_per_second()

		# set the top coordinate of this track to the bottom coordinate of the last track
		x = self.play_head_position * pixels_per_second
		x = x + theme_settings["timeline"]["ruler"]["playhead"]["x"]
		y_top = theme_settings["timeline"]["ruler"]["playhead"]["y"]

		# get a reference to the 2 main canvas objects & theme
		theme = self.project.theme
		canvas_right = self.project.form.TimelineCanvas_Right

		# Add an item to the goocanvas
		root_right = canvas_right.get_root_item ()

		# Load all 3 images
		imgTrack_PlayHead = gtk.image_new_from_file("%s/openshot/themes/%s/play_head.png" % (self.project.form.openshot_path, theme))
		imgTrack_Line = gtk.image_new_from_file("%s/openshot/themes/%s/position_line.png" % (self.project.form.openshot_path, theme))
		imgTrack_Ruler = gtk.image_new_from_file("%s/openshot/themes/%s/ruler_right.png" % (self.project.form.openshot_path, theme))
		imgTrack_Track = gtk.image_new_from_file("%s/openshot/themes/%s/Track_Middle.png" % (self.project.form.openshot_path, theme))

		# Get Height and Width of Images 
		imgTrack_PlayHead_Height = imgTrack_PlayHead.get_pixbuf().get_height()
		imgTrack_PlayHead_Width = imgTrack_PlayHead.get_pixbuf().get_width()
		imgTrack_Ruler_Height = imgTrack_Ruler.get_pixbuf().get_height()
		imgTrack_Track_Height = imgTrack_Track.get_pixbuf().get_height()

		# Get Size of Window (to determine how wide the middle image should be streched)
		Size_Of_Line = len(self.tracks) * imgTrack_Track_Height + (len(self.tracks) * theme_settings["track"]["padding"]) + 2

		# Resize Middle pixbuf
		linePixBuf = imgTrack_Line.get_pixbuf()
		linePixBuf = linePixBuf.scale_simple(1, Size_Of_Line, gtk.gdk.INTERP_NEAREST)

		# Create Group (for the track)
		GroupTrack = goocanvas.Group (parent = root_right)
		self.play_head = GroupTrack

		# Create the red line
		lineRect = goocanvas.Rect(parent = GroupTrack,
				                  x = x,
				                  y = y_top + theme_settings["timeline"]["ruler"]["playhead_line"]["y"],
				                  width = 1,
				                  height = Size_Of_Line,
				                  line_width = theme_settings["timeline"]["ruler"]["playhead_line"]["line_width"],
				                  stroke_color_rgba = theme_settings["timeline"]["ruler"]["playhead_line"]["stroke_color"]
				                  )

		# Create Group (for the extended play line)
		track_canvas_right = self.project.form.MyCanvas
		track_root_right = track_canvas_right.get_root_item ()
		GroupTrack2 = goocanvas.Group (parent = track_root_right)
		self.play_head_line = GroupTrack2

		# Create the red line
		lineRect = goocanvas.Rect(parent = GroupTrack2,
				                  x = x,
				                  y = 0,
				                  width = 1,
				                  height = Size_Of_Line + theme_settings["timeline"]["ruler"]["playhead_line"]["length_offset"],
				                  line_width = theme_settings["timeline"]["ruler"]["playhead_line"]["line_width"],
				                  stroke_color_rgba = theme_settings["timeline"]["ruler"]["playhead_line"]["stroke_color"]
				                  )

		# Add Play Head Image to Group
		image1 = goocanvas.Image (parent = GroupTrack,
				                  pixbuf = imgTrack_PlayHead.get_pixbuf(),
				                  x = x + (imgTrack_PlayHead_Width / 2) * -1,
				                  y = imgTrack_Ruler_Height - imgTrack_PlayHead_Height + y_top - 2)

		GroupTrack3 = goocanvas.Group (parent = track_root_right)
		
		# Connect signals to play head to allow drag and drop
		GroupTrack.connect ("motion_notify_event", self.on_motion_notify_x)
		GroupTrack.connect ("button_press_event", self.on_button_press_x)
		GroupTrack.connect ("button_release_event", self.on_button_release_x)



	def on_motion_notify_x (self, item, target, event):
		"""this method allows the clip to be dragged and dropped on a track"""

		if (event.state & gtk.gdk.BUTTON1_MASK):
			new_x = event.x
			new_y = event.y

			# disable animated playhead
			self.enable_animated_playhead = False

			# get the pixels per second from the parent sequence
			pixels_per_second = self.get_pixels_per_second()

			# get width of playhead
			playhead_width = item.get_bounds().x2 - item.get_bounds().x1
			min_x = (playhead_width / 2) * -1

			# don't allow the clip to slide past the beginning of the canvas
			total_x_diff = new_x - self.drag_x 
			total_y_diff = event.y - self.drag_y
			if (item.get_bounds().x1 + total_x_diff < min_x):
				total_x_diff = min_x - item.get_bounds().x1

			# move clip				
			item.translate (total_x_diff, 0)
			self.play_head_line.translate(total_x_diff, 0)

			# update playhead position
			play_head_position = (item.get_bounds().x1 + (playhead_width / 2)) / pixels_per_second

			# update video frame
			self.update_video(play_head_position)

		return True


	def update_video(self, play_head_position):

		# return to "preview" mode (if in override mode)
		if self.project.form.MyVideo.mode == "override":
			self.project.set_project_modified(is_modified=True, refresh_xml=True)

		# Refresh the MLT XML file
		self.project.RefreshXML()

		# determine new frame number
		frame = self.project.fps() * play_head_position

		# seek to the new frame
		self.project.form.MyVideo.seek(int(frame))


	def move_play_head (self, new_time):
		"""this method allows the play head to be moved to a specific spot on the timeline.  It accepts
		a parameter for the # of seconds to move the playhead to."""

		# move play_head to the top layer
		if self.play_head and new_time != self.play_head_position:

			# keep track of the current play-head position
			self.play_head_position = float(new_time)

			self.play_head.raise_(None)
			self.play_head_line.raise_(None)

			# get the pixels per second from the parent sequence
			pixels_per_second = self.get_pixels_per_second()

			# get width of playhead
			playhead_width = self.play_head.get_bounds().x2 - self.play_head.get_bounds().x1
			min_x = (playhead_width / 2) * -1

			# don't allow the clip to slide past the beginning of the canvas
			total_x_diff = (new_time * pixels_per_second) - (self.play_head.get_bounds().x2 + min_x)

			# animate clip (if needed)
			if self.enable_animated_playhead == True:
				self.play_head.animate(total_x_diff, 0, 1.0, 0.0, False, 100, 4, goocanvas.ANIMATE_FREEZE)
				self.play_head_line.animate(total_x_diff, 0, 1.0, 0.0, False, 100, 4, goocanvas.ANIMATE_FREEZE)

			# move clip
			self.play_head.translate (total_x_diff, 0)
			self.play_head_line.translate (total_x_diff, 0)

			# Get theme settings
			theme_settings = self.project.theme_settings.settings

			# print time of playhead
			milliseconds = ((self.play_head.get_bounds().x1 + (playhead_width / 2)) / pixels_per_second) * 1000
			time = timeline.timeline().get_friendly_time(milliseconds)
			frame = round((time[5] / 1000.0) * self.project.fps())
			self.ruler_time.set_property("text", theme_settings["timeline"]["playhead_text"]["font"] % (time[2], time[3], time[4], frame))


	def on_button_press_x (self, item, target, event):
		""" This method initializes some variables needed for dragging and dropping a clip """

		# enable animated playhead
		self.enable_animated_playhead = True

		# raise the group up to the top level
		item.raise_(None)

		if event.button == 1:

			# set the x and y where the cursor started dragging from
			self.drag_x = event.x
			self.drag_y = event.y

			# change the cursor for the drag n drop operation
			fleur = gtk.gdk.Cursor (gtk.gdk.FLEUR)
			canvas = item.get_canvas ()
			canvas.pointer_grab (item,
						         gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK,
						         fleur,
						         event.time)

			# pause the video
			self.project.form.MyVideo.pause()

		elif event.button == 3:
			# show right click menu
			self.project.form.mnuPlayheadSubMenu1.showmnu(event, self, item)

		return True


	def on_button_release_x (self, item, target, event):

		""" This method drops a clip, and snaps the clip to the nearest valid track """
		# get reference to the canvas, and stop dragging the item
		canvas = item.get_canvas ()
		canvas.pointer_ungrab (item, event.time)

		# enable animated playhead
		self.enable_animated_playhead = True


	def split_images(self, pixbuf, height, max_length):
		""" Because it's not possible to resize an image to an infinate size, we sometimes
		need to split an image into many smaller pieces.  This function takes an image, and
		returns a list of pixbufs to equal the max_length"""

		# how big of chunks do we use (pixels)
		chunk_size = 1000
		image_list = []

		# get a reference to the 2 main canvas objects & theme
		remaining_pixels = max_length

		while remaining_pixels:
			# declare new image
			new_pixbuf = None

			if chunk_size < remaining_pixels:
				# resize the pixbuf
				new_pixbuf = pixbuf.scale_simple(chunk_size, height, gtk.gdk.INTERP_NEAREST)

				# subtract the pixels
				remaining_pixels = remaining_pixels - chunk_size

			else:
				# resize the pixbuf
				new_pixbuf = pixbuf.scale_simple(remaining_pixels, height, gtk.gdk.INTERP_NEAREST)

				# subtract the pixels
				remaining_pixels = 0

			# add image to list
			image_list.append(new_pixbuf)

		# return list of pixbufs
		return image_list


	def resize_image_list(self, image_list, height, new_length):
		""" Because it's not possible to resize an image to an infinate size, we sometimes
		need to split an image into many smaller pieces.  This function takes an image, and
		returns a list of pixbufs to equal the max_length"""

		# create new list
		new_image_list = []

		# get a reference to the 2 main canvas objects & theme
		remaining_pixels = new_length


		# loop through existing pixbufs
		for current_pixbuf in image_list:

			# get width of pixbuf
			pixbuf_width = current_pixbuf.get_width()

			if remaining_pixels == 0:
				pass

			# Is Last Image?
			elif pixbuf_width >= remaining_pixels:

				# resize the pixbuf
				new_pixbuf = current_pixbuf.scale_simple(remaining_pixels, height, gtk.gdk.INTERP_NEAREST)
				new_image_list.append(new_pixbuf)
				remaining_pixels = 0

			else:
				# not the last image
				# subtract the pixels
				new_image_list.append(current_pixbuf)
				remaining_pixels = remaining_pixels - pixbuf_width


		# check for additional pixbufs needed?
		if remaining_pixels > 0:
			# resize the pixbuf
			new_pixbuf = image_list[0].scale_simple(remaining_pixels, height, gtk.gdk.INTERP_NEAREST)

			# add to image list
			new_image_list.append(new_pixbuf)


		# return list of pixbufs
		return new_image_list



	def raise_transitions(self):
		"""this method loops though the children objects of this group looking 
		for the item with a specfic id."""

		# Get root group of the canvas
		canvas_right = self.project.form.MyCanvas
		root_right = canvas_right.get_root_item ()	

		# Build list of canvas IDs
		IDs = {}
		for index in range(0, root_right.get_n_children()):
			child = root_right.get_child(index)
			child_id = child.get_data ("id")

			# add to list
			IDs[str(child_id)] = child


		# loop through each transtion
		for track in self.tracks:
			for trans in track.transitions:

				# see if there is a matching transition
				if trans.unique_id in IDs:
					# raise match to the top layer
					canvas_item = IDs[trans.unique_id]
					canvas_item.raise_(None)

	def raise_play_head(self):
		""" Raise the play-head to the top """
		self.play_head.raise_(None)
		self.play_head_line.raise_(None)

	def get_valid_track(self, x1, y1):
		""" A clip must be dropped on a track.  This method returns the track 
		object that is under the clip's current position """

		# loop through each track
		for track in self.tracks:
			# get the top y and bottom y of each track
			y_top = track.y_top
			y_bottom = track.y_bottom

			# get the middle of the clip
			half_height_of_clip = 0
			middle_position = half_height_of_clip + y1

			# determine if middle of clip is contained inside this track
			if middle_position > y_top and middle_position < y_bottom:
				return track

		# return false if no valid track found
		return None

	#----------------------------------------------------------------------
	def __setstate__(self, state):
		""" This method is called when an OpenShot project file is un-pickled (i.e. opened).  It can
		    be used to update the structure of old clip classes, to make old project files compatable with
		    newer versions of OpenShot. """

		# Check for missing DEBUG attribute (which means it's an old project format)
		if 'enable_animated_playhead' not in state:
			state['enable_animated_playhead'] = False

		# update the state object with new schema changes
		self.__dict__.update(state)

