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):
44 def __init__(self, session, state):
45 menu = [(_("back"), self.close), (None, )]
47 if state == self.SHOW_STARTCUT:
48 menu.append((_("start cut here"), self.startCut))
50 menu.append((_("start cut here"), ))
52 if state == self.SHOW_ENDCUT:
53 menu.append((_("end cut here"), self.endCut))
55 menu.append((_("end cut here"), ))
57 if state == self.SHOW_DELETECUT:
58 menu.append((_("delete cut"), self.deleteCut))
60 menu.append((_("delete cut"), ))
63 menu.append((_("insert mark here"), self.insertMark))
64 FixedMenu.__init__(self, session, _("Cut"), menu)
65 self.skinName = "Menu"
68 self.close(self.RET_STARTCUT)
71 self.close(self.RET_ENDCUT)
74 self.close(self.RET_DELETECUT)
77 self.close(self.RET_MARK)
79 class CutList(GUIComponent):
80 def __init__(self, list):
81 GUIComponent.__init__(self)
82 self.l = eListboxPythonMultiContent()
84 self.l.setFont(0, gFont("Regular", 20))
85 self.onSelectionChanged = [ ]
88 return self.l.getCurrentSelection()
90 def getCurrentIndex(self):
91 return self.l.getCurrentSelectionIndex()
93 def GUIcreate(self, parent):
94 self.instance = eListbox(parent)
95 self.instance.setContent(self.l)
96 self.instance.setItemHeight(30)
97 self.instance.selectionChanged.get().append(self.selectionChanged)
99 def selectionChanged(self):
100 for x in self.onSelectionChanged:
104 self.instance.selectionChanged.get().remove(self.selectionChanged)
105 self.instance.setContent(None)
108 def invalidateEntry(self, index):
109 self.l.invalidateEntry(index)
111 def setIndex(self, index, data):
112 self.list[index] = data
113 self.invalidateEntry(index)
115 def setList(self, list):
117 self.l.setList(self.list)
119 def setSelection(self, index):
120 if self.instance is not None:
121 self.instance.moveSelectionTo(index)
123 class CutListEditor(Screen, InfoBarSeek, InfoBarCueSheetSupport):
125 <screen position="100,100" size="550,400" title="Test" >
126 <widget name="Timeline" position="10,0" size="530,40"
127 pointer="/usr/share/enigma2/position_pointer.png:3,5" />
128 <widget name="Cutlist" position="10,50" size="530,300" scrollbarMode="showOnDemand" />
130 def __init__(self, session, service):
131 self.skin = CutListEditor.skin
132 Screen.__init__(self, session)
133 InfoBarSeek.__init__(self)
134 InfoBarCueSheetSupport.__init__(self)
135 session.nav.playService(service)
137 service = session.nav.getCurrentService()
138 cue = service and service.cueSheet()
140 # disable cutlists. we want to freely browse around in the movie
141 print "cut lists disabled!"
142 cue.setCutListEnable(0)
144 self.downloadCuesheet()
146 self["Timeline"] = ServicePositionGauge(self.session.nav)
147 self["Cutlist"] = CutList(self.getCutlist())
148 self["Cutlist"].onSelectionChanged.append(self.selectionChanged)
150 self["actions"] = HelpableActionMap(self, "CutListEditorActions",
152 "setIn": (self.setIn, _("Make this mark an 'in' point")),
153 "setOut": (self.setOut, _("Make this mark an 'out' point")),
154 "setMark": (self.setMark, _("Make this mark just a mark")),
155 "addMark": (self.__addMark, _("Add a mark")),
156 "removeMark": (self.__removeMark, _("Remove a mark")),
157 "leave": (self.exit, _("Exit editor")),
158 "showMenu": self.showMenu,
161 self.tutorial_seen = False
163 self.onExecBegin.append(self.showTutorial)
164 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
166 iPlayableService.evCuesheetChanged: self.refillList
169 # to track new entries we save the last version of the cutlist
172 self.cut_start = None
174 def showTutorial(self):
175 if not self.tutorial_seen:
176 self.tutorial_seen = True
177 self.session.open(MessageBox,
178 """Welcome to the Cutlist editor. It's still a bit strange to use, but anyway:
180 Seek to the start of the stuff you want to cut away. Press OK, select 'start cut'.
182 Then seek to the end, press OK, select 'end cut'. That's it.
183 """, MessageBox.TYPE_INFO)
185 def checkSkipShowHideLock(self):
188 def setType(self, index, type):
189 self.cut_list[index] = (self.cut_list[index][0], type)
190 self["Cutlist"].setIndex(index, CutListEntry(*self.cut_list[index]))
193 m = self["Cutlist"].getCurrentIndex()
195 self.uploadCuesheet()
198 m = self["Cutlist"].getCurrentIndex()
200 self.uploadCuesheet()
203 m = self["Cutlist"].getCurrentIndex()
205 self.uploadCuesheet()
208 self.toggleMark(onlyadd=True, tolerance=90000) # do not allow two marks in <1s
210 def __removeMark(self):
211 m = self["Cutlist"].getCurrent()
219 def getCutlist(self):
221 for e in self.cut_list:
222 r.append(CutListEntry(*e))
225 def selectionChanged(self):
226 where = self["Cutlist"].getCurrent()
231 seek = self.getSeek()
237 def refillList(self):
238 print "cue sheet changed, refilling"
239 self.downloadCuesheet()
241 # get the first changed entry, and select it
242 new_list = self.getCutlist()
243 self["Cutlist"].setList(new_list)
245 for i in range(min(len(new_list), len(self.last_cuts))):
246 if new_list[i] != self.last_cuts[i]:
247 self["Cutlist"].setSelection(i)
249 self.last_cuts = new_list
251 def getStateForPosition(self, pos):
253 for (where, what) in self.cut_list:
257 elif what == 1: # out
262 curpos = self.cueGetCurrentPosition()
266 self.setSeekState(self.SEEK_STATE_PAUSE)
268 self.context_position = curpos
270 cur_state = self.getStateForPosition(curpos)
272 print "currently in 'IN'"
273 if self.cut_start is None or self.context_position < self.cut_start:
274 state = CutListContextMenu.SHOW_STARTCUT
276 state = CutListContextMenu.SHOW_ENDCUT
278 print "currently in 'OUT'"
279 state = CutListContextMenu.SHOW_DELETECUT
281 self.session.openWithCallback(self.menuCallback, CutListContextMenu, state)
283 def menuCallback(self, *result):
284 self.setSeekState(self.SEEK_STATE_PLAY)
289 if result == CutListContextMenu.RET_STARTCUT:
290 self.cut_start = self.context_position
291 elif result == CutListContextMenu.RET_ENDCUT:
292 # remove in/out marks between the new cut
293 for (where, what) in self.cut_list[:]:
294 if self.cut_start <= where <= self.context_position and what in [0,1]:
295 self.cut_list.remove((where, what))
297 bisect.insort(self.cut_list, (self.cut_start, 1))
298 bisect.insort(self.cut_list, (self.context_position, 0))
299 self.uploadCuesheet()
300 self.cut_start = None
301 elif result == CutListContextMenu.RET_DELETECUT:
305 for (where, what) in self.cut_list:
306 if what == 1 and where < self.context_position: # out
307 out_before = (where, what)
308 elif what == 0 and where < self.context_position: # in, before out
310 elif what == 0 and where > self.context_position and in_after is None:
311 in_after = (where, what)
313 if out_before is not None:
314 self.cut_list.remove(out_before)
316 if in_after is not None:
317 self.cut_list.remove(in_after)
318 self.uploadCuesheet()
319 elif result == CutListContextMenu.RET_MARK:
322 def main(session, service):
323 session.open(CutListEditor, service)
326 return PluginDescriptor(name="Cutlist Editor", description=_("Cutlist editor..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)