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 GUI_WIDGET = eListbox
116 def postWidgetCreate(self, instance):
117 instance.setContent(self.l)
118 instance.setItemHeight(30)
119 instance.selectionChanged.get().append(self.selectionChanged)
121 def selectionChanged(self):
122 for x in self.onSelectionChanged:
125 def invalidateEntry(self, index):
126 self.l.invalidateEntry(index)
128 def setIndex(self, index, data):
129 self.list[index] = data
130 self.invalidateEntry(index)
132 def setList(self, list):
134 self.l.setList(self.list)
136 def setSelection(self, index):
137 if self.instance is not None:
138 self.instance.moveSelectionTo(index)
140 class CutListEditor(Screen, InfoBarSeek, InfoBarCueSheetSupport):
142 <screen position="100,100" size="550,400" title="Test" >
143 <widget name="Timeline" position="10,0" size="530,40"
144 pointer="/usr/share/enigma2/position_pointer.png:3,5" />
145 <widget name="Cutlist" position="10,50" size="530,300" scrollbarMode="showOnDemand" />
147 def __init__(self, session, service):
148 self.skin = CutListEditor.skin
149 Screen.__init__(self, session)
150 InfoBarSeek.__init__(self)
151 InfoBarCueSheetSupport.__init__(self)
152 self.old_service = session.nav.getCurrentlyPlayingServiceReference()
153 session.nav.playService(service)
155 service = session.nav.getCurrentService()
156 cue = service and service.cueSheet()
158 # disable cutlists. we want to freely browse around in the movie
159 print "cut lists disabled!"
160 cue.setCutListEnable(0)
162 self.downloadCuesheet()
164 self["Timeline"] = ServicePositionGauge(self.session.nav)
165 self["Cutlist"] = CutList(self.getCutlist())
166 self["Cutlist"].onSelectionChanged.append(self.selectionChanged)
168 self["actions"] = HelpableActionMap(self, "CutListEditorActions",
170 "setIn": (self.setIn, _("Make this mark an 'in' point")),
171 "setOut": (self.setOut, _("Make this mark an 'out' point")),
172 "setMark": (self.setMark, _("Make this mark just a mark")),
173 "addMark": (self.__addMark, _("Add a mark")),
174 "removeMark": (self.__removeMark, _("Remove a mark")),
175 "leave": (self.exit, _("Exit editor")),
176 "showMenu": self.showMenu,
179 self.tutorial_seen = False
181 self.onExecBegin.append(self.showTutorial)
182 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
184 iPlayableService.evCuesheetChanged: self.refillList
187 # to track new entries we save the last version of the cutlist
189 self.cut_start = None
191 def showTutorial(self):
192 if not self.tutorial_seen:
193 self.tutorial_seen = True
194 self.session.open(MessageBox,
195 """Welcome to the Cutlist editor. It's still a bit strange to use, but anyway:
197 Seek to the start of the stuff you want to cut away. Press OK, select 'start cut'.
199 Then seek to the end, press OK, select 'end cut'. That's it.
200 """, MessageBox.TYPE_INFO)
202 def checkSkipShowHideLock(self):
205 def setType(self, index, type):
206 if len(self.cut_list):
207 self.cut_list[index] = (self.cut_list[index][0], type)
208 self["Cutlist"].setIndex(index, CutListEntry(*self.cut_list[index]))
211 m = self["Cutlist"].getCurrentIndex()
213 self.uploadCuesheet()
216 m = self["Cutlist"].getCurrentIndex()
218 self.uploadCuesheet()
221 m = self["Cutlist"].getCurrentIndex()
223 self.uploadCuesheet()
226 self.toggleMark(onlyadd=True, tolerance=90000) # do not allow two marks in <1s
228 def __removeMark(self):
229 m = self["Cutlist"].getCurrent()
235 self.session.nav.playService(self.old_service)
238 def getCutlist(self):
240 for e in self.cut_list:
241 r.append(CutListEntry(*e))
244 def selectionChanged(self):
245 where = self["Cutlist"].getCurrent()
250 seek = self.getSeek()
256 def refillList(self):
257 print "cue sheet changed, refilling"
258 self.downloadCuesheet()
260 # get the first changed entry, and select it
261 new_list = self.getCutlist()
262 self["Cutlist"].setList(new_list)
264 for i in range(min(len(new_list), len(self.last_cuts))):
265 if new_list[i] != self.last_cuts[i]:
266 self["Cutlist"].setSelection(i)
268 self.last_cuts = new_list
270 def getStateForPosition(self, pos):
273 # when first point is "in", the beginning is "out"
274 if len(self.cut_list) and self.cut_list[0][1] == 0:
277 for (where, what) in self.cut_list:
281 elif what == 1: # out
286 curpos = self.cueGetCurrentPosition()
290 self.setSeekState(self.SEEK_STATE_PAUSE)
292 self.context_position = curpos
294 self.context_nearest_mark = self.toggleMark(onlyreturn=True)
296 cur_state = self.getStateForPosition(curpos)
298 print "currently in 'IN'"
299 if self.cut_start is None or self.context_position < self.cut_start:
300 state = CutListContextMenu.SHOW_STARTCUT
302 state = CutListContextMenu.SHOW_ENDCUT
304 print "currently in 'OUT'"
305 state = CutListContextMenu.SHOW_DELETECUT
307 if self.context_nearest_mark is None:
312 self.session.openWithCallback(self.menuCallback, CutListContextMenu, state, nearmark)
314 def menuCallback(self, *result):
315 self.setSeekState(self.SEEK_STATE_PLAY)
320 if result == CutListContextMenu.RET_STARTCUT:
321 self.cut_start = self.context_position
322 elif result == CutListContextMenu.RET_ENDCUT:
323 # remove in/out marks between the new cut
324 for (where, what) in self.cut_list[:]:
325 if self.cut_start <= where <= self.context_position and what in [0,1]:
326 self.cut_list.remove((where, what))
328 bisect.insort(self.cut_list, (self.cut_start, 1))
329 bisect.insort(self.cut_list, (self.context_position, 0))
330 self.uploadCuesheet()
331 self.cut_start = None
332 elif result == CutListContextMenu.RET_DELETECUT:
336 for (where, what) in self.cut_list:
337 if what == 1 and where < self.context_position: # out
338 out_before = (where, what)
339 elif what == 0 and where < self.context_position: # in, before out
341 elif what == 0 and where > self.context_position and in_after is None:
342 in_after = (where, what)
344 if out_before is not None:
345 self.cut_list.remove(out_before)
347 if in_after is not None:
348 self.cut_list.remove(in_after)
349 self.uploadCuesheet()
350 elif result == CutListContextMenu.RET_MARK:
352 elif result == CutListContextMenu.RET_DELETEMARK:
353 self.cut_list.remove(self.context_nearest_mark)
354 self.uploadCuesheet()
355 elif result == CutListContextMenu.RET_REMOVEBEFORE:
356 # remove in/out marks before current position
357 for (where, what) in self.cut_list[:]:
358 if where <= self.context_position and what in [0,1]:
359 self.cut_list.remove((where, what))
361 bisect.insort(self.cut_list, (self.context_position, 0))
362 self.uploadCuesheet()
363 elif result == CutListContextMenu.RET_REMOVEAFTER:
364 # remove in/out marks after current position
365 for (where, what) in self.cut_list[:]:
366 if where >= self.context_position and what in [0,1]:
367 self.cut_list.remove((where, what))
369 bisect.insort(self.cut_list, (self.context_position, 1))
370 self.uploadCuesheet()
372 def main(session, service, **kwargs):
373 session.open(CutListEditor, service)
375 def Plugins(**kwargs):
376 return PluginDescriptor(name="Cutlist Editor", description=_("Cutlist editor..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)