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) ]
31 res.append(MultiContentEntryText(size=(400, 20), text = "%dh:%02dm:%02ds:%03d" % (h, m, s, ms)))
32 res.append(MultiContentEntryText(pos=(400,0), size=(130, 20), text = type, flags = RT_HALIGN_RIGHT))
36 class CutListContextMenu(FixedMenu):
49 def __init__(self, session, state, nearmark):
50 menu = [(_("back"), self.close)] #, (None, )]
52 if state == self.SHOW_STARTCUT:
53 menu.append((_("start cut here"), self.startCut))
55 menu.append((_("start cut here"), ))
57 if state == self.SHOW_ENDCUT:
58 menu.append((_("end cut here"), self.endCut))
60 menu.append((_("end cut here"), ))
62 if state == self.SHOW_DELETECUT:
63 menu.append((_("delete cut"), self.deleteCut))
65 menu.append((_("delete cut"), ))
67 menu.append((_("remove before this position"), self.removeBefore))
68 menu.append((_("remove after this position"), self.removeAfter))
70 # menu.append((None, ))
73 menu.append((_("insert mark here"), self.insertMark))
75 menu.append((_("remove this mark"), self.removeMark))
77 FixedMenu.__init__(self, session, _("Cut"), menu)
78 self.skinName = "Menu"
81 self.close(self.RET_STARTCUT)
84 self.close(self.RET_ENDCUT)
87 self.close(self.RET_DELETECUT)
90 self.close(self.RET_MARK)
93 self.close(self.RET_DELETEMARK)
95 def removeBefore(self):
96 self.close(self.RET_REMOVEBEFORE)
98 def removeAfter(self):
99 self.close(self.RET_REMOVEAFTER)
102 class CutList(GUIComponent):
103 def __init__(self, list):
104 GUIComponent.__init__(self)
105 self.l = eListboxPythonMultiContent()
107 self.l.setFont(0, gFont("Regular", 20))
108 self.onSelectionChanged = [ ]
110 def getCurrent(self):
111 return self.l.getCurrentSelection()
113 def getCurrentIndex(self):
114 return self.l.getCurrentSelectionIndex()
116 GUI_WIDGET = eListbox
118 def postWidgetCreate(self, instance):
119 instance.setContent(self.l)
120 instance.setItemHeight(30)
121 instance.selectionChanged.get().append(self.selectionChanged)
123 def selectionChanged(self):
124 for x in self.onSelectionChanged:
127 def invalidateEntry(self, index):
128 self.l.invalidateEntry(index)
130 def setIndex(self, index, data):
131 self.list[index] = data
132 self.invalidateEntry(index)
134 def setList(self, list):
136 self.l.setList(self.list)
138 def setSelection(self, index):
139 if self.instance is not None:
140 self.instance.moveSelectionTo(index)
142 class CutListEditor(Screen, InfoBarSeek, InfoBarCueSheetSupport):
144 <screen position="100,100" size="550,400" title="Test" >
145 <widget name="Timeline" position="10,0" size="530,40"
146 pointer="/usr/share/enigma2/position_pointer.png:3,5" foregroundColor="#225b7395" />
147 <widget name="Cutlist" position="10,50" size="530,300" scrollbarMode="showOnDemand" />
149 def __init__(self, session, service):
150 self.skin = CutListEditor.skin
151 Screen.__init__(self, session)
152 InfoBarSeek.__init__(self)
153 InfoBarCueSheetSupport.__init__(self)
154 self.old_service = session.nav.getCurrentlyPlayingServiceReference()
155 session.nav.playService(service)
157 service = session.nav.getCurrentService()
158 cue = service and service.cueSheet()
160 # disable cutlists. we want to freely browse around in the movie
161 print "cut lists disabled!"
162 cue.setCutListEnable(0)
164 self.downloadCuesheet()
166 self["Timeline"] = ServicePositionGauge(self.session.nav)
167 self["Cutlist"] = CutList(self.getCutlist())
168 self["Cutlist"].onSelectionChanged.append(self.selectionChanged)
170 self["actions"] = HelpableActionMap(self, "CutListEditorActions",
172 "setIn": (self.setIn, _("Make this mark an 'in' point")),
173 "setOut": (self.setOut, _("Make this mark an 'out' point")),
174 "setMark": (self.setMark, _("Make this mark just a mark")),
175 "addMark": (self.__addMark, _("Add a mark")),
176 "removeMark": (self.__removeMark, _("Remove a mark")),
177 "leave": (self.exit, _("Exit editor")),
178 "showMenu": self.showMenu,
181 self.tutorial_seen = False
183 self.onExecBegin.append(self.showTutorial)
184 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
186 iPlayableService.evCuesheetChanged: self.refillList
189 # to track new entries we save the last version of the cutlist
191 self.cut_start = None
193 def showTutorial(self):
194 if not self.tutorial_seen:
195 self.tutorial_seen = True
196 self.session.open(MessageBox,
197 """Welcome to the Cutlist editor. It's still a bit strange to use, but anyway:
199 Seek to the start of the stuff you want to cut away. Press OK, select 'start cut'.
201 Then seek to the end, press OK, select 'end cut'. That's it.
202 """, MessageBox.TYPE_INFO)
204 def checkSkipShowHideLock(self):
207 def setType(self, index, type):
208 if len(self.cut_list):
209 self.cut_list[index] = (self.cut_list[index][0], type)
210 self["Cutlist"].setIndex(index, CutListEntry(*self.cut_list[index]))
213 m = self["Cutlist"].getCurrentIndex()
215 self.uploadCuesheet()
218 m = self["Cutlist"].getCurrentIndex()
220 self.uploadCuesheet()
223 m = self["Cutlist"].getCurrentIndex()
225 self.uploadCuesheet()
228 self.toggleMark(onlyadd=True, tolerance=90000) # do not allow two marks in <1s
230 def __removeMark(self):
231 m = self["Cutlist"].getCurrent()
237 self.session.nav.playService(self.old_service)
240 def getCutlist(self):
242 for e in self.cut_list:
243 r.append(CutListEntry(*e))
246 def selectionChanged(self):
247 where = self["Cutlist"].getCurrent()
252 seek = self.getSeek()
258 def refillList(self):
259 print "cue sheet changed, refilling"
260 self.downloadCuesheet()
262 # get the first changed entry, and select it
263 new_list = self.getCutlist()
264 self["Cutlist"].setList(new_list)
266 for i in range(min(len(new_list), len(self.last_cuts))):
267 if new_list[i] != self.last_cuts[i]:
268 self["Cutlist"].setSelection(i)
270 self.last_cuts = new_list
272 def getStateForPosition(self, pos):
275 # when first point is "in", the beginning is "out"
276 if len(self.cut_list) and self.cut_list[0][1] == 0:
279 for (where, what) in self.cut_list:
283 elif what == 1: # out
288 curpos = self.cueGetCurrentPosition()
292 self.setSeekState(self.SEEK_STATE_PAUSE)
294 self.context_position = curpos
296 self.context_nearest_mark = self.toggleMark(onlyreturn=True)
298 cur_state = self.getStateForPosition(curpos)
300 print "currently in 'IN'"
301 if self.cut_start is None or self.context_position < self.cut_start:
302 state = CutListContextMenu.SHOW_STARTCUT
304 state = CutListContextMenu.SHOW_ENDCUT
306 print "currently in 'OUT'"
307 state = CutListContextMenu.SHOW_DELETECUT
309 if self.context_nearest_mark is None:
314 self.session.openWithCallback(self.menuCallback, CutListContextMenu, state, nearmark)
316 def menuCallback(self, *result):
317 self.setSeekState(self.SEEK_STATE_PLAY)
322 if result == CutListContextMenu.RET_STARTCUT:
323 self.cut_start = self.context_position
324 elif result == CutListContextMenu.RET_ENDCUT:
325 # remove in/out marks between the new cut
326 for (where, what) in self.cut_list[:]:
327 if self.cut_start <= where <= self.context_position and what in [0,1]:
328 self.cut_list.remove((where, what))
330 bisect.insort(self.cut_list, (self.cut_start, 1))
331 bisect.insort(self.cut_list, (self.context_position, 0))
332 self.uploadCuesheet()
333 self.cut_start = None
334 elif result == CutListContextMenu.RET_DELETECUT:
338 for (where, what) in self.cut_list:
339 if what == 1 and where < self.context_position: # out
340 out_before = (where, what)
341 elif what == 0 and where < self.context_position: # in, before out
343 elif what == 0 and where > self.context_position and in_after is None:
344 in_after = (where, what)
346 if out_before is not None:
347 self.cut_list.remove(out_before)
349 if in_after is not None:
350 self.cut_list.remove(in_after)
351 self.uploadCuesheet()
352 elif result == CutListContextMenu.RET_MARK:
354 elif result == CutListContextMenu.RET_DELETEMARK:
355 self.cut_list.remove(self.context_nearest_mark)
356 self.uploadCuesheet()
357 elif result == CutListContextMenu.RET_REMOVEBEFORE:
358 # remove in/out marks before current position
359 for (where, what) in self.cut_list[:]:
360 if where <= self.context_position and what in [0,1]:
361 self.cut_list.remove((where, what))
363 bisect.insort(self.cut_list, (self.context_position, 0))
364 self.uploadCuesheet()
365 elif result == CutListContextMenu.RET_REMOVEAFTER:
366 # remove in/out marks after current position
367 for (where, what) in self.cut_list[:]:
368 if where >= self.context_position and what in [0,1]:
369 self.cut_list.remove((where, what))
371 bisect.insort(self.cut_list, (self.context_position, 1))
372 self.uploadCuesheet()
374 def main(session, service, **kwargs):
375 session.open(CutListEditor, service)
377 def Plugins(**kwargs):
378 return PluginDescriptor(name="Cutlist Editor", description=_("Cutlist editor..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)