1 from Plugins.Plugin import PluginDescriptor
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Components.ServicePosition import ServicePositionGauge
6 from Components.ActionMap import HelpableActionMap
7 from Components.MenuList import MenuList
8 from Components.MultiContent import MultiContentEntryText, RT_HALIGN_RIGHT
9 from Components.ServiceEventTracker import ServiceEventTracker
10 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarCueSheetSupport
11 from Components.GUIComponent import GUIComponent
12 from enigma import eListboxPythonMultiContent, eListbox, gFont, iPlayableService
13 from Screens.FixedMenu import FixedMenu
16 def CutListEntry(where, what):
17 res = [ (where, what) ]
29 res.append(MultiContentEntryText(size=(400, 20), text = "%dh:%02dm:%02ds:%03d" % (h, m, s, ms)))
30 res.append(MultiContentEntryText(pos=(400,0), size=(130, 20), text = type, flags = RT_HALIGN_RIGHT))
34 class CutListContextMenu(FixedMenu):
47 def __init__(self, session, state, nearmark):
48 menu = [(_("back"), self.close)] #, (None, )]
50 if state == self.SHOW_STARTCUT:
51 menu.append((_("start cut here"), self.startCut))
53 menu.append((_("start cut here"), ))
55 if state == self.SHOW_ENDCUT:
56 menu.append((_("end cut here"), self.endCut))
58 menu.append((_("end cut here"), ))
60 if state == self.SHOW_DELETECUT:
61 menu.append((_("delete cut"), self.deleteCut))
63 menu.append((_("delete cut"), ))
65 menu.append((_("remove before this position"), self.removeBefore))
66 menu.append((_("remove after this position"), self.removeAfter))
68 # menu.append((None, ))
71 menu.append((_("insert mark here"), self.insertMark))
73 menu.append((_("remove this mark"), self.removeMark))
75 FixedMenu.__init__(self, session, _("Cut"), menu)
76 self.skinName = "Menu"
79 self.close(self.RET_STARTCUT)
82 self.close(self.RET_ENDCUT)
85 self.close(self.RET_DELETECUT)
88 self.close(self.RET_MARK)
91 self.close(self.RET_DELETEMARK)
93 def removeBefore(self):
94 self.close(self.RET_REMOVEBEFORE)
96 def removeAfter(self):
97 self.close(self.RET_REMOVEAFTER)
100 class CutList(GUIComponent):
101 def __init__(self, list):
102 GUIComponent.__init__(self)
103 self.l = eListboxPythonMultiContent()
105 self.l.setFont(0, gFont("Regular", 20))
106 self.onSelectionChanged = [ ]
108 def getCurrent(self):
109 return self.l.getCurrentSelection()
111 def getCurrentIndex(self):
112 return self.l.getCurrentSelectionIndex()
114 def GUIcreate(self, parent):
115 self.instance = eListbox(parent)
116 self.instance.setContent(self.l)
117 self.instance.setItemHeight(30)
118 self.instance.selectionChanged.get().append(self.selectionChanged)
120 def selectionChanged(self):
121 for x in self.onSelectionChanged:
125 self.instance.selectionChanged.get().remove(self.selectionChanged)
126 self.instance.setContent(None)
129 def invalidateEntry(self, index):
130 self.l.invalidateEntry(index)
132 def setIndex(self, index, data):
133 self.list[index] = data
134 self.invalidateEntry(index)
136 def setList(self, list):
138 self.l.setList(self.list)
140 def setSelection(self, index):
141 if self.instance is not None:
142 self.instance.moveSelectionTo(index)
144 class CutListEditor(Screen, InfoBarSeek, InfoBarCueSheetSupport):
146 <screen position="100,100" size="550,400" title="Test" >
147 <widget name="Timeline" position="10,0" size="530,40"
148 pointer="/usr/share/enigma2/position_pointer.png:3,5" />
149 <widget name="Cutlist" position="10,50" size="530,300" scrollbarMode="showOnDemand" />
151 def __init__(self, session, service):
152 self.skin = CutListEditor.skin
153 Screen.__init__(self, session)
154 InfoBarSeek.__init__(self)
155 InfoBarCueSheetSupport.__init__(self)
156 self.old_service = session.nav.getCurrentlyPlayingServiceReference()
157 session.nav.playService(service)
159 service = session.nav.getCurrentService()
160 cue = service and service.cueSheet()
162 # disable cutlists. we want to freely browse around in the movie
163 print "cut lists disabled!"
164 cue.setCutListEnable(0)
166 self.downloadCuesheet()
168 self["Timeline"] = ServicePositionGauge(self.session.nav)
169 self["Cutlist"] = CutList(self.getCutlist())
170 self["Cutlist"].onSelectionChanged.append(self.selectionChanged)
172 self["actions"] = HelpableActionMap(self, "CutListEditorActions",
174 "setIn": (self.setIn, _("Make this mark an 'in' point")),
175 "setOut": (self.setOut, _("Make this mark an 'out' point")),
176 "setMark": (self.setMark, _("Make this mark just a mark")),
177 "addMark": (self.__addMark, _("Add a mark")),
178 "removeMark": (self.__removeMark, _("Remove a mark")),
179 "leave": (self.exit, _("Exit editor")),
180 "showMenu": self.showMenu,
183 self.tutorial_seen = False
185 self.onExecBegin.append(self.showTutorial)
186 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
188 iPlayableService.evCuesheetChanged: self.refillList
191 # to track new entries we save the last version of the cutlist
193 self.cut_start = None
195 def showTutorial(self):
196 if not self.tutorial_seen:
197 self.tutorial_seen = True
198 self.session.open(MessageBox,
199 """Welcome to the Cutlist editor. It's still a bit strange to use, but anyway:
201 Seek to the start of the stuff you want to cut away. Press OK, select 'start cut'.
203 Then seek to the end, press OK, select 'end cut'. That's it.
204 """, MessageBox.TYPE_INFO)
206 def checkSkipShowHideLock(self):
209 def setType(self, index, type):
210 if len(self.cut_list):
211 self.cut_list[index] = (self.cut_list[index][0], type)
212 self["Cutlist"].setIndex(index, CutListEntry(*self.cut_list[index]))
215 m = self["Cutlist"].getCurrentIndex()
217 self.uploadCuesheet()
220 m = self["Cutlist"].getCurrentIndex()
222 self.uploadCuesheet()
225 m = self["Cutlist"].getCurrentIndex()
227 self.uploadCuesheet()
230 self.toggleMark(onlyadd=True, tolerance=90000) # do not allow two marks in <1s
232 def __removeMark(self):
233 m = self["Cutlist"].getCurrent()
239 self.session.nav.playService(self.old_service)
242 def getCutlist(self):
244 for e in self.cut_list:
245 r.append(CutListEntry(*e))
248 def selectionChanged(self):
249 where = self["Cutlist"].getCurrent()
254 seek = self.getSeek()
260 def refillList(self):
261 print "cue sheet changed, refilling"
262 self.downloadCuesheet()
264 # get the first changed entry, and select it
265 new_list = self.getCutlist()
266 self["Cutlist"].setList(new_list)
268 for i in range(min(len(new_list), len(self.last_cuts))):
269 if new_list[i] != self.last_cuts[i]:
270 self["Cutlist"].setSelection(i)
272 self.last_cuts = new_list
274 def getStateForPosition(self, pos):
277 # when first point is "in", the beginning is "out"
278 if len(self.cut_list) and self.cut_list[0][1] == 0:
281 for (where, what) in self.cut_list:
285 elif what == 1: # out
290 curpos = self.cueGetCurrentPosition()
294 self.setSeekState(self.SEEK_STATE_PAUSE)
296 self.context_position = curpos
298 self.context_nearest_mark = self.toggleMark(onlyreturn=True)
300 cur_state = self.getStateForPosition(curpos)
302 print "currently in 'IN'"
303 if self.cut_start is None or self.context_position < self.cut_start:
304 state = CutListContextMenu.SHOW_STARTCUT
306 state = CutListContextMenu.SHOW_ENDCUT
308 print "currently in 'OUT'"
309 state = CutListContextMenu.SHOW_DELETECUT
311 if self.context_nearest_mark is None:
316 self.session.openWithCallback(self.menuCallback, CutListContextMenu, state, nearmark)
318 def menuCallback(self, *result):
319 self.setSeekState(self.SEEK_STATE_PLAY)
324 if result == CutListContextMenu.RET_STARTCUT:
325 self.cut_start = self.context_position
326 elif result == CutListContextMenu.RET_ENDCUT:
327 # remove in/out marks between the new cut
328 for (where, what) in self.cut_list[:]:
329 if self.cut_start <= where <= self.context_position and what in [0,1]:
330 self.cut_list.remove((where, what))
332 bisect.insort(self.cut_list, (self.cut_start, 1))
333 bisect.insort(self.cut_list, (self.context_position, 0))
334 self.uploadCuesheet()
335 self.cut_start = None
336 elif result == CutListContextMenu.RET_DELETECUT:
340 for (where, what) in self.cut_list:
341 if what == 1 and where < self.context_position: # out
342 out_before = (where, what)
343 elif what == 0 and where < self.context_position: # in, before out
345 elif what == 0 and where > self.context_position and in_after is None:
346 in_after = (where, what)
348 if out_before is not None:
349 self.cut_list.remove(out_before)
351 if in_after is not None:
352 self.cut_list.remove(in_after)
353 self.uploadCuesheet()
354 elif result == CutListContextMenu.RET_MARK:
356 elif result == CutListContextMenu.RET_DELETEMARK:
357 self.cut_list.remove(self.context_nearest_mark)
358 self.uploadCuesheet()
359 elif result == CutListContextMenu.RET_REMOVEBEFORE:
360 # remove in/out marks before current position
361 for (where, what) in self.cut_list[:]:
362 if where <= self.context_position and what in [0,1]:
363 self.cut_list.remove((where, what))
365 bisect.insort(self.cut_list, (self.context_position, 0))
366 self.uploadCuesheet()
367 elif result == CutListContextMenu.RET_REMOVEAFTER:
368 # remove in/out marks after current position
369 for (where, what) in self.cut_list[:]:
370 if where >= self.context_position and what in [0,1]:
371 self.cut_list.remove((where, what))
373 bisect.insort(self.cut_list, (self.context_position, 1))
374 self.uploadCuesheet()
376 def main(session, service, **kwargs):
377 session.open(CutListEditor, service)
379 def Plugins(**kwargs):
380 return PluginDescriptor(name="Cutlist Editor", description=_("Cutlist editor..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)