[xiph-commits] r15170 - in trunk/subtle: . Subtle Subtle/Subtitles Subtle/Subtitles/Formats
jmesquita at svn.xiph.org
jmesquita at svn.xiph.org
Fri Aug 8 18:28:27 PDT 2008
Author: jmesquita
Date: 2008-08-08 18:28:27 -0700 (Fri, 08 Aug 2008)
New Revision: 15170
Added:
trunk/subtle/Subtle/
trunk/subtle/Subtle/GPlayer.py
trunk/subtle/Subtle/MediaInfo.py
trunk/subtle/Subtle/Subtitles/
trunk/subtle/Subtle/Subtitles/Discoverer.py
trunk/subtle/Subtle/Subtitles/Formats/
trunk/subtle/Subtle/Subtitles/Formats/Softni.py
trunk/subtle/Subtle/Subtitles/Formats/SubRip.py
trunk/subtle/Subtle/Subtitles/Formats/__init__.py
trunk/subtle/Subtle/Subtitles/Line.py
trunk/subtle/Subtle/Subtitles/Sub.py
trunk/subtle/Subtle/Subtitles/Subtitles.py
trunk/subtle/Subtle/Subtitles/__init__.py
trunk/subtle/Subtle/SubtleXML.py
trunk/subtle/Subtle/__init__.py
trunk/subtle/Subtle/subtle.glade
Log:
Ooops, the new layout was not imported on last commit.
Added: trunk/subtle/Subtle/GPlayer.py
===================================================================
--- trunk/subtle/Subtle/GPlayer.py (rev 0)
+++ trunk/subtle/Subtle/GPlayer.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,281 @@
+# This file is part of Subtle
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+import pygtk
+pygtk.require('2.0')
+
+import gobject
+gobject.threads_init()
+
+
+import pygst
+import gst
+import gst.interfaces
+
+import gtk
+
+## \file GPlayer.py
+# Documentation for GPlayer module of Subtle project.
+# \todo Add better seeking.
+
+
+## GstPlayer class.
+# Class for playing media in GStreamer.
+class GstPlayer:
+ ## Construstor
+ # \param videowidget - VideoWidget class.
+ def __init__(self, videowidget):
+ self.playing = False
+ bin = gst.Bin('my-bin')
+ self.textoverlay = gst.element_factory_make('textoverlay')
+ bin.add(self.textoverlay)
+ pad = self.textoverlay.get_pad("video_sink")
+ ghostpad = gst.GhostPad("sink", pad)
+ bin.add_pad(ghostpad)
+ color = gst.element_factory_make('ffmpegcolorspace')
+ bin.add(color)
+ scale = gst.element_factory_make('videoscale')
+ bin.add(scale)
+ self.videosink = gst.element_factory_make('autovideosink')
+ bin.add(self.videosink)
+ gst.element_link_many(self.textoverlay, color, scale, self.videosink)
+ self.player = gst.element_factory_make("playbin", "player")
+ self.player.set_property("video-sink", bin)
+ self.videowidget = videowidget
+
+ bus = self.player.get_bus()
+ bus.enable_sync_message_emission()
+ bus.add_signal_watch()
+ bus.connect('sync-message::element', self.on_sync_message)
+ bus.connect('message', self.on_message)
+ self.cur_frame = 0
+ self.rate = 1.0
+
+ def on_sync_message(self, bus, message):
+ if message.structure is None:
+ return
+ if message.structure.get_name() == 'prepare-xwindow-id':
+ self.videowidget.set_sink(message.src)
+ message.src.set_property('force-aspect-ratio', True)
+
+ def on_message(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ print "Error: %s" % err, debug
+ self.playing = False
+ elif t == gst.MESSAGE_EOS:
+ self.playing = False
+
+ def fast_forward(self):
+ """
+ Here we will fast forward the stream for as many times
+ as this is called
+ """
+ if self.rate < 8.0:
+ self.rate = self.rate*2.0
+ event = gst.event_new_seek(self.rate, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH,
+ gst.SEEK_TYPE_SET, self.query_position()[0],
+ gst.SEEK_TYPE_NONE, 0)
+
+ res = self.player.send_event(event)
+ if res:
+ gst.info("fast forwarding at rate: %f" % self.rate)
+ self.player.set_new_stream_time(0L)
+ else:
+ gst.error("change rate to %f failed" % self.rate)
+ return
+
+ def slow_motion(self):
+ """
+ Here we will slow motion the stream for as many times
+ as this is called
+ """
+ self.rate = self.rate/2.0
+ event = gst.event_new_seek(self.rate, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH,
+ gst.SEEK_TYPE_SET, self.query_position()[0],
+ gst.SEEK_TYPE_NONE, 0)
+
+ res = self.player.send_event(event)
+ if res:
+ gst.info("slowing playback to rate: %f" % self.rate)
+ self.player.set_new_stream_time(0L)
+ else:
+ gst.error("change rate to %f failed" % self.rate)
+
+ return
+
+ def get_rate(self):
+ """
+ Get the playing rate at the moment
+ """
+ return self.rate
+
+ ## Set location.
+ # Set location of the source.
+ # \param location - URI of the source.
+ def set_location(self, location):
+ self.player.set_state(gst.STATE_NULL)
+ self.player.set_property('uri', location)
+
+ ## Set Subtitle Text
+ # Set subtitle text to be overlayed.
+ # \param text - Text (may have pango tags)
+ # \param font - Pango FontDescrition for the text
+ def set_subtitle_text(self, text, font=None):
+ if font:
+ self.textoverlay.set_property('subtitle-font-desc', font)
+ self.textoverlay.set_property('text', text)
+ return
+
+ ## Get location.
+ # Get location of the source.
+ def get_location(self):
+ return self.player.get_property('uri')
+
+ def query_position(self):
+ "Returns a (position, duration) tuple"
+ try:
+ position, format = self.player.query_position(gst.FORMAT_TIME)
+ except:
+ position = gst.CLOCK_TIME_NONE
+
+ try:
+ duration, format = self.player.query_duration(gst.FORMAT_TIME)
+ except:
+ duration = gst.CLOCK_TIME_NONE
+
+ return (position, duration)
+
+ def query_frame(self, position):
+ "Query the frame position"
+ if position != gst.CLOCK_TIME_NONE:
+ pad = self.videosink.get_pad('sink')
+ caps = pad.get_negotiated_caps()
+ if caps is not None:
+ framerate = caps[0]['framerate']
+ position = float(position)/float(1000000000)
+ self.cur_frame = (float(position)*float(
+ framerate.num))/float(framerate.denom)
+ return self.cur_frame
+
+ ## Seek.
+ # Seek media.
+ # \param location - location to the seek.
+ def seek(self, location):
+ gst.debug("seeking to %r" % location)
+ event = gst.event_new_seek(self.rate, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH,
+ gst.SEEK_TYPE_SET, location,
+ gst.SEEK_TYPE_NONE, 0)
+
+ res = self.player.send_event(event)
+ if res:
+ gst.info("setting new stream time to 0")
+ self.player.set_new_stream_time(0L)
+ else:
+ gst.error("seek to %r failed" % location)
+
+ ## Pause.
+ # Media pause.
+ def pause(self):
+ gst.info("pausing player")
+ self.player.set_state(gst.STATE_PAUSED)
+ self.playing = False
+
+ ## Play.
+ # Media play.
+ def play(self):
+ """
+ Change the stream state to playing or simply
+ change its playing rate to normal rate
+ """
+ if self.rate != 1.0:
+ self.rate = 1.0
+ event = gst.event_new_seek(self.rate, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH,
+ gst.SEEK_TYPE_SET, self.query_position()[0],
+ gst.SEEK_TYPE_NONE, 0)
+
+ res = self.player.send_event(event)
+ if res:
+ gst.info("slowing playback to rate: %f" % self.rate)
+ self.player.set_new_stream_time(0L)
+ else:
+ gst.error("change rate to %f failed" % self.rate)
+ else:
+ gst.info("playing player")
+ self.player.set_state(gst.STATE_PLAYING)
+ self.playing = True
+ return
+
+ ## Stop
+ # Media stop.
+ def stop(self):
+ self.player.set_state(gst.STATE_READY)
+ self.playing = False
+ gst.info("stopped player")
+
+ ## Get state.
+ # Get current state of the media.
+ # \param timeout - time out of the operation.
+ # \raturn state of the media.
+ def get_state(self, timeout=1):
+ return self.player.get_state(timeout=timeout)
+
+ ## Is playing
+ # \return TRUE if media is playing.
+ def is_playing(self):
+ return self.playing
+
+ ## \var playing
+ # Bool variable, TRUE - if media is playing.
+
+ ## \var player
+ # GStreamer playerbin element.
+
+ ## \var videowidget
+ # GTK+ widget for video render.
+
+#==============================================================================
+## VideoWidget class.
+# VideoWidget class for render video stream on GTK+ widget.
+class VideoWidget:
+ ## Constructor.
+ # \param TArea - GTK+ drowing area widget.
+ def __init__(self, TArea):
+ self.Area=TArea
+ self.imagesink = None
+ self.Area.unset_flags(gtk.DOUBLE_BUFFERED)
+
+ ## \var Area
+ # GTK+ drowing area widget.
+
+ ## \var imagesink
+ # Sink element for
+
+ def do_expose_event(self, event):
+ if self.imagesink:
+ self.imagesink.expose()
+ return False
+ else:
+ return True
+
+ def set_sink(self, sink):
+ assert self.Area.window.xid
+ self.imagesink = sink
+ self.imagesink.set_xwindow_id(self.Area.window.xid)
Added: trunk/subtle/Subtle/MediaInfo.py
===================================================================
--- trunk/subtle/Subtle/MediaInfo.py (rev 0)
+++ trunk/subtle/Subtle/MediaInfo.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,72 @@
+# This file is part of Subtle
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import pygtk
+pygtk.require('2.0')
+import gobject
+gobject.threads_init()
+import pygst
+import gst
+from gst.extend import discoverer
+
+class Media:
+ has_audio = None
+ has_video = None
+ framerate = None
+ sourceURI = None
+ MIME = None
+ videoLengthNS = None
+ videoLengthS = None
+ videoCaps = None
+ videoWidth = None
+ videoHeight = None
+
+class MediaInfo:
+
+ def __init__(self, file, uri):
+ self.media = Media()
+ self.media.source = file
+ self.media.sourceURI = uri
+ self.discover(file)
+ self.notDone = True
+
+ def discover(self,path):
+ d = discoverer.Discoverer(path)
+ d.connect('discovered',self.cb_discover)
+ d.discover()
+
+ def cb_discover(self, d, ismedia):
+ if ismedia:
+ self.media.MIME = d.mimetype
+ if d.is_video:
+ self.media.has_video = True
+ self.media.framerate = float(d.videorate.num) \
+ / float(d.videorate.denom)
+ self.media.videoLengthNS = d.videolength
+ self.media.videoLengthS = float(d.videolength) \
+ / float(gst.MSECOND)/1000.0
+ self.media.videoCaps = d.videocaps
+ self.media.videoHeight = d.videoheight
+ self.media.videoWidth = d.videowidth
+ if d.is_audio:
+ self.media.has_audio = True
+ self.notDone = False
+
+ def poll(self):
+ return self.notDone
+
+ def getMedia(self):
+ return self.media
Added: trunk/subtle/Subtle/Subtitles/Discoverer.py
===================================================================
--- trunk/subtle/Subtle/Subtitles/Discoverer.py (rev 0)
+++ trunk/subtle/Subtle/Subtitles/Discoverer.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# discoverer.py
+#
+# Copyright 2008 Joao Mesquita <jmesquita at gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+import os, glob
+from Subtle.Subtitles import Formats
+
+discover_funcs = []
+
+format_path = os.path.dirname(Formats.__file__)
+modules = glob.glob(os.path.join(format_path, '*.py'))
+for module in modules:
+ module = __import__('Formats.' + os.path.basename(module)[:-3],
+ globals(), locals(), ['discover'], 1)
+ if hasattr(module, 'discover'):
+ discover_funcs.append(module.discover)
+
+def discoverer(file):
+ """
+ This procedure will negotiate and return the proper subtitle class to
+ handle the specific format. If it returns None, format is not yet
+ supported.
+ """
+
+ for func in discover_funcs:
+ handle = func(file)
+ if handle is not None:
+ return handle(file)
+
+
Added: trunk/subtle/Subtle/Subtitles/Formats/Softni.py
===================================================================
--- trunk/subtle/Subtle/Subtitles/Formats/Softni.py (rev 0)
+++ trunk/subtle/Subtle/Subtitles/Formats/Softni.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+#
+# Softni.py
+#
+# Copyright 2008 Joao Mesquita <jmesquita at gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+
+# This implementation is on real BAD alpha stage and should not be
+# considered by any chance ready for production.
+# A lot of study is still needed to transform the frames into timestamp
+# since this format is a bit funky.
+
+import os
+import sys
+import string
+import re
+import codecs
+
+# This is not the best option since we rely on Linux-only
+# Make use of file command to check on the file type
+try:
+ import magic
+except:
+ print "We need python-magic, otherwise, this format will not be \
+ supported"
+ sys.exit(1)
+
+from Subtle.Subtitles import Subtitles
+from Subtle.Subtitles import Sub
+
+FRAMERATE=25.00
+
+def discover(file):
+ """
+ Every subtitle should have a discover function
+ and return true if it should handle the requested
+ file.
+ """
+
+ m = magic.open(magic.MAGIC_COMPRESS | magic.MAGIC_MIME)
+ status = m.load()
+
+ if m.file(file).split('/')[0] == "text":
+ # Open file and read it
+ fd = open(file, "r")
+ data = fd.read()
+ fd.close()
+ else:
+ return
+
+ #: Test for Softni by matching the timecode
+ rawstr = r"""^(?P<ts_from>\d{2}:\d{2}:\d{2}.\d{2})\\(?P<ts_to>\d{2}:\d{2}:\d{2}.\d{2})"""
+
+ regex = re.compile(rawstr, re.MULTILINE| re.VERBOSE)
+
+ if regex.search(data):
+ return Softni
+ return
+
+class Softni(Subtitles.Subtitles):
+ """
+ This class handles the Softni file format
+ """
+ def __init__(self, filename):
+ Subtitles.Subtitles.__init__(self,filename)
+
+ # Set the file encoding
+ m = magic.open(magic.MAGIC_COMPRESS | magic.MAGIC_MIME)
+ status = m.load()
+ self.encoding = m.file(filename).split('/')[1].split('=')[1]
+
+ self.subType="Softni"
+
+ self._loadFromFile(filename)
+ return
+
+ def _loadFromFile(self, file):
+ """
+ Parse and load the subtitle using a string
+ as input
+ """
+ regex = re.compile(r"""^(?P<ts_from>\d{2}:\d{2}:\d{2}.\d{2})\\(?P<ts_to>\d{2}:\d{2}:\d{2}.\d{2})""", re.MULTILINE)
+
+ # We reopen the file here so we can
+ # iterate over the lines
+ fd = codecs.open(file, "r", self.encoding)
+ contents = fd.readlines()
+ fd.close()
+
+ # Lets set the data structure like we need it
+ info = []
+ buffer = ""
+ for line in contents:
+ if regex.search(line):
+ info.append(tuple([buffer] + line.split('\\')))
+ buffer=""
+ else:
+ buffer+=line
+
+ # Iterate all the subs and create the
+ # sub objects
+ sub_count = 0
+ for sub in info:
+ text = sub[0]
+ stime = sub[1]
+ etime = sub[2]
+ TS = Sub.Sub(text)
+ TS.start_time = self._softniFormat2Timestamp(stime)
+ TS.end_time = self._softniFormat2Timestamp(etime)
+ TS.start_frame = self._softniFormat2Frame(stime)
+ TS.end_frame = self._softniFormat2Frame(etime)
+ TS.number = sub_count
+ sub_count += 1
+ self.subs[int(self._softniFormat2Timestamp(stime))]=TS
+ self.updateKeys()
+ return
+
+ def _softniFormat2Frame(self, softniFormat):
+ """
+ Convert Softni frame format to cumulative frame counting
+ """
+ frames = ((float(softniFormat[0:2])*60*60) + \
+ (float(softniFormat[3:5])*60) + \
+ float(softniFormat[6:8]) * FRAMERATE) + \
+ float(softniFormat[9:11])
+ return frames
+
+ def _softniFormat2Timestamp(self, softniFormat):
+ """
+ Convert Softni frame format to cumulative frame counting
+ """
+ timestamp = (float(softniFormat[0:2])*60*60) + \
+ (float(softniFormat[3:5])*60) + \
+ float(softniFormat[6:8]) + \
+ (float(softniFormat[9:11])/FRAMERATE)
+ return timestamp*1000
Added: trunk/subtle/Subtle/Subtitles/Formats/SubRip.py
===================================================================
--- trunk/subtle/Subtle/Subtitles/Formats/SubRip.py (rev 0)
+++ trunk/subtle/Subtle/Subtitles/Formats/SubRip.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+#
+# SubRip.py
+#
+# Copyright 2008 Joao Mesquita <jmesquita at gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+import os
+import sys
+import string
+import re
+import codecs
+
+# This is not the best option since we rely on Linux-only
+# Make use of file command to check on the file type
+try:
+ import magic
+except:
+ print "We need python-magic, otherwise, this format will not be \
+ supported"
+ sys.exit(1)
+
+from Subtle.Subtitles import Subtitles
+from Subtle.Subtitles import Sub
+
+FRAMERATE=25.00
+
+def discover(file):
+ """
+ Every subtitle should have a discover function
+ and return true if it should handle the requested
+ file.
+ """
+
+ m = magic.open(magic.MAGIC_COMPRESS | magic.MAGIC_MIME)
+ status = m.load()
+
+ if m.file(file).split('/')[0] == "text":
+ # Open file and read it
+ fd = open(file, "r")
+ data = fd.read()
+ fd.close()
+ else:
+ return
+
+ # Test for SubRip by matching the header
+ rawstr = r"""^(?P<counter>\d+)\s*
+ ^(?P<ts_from>\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(?P<ts_to>\d{2}:\d{2}:\d{2},\d{3})\r?"""
+ regex = re.compile(rawstr,re.MULTILINE| re.VERBOSE)
+
+ if regex.search(data):
+ return SubRip
+ return
+
+class SubRip(Subtitles.Subtitles):
+ """
+ This class handles the SubRip subtitle format
+ """
+
+ ## Load subtitles.
+ # Load subtitles from file.
+ def __init__(self, filename):
+ Subtitles.Subtitles.__init__(self, filename)
+
+ # Set the file encoding
+ m = magic.open(magic.MAGIC_COMPRESS | magic.MAGIC_MIME)
+ status = m.load()
+ self.encoding = m.file(filename).split('/')[1].split('=')[1]
+
+ FILE = codecs.open(filename, 'r', self.encoding)
+ DATA = FILE.read()
+ FILE.close()
+
+ self.subType="SubRip"
+
+ self._subSRTLoadFromString(DATA)
+ return
+
+ ## Save subtitles.
+ # Save subtitles to the file.
+ # \param FN - file name.
+ # \param format - the store format of subtitles. (NOT USED YET)
+ def subSave(self, FN, format):
+ FUN=os.open(FN,os.O_WRONLY|os.O_CREAT|os.O_TRUNC)
+ N=1
+ for i in self.subKeys:
+ SUB = self.subs[int(i)]
+ Text=str(N)+"\r\n"
+ Hour, Min, Sec, MSec = self._subTime2SRTtime(SUB.start_time)
+ Text+="%02d:%02d:%02d,%03d"%(Hour, Min, Sec, MSec)
+ Text+=" --> "
+ Hour, Min, Sec, MSec = self._subTime2SRTtime(SUB.end_time)
+ Text+="%02d:%02d:%02d,%03d"%(Hour, Min, Sec, MSec)+"\r\n"
+ Text+=SUB.text+"\r\n"
+ if (SUB.text[-2]!="\r\n"):
+ Text+="\r\n"
+ os.write(FUN, Text)
+ N+=1
+ os.close(FUN)
+ return
+
+ ## Convert subtitle time to SRT format.
+ # Convert subtitle time for saving in SRT subtitles file.
+ # \param time - subtitle time.
+ # \return list of: hour, minute, second and milisecond
+ def _subTime2SRTtime(self, time):
+ tTime = time
+ MSec = tTime%1000
+ tTime /=1000
+ Sec = tTime%60
+ tTime /= 60
+ Min = tTime%60
+ Hour = tTime/60
+ return Hour, Min, Sec, MSec
+
+ ## Load SRT formated subtitles.
+ # Load SRT formated subtitles from given string.
+ # \param DATA - string of SRT subtitles.
+ def _subSRTLoadFromString(self, DATA):
+ num_sub = 0
+ if (string.find(DATA, "\r\n")==-1):
+ DATA=string.split(DATA,"\n")
+ else:
+ DATA=string.split(DATA,"\r\n")
+ i=0
+ while(i<len(DATA)):
+ if(i>=len(DATA)):
+ break
+ N = DATA[i]
+ i+=1
+ if(i>=len(DATA)):
+ break
+ Timing = DATA[i]
+ Text="";
+ i+=1
+ if(i>=len(DATA)):
+ break
+ while(DATA[i]!=""):
+ Text=Text+DATA[i]+"\n"
+ i+=1
+ i+=1
+ Text=Text[0:-1]
+ ST=int(Timing[0:2])*3600000+int(Timing[3:5])*60000+int(Timing[6:8])*1000+int(Timing[9:12])
+ ET=int(Timing[17:19])*3600000+int(Timing[20:22])*60000+int(Timing[23:25])*1000+int(Timing[26:29])
+
+ TS=Sub.Sub(Text)
+ num_sub += 1
+ #TS.text=Text
+ TS.start_time=ST
+ TS.end_time=ET
+ TS.start_frame=ST*FRAMERATE/1000
+ TS.end_frame=ET*FRAMERATE/1000
+ TS.number = num_sub
+ self.subs[int(ST)]=TS
+ self.updateKeys()
Added: trunk/subtle/Subtle/Subtitles/Formats/__init__.py
===================================================================
Added: trunk/subtle/Subtle/Subtitles/Line.py
===================================================================
--- trunk/subtle/Subtle/Subtitles/Line.py (rev 0)
+++ trunk/subtle/Subtle/Subtitles/Line.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Line.py
+#
+# Copyright 2008 Joao Mesquita <jmesquita at gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+
+class Line:
+ """
+ Each line of a subtile will have its own class to control
+ the number of characters and other features
+ """
+ def __init__(self, text):
+ """
+ Each line has its own text
+ """
+ self.text = text
+ self.length = self._count(text)
+
+ def _count(self, text):
+ """
+ We have to make our own count
+ function because of pango markups
+ and end of lines.
+ """
+ t = text.strip('\n')
+ return len(t)
Added: trunk/subtle/Subtle/Subtitles/Sub.py
===================================================================
--- trunk/subtle/Subtle/Subtitles/Sub.py (rev 0)
+++ trunk/subtle/Subtle/Subtitles/Sub.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# Sub.py
+#
+# Copyright 2008 Joao Mesquita <jmesquita at gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+import string
+
+from Line import *
+
+class Sub:
+ """
+ The Sub class, is the class that handles each subtitle
+ individually
+ """
+
+ def __init__(self,text):
+ """
+ Init all the variables
+ """
+ self.lines = []
+ # Start with 1 cos we are only called
+ # when there is at least one line
+ self.nLines = 1
+ self.start_time=None
+ self.start_frame=0
+ self.end_time=None
+ self.end_frame=0
+ self.number=None
+ self._processText(text)
+
+ def isInTime(self, time):
+ """
+ Is it time to display a subtitle?
+ """
+ if( (time>=self.start_time) and (time<=self.end_time) ):
+ return 1
+ else:
+ return 0
+
+ def _processText(self,text):
+ """
+ We should parse the full text of a subtitle and divide it
+ line by line.
+ Another getSub method exists to retrieve the full text
+ """
+ lines = text.splitlines(True)
+ self.nLines = len(lines)
+ for i in xrange(0, len(lines)):
+ self.lines.append( Line(lines[i]) )
+ return
+
+ def getSubText(self):
+ """
+ Retrieve the full subtitle text.
+ The data model is yet to be defined.
+ """
+ fullText = ''
+ for i in range(0, self.nLines):
+ fullText += self.lines[i].text
+ return fullText
+
+ def setSubText(self, text):
+ """
+ Set the subtitle text and this method will rearrange the
+ structure of lines as well as all other attributes.
+ """
+ pass
Added: trunk/subtle/Subtle/Subtitles/Subtitles.py
===================================================================
--- trunk/subtle/Subtle/Subtitles/Subtitles.py (rev 0)
+++ trunk/subtle/Subtle/Subtitles/Subtitles.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+#
+# Subtitles.py
+#
+# Copyright 2008 Joao Mesquita <jmesquita at gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+import os
+import string
+
+# Subtle imports
+from Sub import *
+
+class Subtitles:
+ """
+ This class defines all the interface for the application to handle
+ subtitles and to ease the implementation of new formats
+ """
+
+ def __init__(self,FN):
+ """
+ Initialize all the attributes needed to handle
+ all types of subtitle formats as well as their manipulation
+ """
+ self.subs={}
+ self.subKeys=[]
+ self.filename = FN
+ # TODO: Support more subtitles types
+ self.subType = None
+ self.encoding = None
+ self.framerate = None
+ return
+
+ ## Delete subtitle.
+ # Delete subtitle from subtitles array.
+ # \param time - key of subtitle in "subs" list.
+ def subDel(self, time):
+ del self.subs[time]
+ self.updateKeys()
+
+ ## Add subtitle.
+ # Add subtitle to the "subs" list.
+ # \param STime - start time of the subtitle.
+ # \param ETime - end time of the subtitle.
+ # \param Attrs - attributes of the subtitle.
+ # \param isUpdate - to update (or not) keys array of "subs" list.
+ def subAdd(self, STime, ETime, Text, Attrs, isUpdate=0):
+ TS=Sub()
+ TS.text=Text
+ TS.start_time=STime
+ TS.end_time=ETime
+ TS.Attributes=Attrs
+ self.subs[int(STime)]=TS
+ if isUpdate==1:
+ self.updateKeys()
+
+ ## Update keys array.
+ # Update array of "subs" keys.
+ def updateKeys(self):
+ self.subKeys=self.subs.keys()
+ self.subKeys.sort()
+
+ ## Update sub text.
+ # Update text for sub.
+ def updateText(self, key, text):
+ if key in self.subs.keys():
+ self.subs[key].text = text
+ else:
+ print "Subkey %s not found" % key
+
+ ## Update subtitle.
+ # Update subtitle key.
+ # \param upSubKey - subtitle to update.
+ def subUpdate(self, upSubKey):
+ Sub = self.subs[upSubKey]
+ self.subDel(upSubKey)
+ self.subAdd(Sub.start_time, Sub.end_time, Sub.text, Sub.Attributes, 1)
+
+ ## Get subtitle.
+ # Get subtitle with given time of visibility.
+ # \param time - time of requested subtitle.
+ # \return subtitle or "None".
+ def getSub(self, time):
+ i=0
+ for i in self.subKeys:
+ if(time>=i):
+ if(self.subs[i].isInTime(time)==1):
+ return self.subs[i]
+ else:
+ return None
+ return None
+
+
+ ## Get subtitle supported types.
+ # Get subtitle supported types
+ # \return supported subtitle types
+ def getSupportedTypes(self):
+ return [".srt"]
Added: trunk/subtle/Subtle/Subtitles/__init__.py
===================================================================
Added: trunk/subtle/Subtle/SubtleXML.py
===================================================================
--- trunk/subtle/Subtle/SubtleXML.py (rev 0)
+++ trunk/subtle/Subtle/SubtleXML.py 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,281 @@
+# This file is part of Subtle
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+## \file SouffleurXML.py
+# Documentation for subtitles module of Souffleur project.
+# \author Maxim Litvinov (aka DarakuTenshi) <otaky at ukr.net>
+
+import xml.dom.minidom
+
+from Subtitles import Sub
+from Subtitles import Subtitles
+
+## ProjectXML class.
+# Class for working whith XML formated project file.
+class ProjectXML:
+ ## Constructor
+ def __init__(self):
+ self.impl = xml.dom.minidom.getDOMImplementation()
+ self.doc = self.impl.createDocument(None, "souffleur", None)
+ self.root = self.doc.documentElement
+
+ rootAttr= self.doc.createAttribute("type")
+ rootAttr.nodeValue="project"
+
+ self.root.setAttributeNode(rootAttr)
+
+ versionEl = self.doc.createElement("version")
+ versionTxt = self.doc.createTextNode("0")
+ versionEl.appendChild(versionTxt)
+ self.root.appendChild(versionEl)
+
+ self.head = None
+ self.body = None
+ self.version = 0
+
+ ## \var impl
+ # DOMImplementation for XML parsing.
+
+ ## \var doc
+ # Document XML object.
+
+ ## \var root
+ # Root element ("souffleur" section) in the object.
+
+ ## \var head
+ # Object of the "head" section in the XML.
+
+ ## \var body
+ # Object of the "body" section in the XML.
+
+ ## \var version
+ # Version of the pfoject file format.
+
+#==============================================================================
+ ## Load XML file.
+ # Load XML tree from the file.
+ # \param fileName - name of the XML project file.
+ # \return self object or None.
+ def load(self, fileName):
+ self.root = None
+ self.head = None
+ self.body = None
+ self.version = None
+ self.doc = xml.dom.minidom.parse(fileName)
+ if self.doc.documentElement.nodeName != "souffleur":
+ return None
+ self.root=self.doc.documentElement
+ for i in self.root.childNodes:
+ if i.nodeName=="head":
+ self.head=i
+ elif i.nodeName=="body":
+ self.body=i
+ elif i.nodeName=="version":
+ self.version = i.childNodes[0].nodeValue
+ return self
+
+#==============================================================================
+ ## Write XML.
+ # Write XML data to the file.
+ # \param fileName - name of file to store data.
+ def write(self, fileName):
+ HDLR=file(fileName, "w")
+ self.doc.writexml(HDLR)
+ HDLR.close()
+
+#==============================================================================
+ ## Add variable head.
+ # Add some variable to the head section.
+ # \param attrName - name of the attribute.
+ # \param attrValue - value of the attribute.
+ def addHeadInfo(self, attrName, attrValue):
+ if not self.head:
+ self.head=self.doc.createElement("head")
+ self.root.appendChild(self.head)
+
+ if not attrName or not attrValue:
+ return
+
+ attrEl = self.doc.createElement(attrName)
+ attrTxt = self.doc.createTextNode(attrValue)
+ attrEl.appendChild(attrTxt)
+ self.head.appendChild(attrEl)
+
+#==============================================================================
+ ## Add media.
+ # Add media info to the body section.
+ # \param media - Media class instance.
+ def addMedia(self, media):
+ if not media:
+ return
+ if type(media)!=type(Media()):
+ return
+ if not self.body:
+ self.body=self.doc.createElement("body")
+ self.root.appendChild(self.body)
+
+ data = self.doc.createElement("data")
+ self.body.appendChild(data)
+
+ source = self.doc.createElement("source")
+ sType= self.doc.createAttribute("type")
+ sType.nodeValue=media.MIME
+ source.setAttributeNode(sType)
+ sTxt = self.doc.createTextNode(media.source)
+ source.appendChild(sTxt)
+ data.appendChild(source)
+
+ for i in media.Streams:
+ tmpMedia = self.doc.createElement("media")
+ data.appendChild(tmpMedia)
+
+ tmpEl = self.doc.createElement("type")
+ tmpTxt = self.doc.createTextNode(i.MIME)
+ tmpEl.appendChild(tmpTxt)
+ tmpMedia.appendChild(tmpEl)
+
+ tmpEl = self.doc.createElement("name")
+ tmpTxt = self.doc.createTextNode(i.Name)
+ tmpEl.appendChild(tmpTxt)
+ tmpMedia.appendChild(tmpEl)
+
+ tmpEl = self.doc.createElement("id")
+ tmpTxt = self.doc.createTextNode(str(i.ID))
+ tmpEl.appendChild(tmpTxt)
+ tmpMedia.appendChild(tmpEl)
+
+ if not i.attrs:
+ continue
+
+ attrs = self.doc.createElement("attrs")
+ tmpMedia.appendChild(attrs)
+ for j in i.attrs.keys():
+ tmpEl = self.doc.createElement(j)
+ tmpTxt = self.doc.createTextNode(i.attrs[j])
+ tmpEl.appendChild(tmpTxt)
+ attrs.appendChild(tmpEl)
+
+#==============================================================================
+ ## Add subtitles.
+ # Add subtitles to the body section.
+ # \param subtitle - Subtitles class instance.
+ def addSubtitle(self, subtitle):
+ if not subtitle:
+ return
+ if type(subtitle)!=type(Subtitles()):
+ return
+ if not self.body:
+ self.body=self.doc.createElement("body")
+ self.root.appendChild(self.body)
+
+ data = self.doc.createElement("subtitles")
+ self.body.appendChild(data)
+
+ source = self.doc.createElement("source")
+ sTxt = self.doc.createTextNode(str(subtitle.subSource))
+ source.appendChild(sTxt)
+ data.appendChild(source)
+
+ for i in subtitle.subKeys:
+ sub = self.doc.createElement("sub")
+ tmpEl = self.doc.createElement("start")
+ tmpTxt = self.doc.createTextNode(str(subtitle.subs[i].start_time))
+ tmpEl.appendChild(tmpTxt)
+ sub.appendChild(tmpEl)
+ tmpEl = self.doc.createElement("end")
+ tmpTxt = self.doc.createTextNode(str(subtitle.subs[i].end_time))
+ tmpEl.appendChild(tmpTxt)
+ sub.appendChild(tmpEl)
+ tmpEl = self.doc.createElement("text")
+ tmpTxt = self.doc.createTextNode(str(subtitle.subs[i].text))
+ tmpEl.appendChild(tmpTxt)
+ sub.appendChild(tmpEl)
+ data.appendChild(sub)
+
+#==============================================================================
+ ##Get head
+ # Get list of the head section attributes.
+ # \return list of the attrName => attrValue
+ def getHead(self):
+ if not self.head:
+ return None
+ ret={}
+ for i in self.head.childNodes:
+ ret[i.nodeName]=i.childNodes[0].nodeValue
+ return ret
+
+#==============================================================================
+ ## Get media.
+ # Get media info from XML.
+ # \return List of the Media class.
+ def getMedia(self):
+ if not self.body:
+ return None
+ ret=[]
+ for i in self.body.childNodes:
+ if i.nodeName=="data":
+ tMedia=Media()
+ for j in i.childNodes:
+ if j.nodeName=="source":
+ mType=j.attributes["type"]
+ if not mType:
+ return None
+ tMedia.MIME=mType.nodeValue
+ tMedia.source=j.childNodes[0].nodeValue
+ elif j.nodeName=="media":
+ tStream = Stream()
+ for k in j.childNodes:
+ nodeName = k.nodeName
+ if nodeName == "type":
+ tStream.MIME = k.childNodes[0].nodeValue
+ elif nodeName == "id":
+ tStream.ID = k.childNodes[0].nodeValue
+ elif nodeName == "name":
+ tStream.Name = k.childNodes[0].nodeValue
+ elif nodeName == "attrs":
+ for l in k.childNodes:
+ tStream.addAttr(l.nodeName, l.childNodes[0].nodeValue)
+ tMedia.addStream(tStream)
+ ret.append(tMedia)
+ return ret
+
+#==============================================================================
+ ##Get subtitles.
+ # Get subtitles from XML project file.
+ # \raturn Array of the Subtitles.
+ def getSubtitle(self):
+ if not self.body:
+ return None
+ ret=[]
+ for i in self.body.childNodes:
+ if i.nodeName=="subtitles":
+ tSubtitles=Subtitles()
+ for j in i.childNodes:
+ if j.nodeName=="source":
+ tSubtitles.subSource=j.childNodes[0].nodeValue
+ elif j.nodeName=="sub":
+ tSub=Sub()
+ for k in j.childNodes:
+ nodeName = k.nodeName
+ if nodeName == "start":
+ tSub.start_time=int(k.childNodes[0].nodeValue)
+ elif nodeName == "end":
+ tSub.end_time=int(k.childNodes[0].nodeValue)
+ elif nodeName == "text":
+ tSub.text=str(k.childNodes[0].nodeValue)
+ tSubtitles.subs[tSub.start_time]=tSub
+ tSubtitles.updateKeys()
+ ret.append(tSubtitles)
+ return ret
Added: trunk/subtle/Subtle/__init__.py
===================================================================
Added: trunk/subtle/Subtle/subtle.glade
===================================================================
--- trunk/subtle/Subtle/subtle.glade (rev 0)
+++ trunk/subtle/Subtle/subtle.glade 2008-08-09 01:28:27 UTC (rev 15170)
@@ -0,0 +1,1319 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="MAIN_WINDOW">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Subtle</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <signal name="destroy" handler="gtk_main_quit"/>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuBar" id="MAIN_MENU">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_FILE_MENU">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="MAIN_FILE_MENU_menu">
+ <child>
+ <widget class="GtkImageMenuItem" id="MAIN_FILE_NEW">
+ <property name="sensitive">False</property>
+ <property name="label">gtk-new</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_main_file_new_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="MAIN_FILE_OPEN">
+ <property name="sensitive">False</property>
+ <property name="label">gtk-open</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_main_file_open_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="MAIN_FILE_SAVE">
+ <property name="sensitive">False</property>
+ <property name="label">gtk-save</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_main_file_save_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="MAIN_FILE_AS">
+ <property name="sensitive">False</property>
+ <property name="label">gtk-save-as</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_main_file_save_as_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="MAIN_FILE_QUIT">
+ <property name="visible">True</property>
+ <property name="label">gtk-quit</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_main_file_quit_activate"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_VIEW">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="MAIN_VIEW_menu">
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_VIEW_STREAMS">
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">_Streams window</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_MAIN_VIEW_STREAMS_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_VIEW_STREAMS_PANE">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Project _Pane</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_MAIN_VIEW_STREAMS_PANE_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_VIEW_SUBTITLES">
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">S_ubtitles window</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_MAIN_VIEW_SUBTITLES_activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_VIEW_SUBTITLES1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">S_ubtitle Pane</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_MAIN_VIEW_SUBTITLES_activate"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_HELP_MENU">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="MAIN_HELP_MENU_menu">
+ <child>
+ <widget class="GtkMenuItem" id="MAIN_HELP_ABOUT">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_About</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_main_help_about_activate"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkHPaned" id="hpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="position">245</property>
+ <property name="position_set">True</property>
+ <child>
+ <widget class="GtkVBox" id="subtitle_pane">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_HIDE_SUBLIST">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-close</property>
+ <signal name="clicked" handler="on_TOOL_HIDE_SUBLIST_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DETACH_SUBLIST">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-leave-fullscreen</property>
+ <signal name="clicked" handler="on_TOOL_DETACH_SUBLIST_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar5">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_INS_B4_SUB">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-sort-ascending</property>
+ <signal name="clicked" handler="on_TOOL_INS_B4_SUB_clicked"/>
+ <accelerator key="Return" modifiers="GDK_SHIFT_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_INS_AFTER_SUB">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-sort-descending</property>
+ <signal name="clicked" handler="on_TOOL_INS_AFTER_SUB_clicked"/>
+ <accelerator key="Return" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DEL_SUBS">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-delete</property>
+ <signal name="clicked" handler="on_TOOL_DEL_SUBS_clicked"/>
+ <accelerator key="D" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_SAVE_STREAM">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-save</property>
+ <signal name="clicked" handler="on_TOOL_SAVE_STREAM_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkSeparatorToolItem" id="separatortoolitem2">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_IN_SUB">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Timecode IN (ALT+C)</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-down</property>
+ <signal name="clicked" handler="on_TOOL_IN_SUB_clicked"/>
+ <accelerator key="c" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ <accelerator key="C" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_OUT_SUB">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Timecode OUT (ALT+V)</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-up</property>
+ <signal name="clicked" handler="on_TOOL_OUT_SUB_clicked"/>
+ <accelerator key="V" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ <accelerator key="v" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkTreeView" id="LIST_SUBS">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="reorderable">True</property>
+ <signal name="button_press_event" handler="on_LIST_SUBS_button_press_event"/>
+ <signal name="button_release_event" handler="on_LIST_SUBS_button_release_event"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="video_pane">
+ <property name="width_request">640</property>
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar9">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_HIDE_VIDEO">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-close</property>
+ <signal name="clicked" handler="on_TOOL_HIDE_VIDEO_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DETACH_VIDEO">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-leave-fullscreen</property>
+ <signal name="clicked" handler="on_TOOL_DETACH_VIDEO_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkDrawingArea" id="VIDEO_OUT_PUT">
+ <property name="width_request">640</property>
+ <property name="height_request">320</property>
+ <property name="visible">True</property>
+ <signal name="expose_event" handler="on_VIDEO_OUT_PUT_expose_event"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkDrawingArea" id="AUDIO_GPAPH">
+ <property name="height_request">64</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="VIDEO_TOOLS">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_SM">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Slow Motion</property>
+ <property name="stock_id">gtk-media-previous</property>
+ <signal name="clicked" handler="on_TOOL_SM_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_PLAY">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-media-play</property>
+ <signal name="clicked" handler="on_TOOL_PLAY_clicked"/>
+ <accelerator key="space" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_STOP">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-media-stop</property>
+ <signal name="clicked" handler="on_TOOL_STOP_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_FF">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Fast Forward</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-media-next</property>
+ <signal name="clicked" handler="on_TOOL_FF_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkSeparatorToolItem" id="toolbutton1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_SEEK_REWIND">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Seek video backward</property>
+ <property name="stock_id">gtk-media-rewind</property>
+ <signal name="clicked" handler="on_TOOL_SEEK_REWIND_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_SEEK_FORWARD">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Seek video forward</property>
+ <property name="stock_id">gtk-media-forward</property>
+ <signal name="clicked" handler="on_TOOL_SEEK_FORWARD_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkComboBox" id="COMBO_SEEK_TYPE">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">What unit to use when seeking</property>
+ <property name="items" translatable="yes">Frames
+Seconds
+Nanoseconds
+Minutes</property>
+ <signal name="changed" handler="on_COMBO_SEEK_TYPE_changed"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkSpinButton" id="spin_seek_value">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="adjustment">1 0 100 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="border_width">4</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkLabel" id="LABEL_HOUR">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">00</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">:</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="LABEL_MIN">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">00</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">:</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="LABEL_SEC">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">00</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">.</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="LABEL_MSEC">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">000000000</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">(</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="lbl_cur_fps">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">00000</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">)</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHScale" id="MEDIA_ADJUSTMENT">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">0.20000000298000001 0 100 0.10000000149 0 0</property>
+ <property name="draw_value">False</property>
+ <signal name="button_press_event" handler="on_MEDIA_ADJUSTMENT_button_press_event"/>
+ <signal name="change_value" handler="on_MEDIA_ADJUSTMENT_change_value"/>
+ <signal name="button_release_event" handler="on_MEDIA_ADJUSTMENT_button_release_event"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkVPaned" id="vpaned2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkVBox" id="subedit_pane1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_HIDE_SUBEDIT">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-close</property>
+ <signal name="clicked" handler="on_TOOL_HIDE_SUBEDIT_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DETACH_SUBEDIT1">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-leave-fullscreen</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkToggleButton" id="tgl_mode">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Online Mode</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <signal name="toggled" handler="on_tgl_mode_toggled"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkTextView" id="txt_subedit">
+ <property name="height_request">35</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="justification">GTK_JUSTIFY_CENTER</property>
+ <signal name="key_release_event" handler="on_txt_subedit_key_release_event"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes"><b>Subtitle Edition</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="streams_pane">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar11">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_HIDE_STREAMS">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-close</property>
+ <signal name="clicked" handler="on_TOOL_HIDE_STREAMS_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DETACH_STREAMS">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock_id">gtk-leave-fullscreen</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar13">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_ADD_STREAM">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-add</property>
+ <signal name="clicked" handler="on_TOOL_ADD_STREAM_clicked"/>
+ <accelerator key="a" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_NEW_STREAM">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-new</property>
+ <signal name="clicked" handler="on_TOOL_NEW_STREAM_clicked"/>
+ <accelerator key="n" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_MOD_STREAM">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-edit</property>
+ <signal name="clicked" handler="on_TOOL_MOD_STREAM_clicked"/>
+ <accelerator key="e" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DEL_STREAM">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-delete</property>
+ <signal name="clicked" handler="on_TOOL_DEL_STREAM_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="LIST_STREAMS">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes"><b>Project</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="STREAM_WINDOW">
+ <property name="width_request">240</property>
+ <property name="height_request">320</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Streams</property>
+ <property name="destroy_with_parent">True</property>
+ <signal name="delete_event" handler="on_STREAM_WINDOW_delete_event"/>
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar2">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_ADD_STREAM1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-add</property>
+ <signal name="clicked" handler="on_TOOL_ADD_STREAM_clicked"/>
+ <accelerator key="a" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_NEW_STREAM1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-new</property>
+ <signal name="clicked" handler="on_TOOL_NEW_STREAM_clicked"/>
+ <accelerator key="n" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_MOD_STREAM1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-edit</property>
+ <signal name="clicked" handler="on_TOOL_MOD_STREAM_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DEL_STREAM1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-delete</property>
+ <signal name="clicked" handler="on_TOOL_DEL_STREAM_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="LIST_STREAMS1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="SUBS_LIST">
+ <property name="width_request">480</property>
+ <property name="height_request">320</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Subtitles list</property>
+ <signal name="delete_event" handler="on_SUBS_LIST_delete_event"/>
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar3">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_ICONS</property>
+ <property name="icon_size">GTK_ICON_SIZE_MENU</property>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_INS_B4_SUB1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-sort-ascending</property>
+ <signal name="clicked" handler="on_TOOL_INS_B4_SUB_clicked"/>
+ <accelerator key="Return" modifiers="GDK_SHIFT_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_INS_AFTER_SUB1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-sort-descending</property>
+ <signal name="clicked" handler="on_TOOL_INS_AFTER_SUB_clicked"/>
+ <accelerator key="Return" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_DEL_SUBS1">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-delete</property>
+ <signal name="clicked" handler="on_TOOL_DEL_SUBS_clicked"/>
+ <accelerator key="D" modifiers="GDK_CONTROL_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_SAVE_STREAM1">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-save</property>
+ <signal name="clicked" handler="on_TOOL_SAVE_STREAM_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkSeparatorToolItem" id="separatortoolitem4">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_IN_SUB1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Timecode IN (ALT+C)</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-down</property>
+ <signal name="clicked" handler="on_TOOL_IN_SUB_clicked"/>
+ <accelerator key="c" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ <accelerator key="C" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="TOOL_OUT_SUB1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Timecode OUT (ALT+V)</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-up</property>
+ <signal name="clicked" handler="on_TOOL_OUT_SUB_clicked"/>
+ <accelerator key="V" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ <accelerator key="v" modifiers="GDK_MOD1_MASK" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkTreeView" id="LIST_SUBS1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="reorderable">True</property>
+ <signal name="cursor_changed" handler="on_LIST_SUBS_cursor_changed"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkFileChooserDialog" id="OPEN_MEDIA">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="show_hidden">True</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">24</property>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="OPEN_BUTTON_CANCEL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-6</property>
+ <signal name="clicked" handler="on_OPEN_BUTTON_CANCEL_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="OPEN_BUTTON_OPEN">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="label">gtk-open</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-5</property>
+ <signal name="clicked" handler="on_OPEN_BUTTON_OPEN_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkFileChooserDialog" id="SAVE_OPEN_PFILE">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_CENTER</property>
+ <property name="show_hidden">True</property>
+ <property name="do_overwrite_confirmation">True</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="spacing">24</property>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="PROJECT_BUTTON_CANCEL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-6</property>
+ <signal name="clicked" handler="on_PROJECT_BUTTON_CANCEL_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="PROJECT_BUTTON_OK">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="label">gtk-open</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-5</property>
+ <signal name="clicked" handler="on_PROJECT_BUTTON_OK_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkDialog" id="NEW_SUBTITLE">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkIconView" id="iconview1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="btnOK">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
More information about the commits
mailing list