X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/b4a8712280e79e52de422a48f247202a934ac576..HEAD:/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py diff --git a/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py b/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py old mode 100644 new mode 100755 index e1481276..1d621f47 --- a/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py +++ b/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py @@ -1,4 +1,4 @@ -from skin import queryColor +from skin import parseColor from Components.config import config, ConfigClock, ConfigInteger from Components.Pixmap import Pixmap from Components.Button import Button @@ -7,16 +7,20 @@ from Components.HTMLComponent import HTMLComponent from Components.GUIComponent import GUIComponent from Components.EpgList import Rect from Components.Sources.Event import Event -from Components.Sources.Clock import Clock +from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest +from Components.TimerList import TimerList from Screens.Screen import Screen from Screens.EventView import EventViewSimple from Screens.TimeDateInput import TimeDateInput from Screens.TimerEntry import TimerEntry from Screens.EpgSelection import EPGSelection -from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE -from RecordTimer import RecordTimerEntry, parseEvent +from Screens.TimerEdit import TimerSanityConflict +from Screens.MessageBox import MessageBox +from Tools.Directories import resolveFilename, SCOPE_CURRENT_SKIN +from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT from ServiceReference import ServiceReference -from enigma import eEPGCache, eListbox, eListboxPythonMultiContent, gFont, loadPNG, \ +from Tools.LoadPixmap import LoadPixmap +from enigma import eEPGCache, eListbox, gFont, eListboxPythonMultiContent, \ RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, RT_WRAP, eRect, eTimer from time import localtime, time, strftime @@ -37,39 +41,55 @@ class EPGList(HTMLComponent, GUIComponent): if overjump_empty: self.l.setSelectableFunc(self.isSelectable) self.epgcache = eEPGCache.getInstance() - self.clock_pixmap = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'epgclock-fs8.png')) + self.clock_pixmap = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, 'skin_default/icons/epgclock.png')) + self.clock_add_pixmap = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, 'skin_default/icons/epgclock_add.png')) + self.clock_pre_pixmap = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, 'skin_default/icons/epgclock_pre.png')) + self.clock_post_pixmap = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, 'skin_default/icons/epgclock_post.png')) + self.clock_prepost_pixmap = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, 'skin_default/icons/epgclock_prepost.png')) self.time_base = None self.time_epoch = time_epoch self.list = None self.event_rect = None - #query skin colors - col = queryColor("GraphEpg.Foreground") - self.foreColor = col and col.argb() - - col = queryColor("GraphEpg.Border") - self.borderColor = col and col.argb() - - col = queryColor("GraphEpg.Background") - if col is None: - self.backColor = 0x586d88 - else: - self.backColor = col.argb() - - col = queryColor("GraphEpg.BackgroundSelected") - if col is None: - self.backColorSelected = 0x808080 - else: - self.backColorSelected = col.argb() + self.foreColor = None + self.foreColorSelected = None + self.borderColor = None + self.backColor = 0x586d88 + self.backColorSelected = 0x808080 + self.foreColorService = None + self.backColorService = None + + def applySkin(self, desktop, screen): + if self.skinAttributes is not None: + attribs = [ ] + for (attrib, value) in self.skinAttributes: + if attrib == "EntryForegroundColor": + self.foreColor = parseColor(value).argb() + elif attrib == "EntryForegroundColorSelected": + self.foreColorSelected = parseColor(value).argb() + elif attrib == "EntryBorderColor": + self.borderColor = parseColor(value).argb() + elif attrib == "EntryBackgroundColor": + self.backColor = parseColor(value).argb() + elif attrib == "EntryBackgroundColorSelected": + self.backColorSelected = parseColor(value).argb() + elif attrib == "ServiceNameForegroundColor": + self.foreColorService = parseColor(value).argb() + elif attrib == "ServiceNameBackgroundColor": + self.backColorService = parseColor(value).argb() + else: + attribs.append((attrib,value)) + self.skinAttributes = attribs + return GUIComponent.applySkin(self, desktop, screen) def isSelectable(self, service, sname, event_list): return (event_list and len(event_list) and True) or False def setEpoch(self, epoch): - if self.cur_event is not None and self.cur_service is not None: - self.offs = 0 - self.time_epoch = epoch - self.fillMultiEPG(None) # refill +# if self.cur_event is not None and self.cur_service is not None: + self.offs = 0 + self.time_epoch = epoch + self.fillMultiEPG(None) # refill def getEventFromId(self, service, eventid): event = None @@ -77,14 +97,31 @@ class EPGList(HTMLComponent, GUIComponent): event = self.epgcache.lookupEventId(service.ref, eventid) return event + def moveToService(self,serviceref): + if serviceref is not None: + for x in range(len(self.list)): + if self.list[x][0] == serviceref.toString(): + self.instance.moveSelectionTo(x) + break + + def getIndexFromService(self, serviceref): + if serviceref is not None: + for x in range(len(self.list)): + if self.list[x][0] == serviceref.toString(): + return x + + def setCurrentIndex(self, index): + if self.instance is not None: + self.instance.moveSelectionTo(index) + def getCurrent(self): - if self.cur_service is None or self.cur_event is None: + if self.cur_service is None: return ( None, None ) old_service = self.cur_service #(service, service_name, events) events = self.cur_service[2] refstr = self.cur_service[0] - if not events or not len(events): - return ( None, None ) + if self.cur_event is None or not events or not len(events): + return ( None, ServiceReference(refstr) ) event = events[self.cur_event] #(event_id, event_title, begin_time, duration) eventid = event[0] service = ServiceReference(refstr) @@ -107,10 +144,13 @@ class EPGList(HTMLComponent, GUIComponent): old_service = self.cur_service #(service, service_name, events) cur_service = self.cur_service = self.l.getCurrentSelection() last_time = 0; + time_base = self.getTimeBase() if old_service and self.cur_event is not None: events = old_service[2] cur_event = events[self.cur_event] #(event_id, event_title, begin_time, duration) last_time = cur_event[2] + if last_time < time_base: + last_time = time_base if cur_service: self.cur_event = 0 events = cur_service[2] @@ -120,7 +160,10 @@ class EPGList(HTMLComponent, GUIComponent): best = len(events) #set invalid idx = 0 for event in events: #iterate all events - diff = abs(event[2]-last_time) + ev_time = event[2] + if ev_time < time_base: + ev_time = time_base + diff = abs(ev_time-last_time) if (best == len(events)) or (diff < best_diff): best = idx best_diff = diff @@ -134,11 +177,12 @@ class EPGList(HTMLComponent, GUIComponent): def selectionChanged(self): for x in self.onSelChanged: if x is not None: - try: - x() - except: # FIXME!!! - print "FIXME in EPGList.selectionChanged" - pass + x() +# try: +# x() +# except: # FIXME!!! +# print "FIXME in EPGList.selectionChanged" +# pass GUI_WIDGET = eListbox @@ -146,11 +190,16 @@ class EPGList(HTMLComponent, GUIComponent): instance.setWrapAround(True) instance.selectionChanged.get().append(self.serviceChanged) instance.setContent(self.l) + self.l.setFont(0, gFont("Regular", 20)) + self.l.setFont(1, gFont("Regular", 14)) + self.l.setSelectionClip(eRect(0,0,0,0), False) + + def preWidgetRemove(self, instance): + instance.selectionChanged.get().remove(self.serviceChanged) + instance.setContent(None) def recalcEntrySize(self): esize = self.l.getItemSize() - self.l.setFont(0, gFont("Regular", 20)) - self.l.setFont(1, gFont("Regular", 14)) width = esize.width() height = esize.height() xpos = 0; @@ -159,7 +208,6 @@ class EPGList(HTMLComponent, GUIComponent): xpos += w; w = width/10*8; self.event_rect = Rect(xpos, 0, w, height) - self.l.setSelectionClip(eRect(xpos, 0, w, height), False) def calcEntryPosAndWidthHelper(self, stime, duration, start, end, width): xpos = (stime - start) * width / (end - start) @@ -179,8 +227,13 @@ class EPGList(HTMLComponent, GUIComponent): def buildEntry(self, service, service_name, events): r1=self.service_rect r2=self.event_rect - res = [ None ] # no private data needed - res.append((eListboxPythonMultiContent.TYPE_TEXT, r1.left(), r1.top(), r1.width(), r1.height(), 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, service_name)) + res = [ None, MultiContentEntryText( + pos = (r1.left(),r1.top()), + size = (r1.width(), r1.height()), + font = 0, flags = RT_HALIGN_LEFT | RT_VALIGN_CENTER, + text = service_name, + color = self.foreColorService, + backcolor = self.backColorService) ] if events: start = self.time_base+self.offs*self.time_epoch*60 @@ -190,44 +243,51 @@ class EPGList(HTMLComponent, GUIComponent): width = r2.width() height = r2.height() foreColor = self.foreColor + foreColorSelected = self.foreColorSelected backColor = self.backColor backColorSelected = self.backColorSelected borderColor = self.borderColor for ev in events: #(event_id, event_title, begin_time, duration) - rec=self.timer.isInTimer(ev[0], ev[2], ev[3], service) > ((ev[3]/10)*8) + rec=ev[2] and self.timer.isInTimer(ev[0], ev[2], ev[3], service) xpos, ewidth = self.calcEntryPosAndWidthHelper(ev[2], ev[3], start, end, width) - if self.borderColor is None: - res.append((eListboxPythonMultiContent.TYPE_TEXT, left+xpos, top, ewidth, height, 1, RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, ev[1], foreColor, backColor, backColorSelected, 1)) - else: - res.append((eListboxPythonMultiContent.TYPE_TEXT, left+xpos, top, ewidth, height, 1, RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, ev[1], foreColor, backColor, backColorSelected, 1, borderColor)) + res.append(MultiContentEntryText( + pos = (left+xpos, top), size = (ewidth, height), + font = 1, flags = RT_HALIGN_CENTER | RT_VALIGN_CENTER | RT_WRAP, + text = ev[1], color = foreColor, color_sel = foreColorSelected, + backcolor = backColor, backcolor_sel = backColorSelected, border_width = 1, border_color = borderColor)) if rec and ewidth > 23: - res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, left+xpos+ewidth-22, top+height-22, 21, 21, self.clock_pixmap, backColor, backColorSelected)) + res.append(MultiContentEntryPixmapAlphaTest( + pos = (left+xpos+ewidth-22, top+height-22), size = (21, 21), + png = self.getClockPixmap(service, ev[2], ev[3], ev[0]), + backcolor = backColor, + backcolor_sel = backColorSelected)) return res def selEntry(self, dir, visible=True): cur_service = self.cur_service #(service, service_name, events) - if not self.event_rect: - self.recalcEntrySize() - if cur_service and self.cur_event is not None: + self.recalcEntrySize() + valid_event = self.cur_event is not None + if cur_service: update = True entries = cur_service[2] if dir == 0: #current update = False elif dir == +1: #next - if self.cur_event+1 < len(entries): + if valid_event and self.cur_event+1 < len(entries): self.cur_event+=1 else: self.offs += 1 self.fillMultiEPG(None) # refill return True elif dir == -1: #prev - if self.cur_event-1 >= 0: + if valid_event and self.cur_event-1 >= 0: self.cur_event-=1 elif self.offs > 0: self.offs -= 1 self.fillMultiEPG(None) # refill return True + if cur_service and valid_event: entry = entries[self.cur_event] #(event_id, event_title, begin_time, duration) time_base = self.time_base+self.offs*self.time_epoch*60 xpos, width = self.calcEntryPosAndWidth(self.event_rect, time_base, self.time_epoch, entry[2], entry[3]) @@ -254,9 +314,14 @@ class EPGList(HTMLComponent, GUIComponent): self.cur_service = None self.time_base = int(stime) test = [ (service.ref.toString(), 0, self.time_base, self.time_epoch) for service in services ] - test.insert(0, 'RnITBD') + test.insert(0, 'XRnITBD') +# print "BEFORE:" +# for x in test: +# print x epg_data = self.queryEPG(test) - +# print "EPG:" +# for x in epg_data: +# print x self.list = [ ] tmp_list = None service = "" @@ -264,13 +329,13 @@ class EPGList(HTMLComponent, GUIComponent): for x in epg_data: if service != x[0]: if tmp_list is not None: - self.list.append((service, sname, tmp_list[0][0] and tmp_list)) + self.list.append((service, sname, tmp_list[0][0] is not None and tmp_list or None)) service = x[0] sname = x[1] tmp_list = [ ] tmp_list.append((x[2], x[3], x[4], x[5])) if tmp_list and len(tmp_list): - self.list.append((service, sname, tmp_list[0][0] and tmp_list)) + self.list.append((service, sname, tmp_list[0][0] is not None and tmp_list or None)) self.l.setList(self.list) self.findBestEvent() @@ -287,6 +352,30 @@ class EPGList(HTMLComponent, GUIComponent): def resetOffset(self): self.offs = 0 + + def getClockPixmap(self, refstr, beginTime, duration, eventId): + pre_clock = 1 + post_clock = 2 + clock_type = 0 + endTime = beginTime + duration + for x in self.timer.timer_list: + if x.service_ref.ref.toString() == refstr: + if x.eit == eventId: + return self.clock_pixmap + beg = x.begin + end = x.end + if beginTime > beg and beginTime < end and endTime > end: + clock_type |= pre_clock + elif beginTime < beg and endTime > beg and endTime < end: + clock_type |= post_clock + if clock_type == 0: + return self.clock_add_pixmap + elif clock_type == pre_clock: + return self.clock_pre_pixmap + elif clock_type == post_clock: + return self.clock_post_pixmap + else: + return self.clock_prepost_pixmap class TimelineText(HTMLComponent, GUIComponent): def __init__(self): @@ -314,6 +403,12 @@ config.misc.graph_mepg_prev_time=ConfigClock(default = time()) config.misc.graph_mepg_prev_time_period=ConfigInteger(default=120, limits=(60,300)) class GraphMultiEPG(Screen): + EMPTY = 0 + ADD_TIMER = 1 + REMOVE_TIMER = 2 + + ZAP = 1 + def __init__(self, session, services, zapFunc=None, bouquetChangeCB=None): Screen.__init__(self, session) self.bouquetChangeCB = bouquetChangeCB @@ -322,10 +417,11 @@ class GraphMultiEPG(Screen): self.ask_time = now - tmp self.closeRecursive = False self["key_red"] = Button("") - self["key_green"] = Button(_("Add timer")) + self["key_green"] = Button("") + self.key_green_choice = self.EMPTY + self.key_red_choice = self.EMPTY self["timeline_text"] = TimelineText() self["Event"] = Event() - self["Clock"] = Clock() self.time_lines = [ ] for x in (0,1,2,3,4,5): pm = Pixmap() @@ -362,7 +458,7 @@ class GraphMultiEPG(Screen): },-1) self.updateTimelineTimer = eTimer() - self.updateTimelineTimer.timeout.get().append(self.moveTimeLines) + self.updateTimelineTimer.callback.append(self.moveTimeLines) self.updateTimelineTimer.start(60*1000) self.onLayoutFinish.append(self.onCreate) @@ -447,6 +543,7 @@ class GraphMultiEPG(Screen): #just used in multipeg def onCreate(self): self["list"].fillMultiEPG(self.services, self.ask_time) + self["list"].moveToService(self.session.nav.getCurrentlyPlayingServiceReference()) self.moveTimeLines() def eventViewCallback(self, setEvent, setService, val): @@ -464,43 +561,109 @@ class GraphMultiEPG(Screen): setEvent(cur[0]) def zapTo(self): - if self.zapFunc and self["key_red"].getText() == "Zap": + if self.zapFunc and self.key_red_choice == self.ZAP: self.closeRecursive = True ref = self["list"].getCurrent()[1] - self.zapFunc(ref.ref) + if ref: + self.zapFunc(ref.ref) def eventSelected(self): self.infoKeyPressed() + def removeTimer(self, timer): + timer.afterEvent = AFTEREVENT.NONE + self.session.nav.RecordTimer.removeEntry(timer) + self["key_green"].setText(_("Add timer")) + self.key_green_choice = self.ADD_TIMER + def timerAdd(self): cur = self["list"].getCurrent() event = cur[0] serviceref = cur[1] if event is None: return - newEntry = RecordTimerEntry(serviceref, checkOldTimers = True, *parseEvent(event)) - self.session.openWithCallback(self.timerEditFinished, TimerEntry, newEntry) + eventid = event.getEventId() + refstr = serviceref.ref.toString() + for timer in self.session.nav.RecordTimer.timer_list: + if timer.eit == eventid and timer.service_ref.ref.toString() == refstr: + cb_func = lambda ret : not ret or self.removeTimer(timer) + self.session.openWithCallback(cb_func, MessageBox, _("Do you really want to delete %s?") % event.getEventName()) + break + else: + newEntry = RecordTimerEntry(serviceref, checkOldTimers = True, *parseEvent(event)) + self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry) - def timerEditFinished(self, answer): + def finishedAdd(self, answer): + print "finished add" if answer[0]: - self.session.nav.RecordTimer.record(answer[1]) + entry = answer[1] + simulTimerList = self.session.nav.RecordTimer.record(entry) + if simulTimerList is not None: + for x in simulTimerList: + if x.setAutoincreaseEnd(entry): + self.session.nav.RecordTimer.timeChanged(x) + simulTimerList = self.session.nav.RecordTimer.record(entry) + if simulTimerList is not None: + self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList) + self["key_green"].setText(_("Remove timer")) + self.key_green_choice = self.REMOVE_TIMER else: + self["key_green"].setText(_("Add timer")) + self.key_green_choice = self.ADD_TIMER print "Timeredit aborted" + + def finishSanityCorrection(self, answer): + self.finishedAdd(answer) def onSelectionChanged(self): - evt = self["list"].getCurrent() - self["Event"].newEvent(evt and evt[0]) - if evt and evt[0]: - evt = evt[0] - now = time() - start = evt.getBeginTime() - end = start + evt.getDuration() - if now >= start and now <= end: - self["key_red"].setText("Zap") - else: + cur = self["list"].getCurrent() + if cur is None: + if self.key_green_choice != self.EMPTY: + self["key_green"].setText("") + self.key_green_choice = self.EMPTY + if self.key_red_choice != self.EMPTY: self["key_red"].setText("") - + self.key_red_choice = self.EMPTY + return + + event = cur[0] + self["Event"].newEvent(event) + + if cur[1] is None or cur[1].getServiceName() == "": + if self.key_green_choice != self.EMPTY: + self["key_green"].setText("") + self.key_green_choice = self.EMPTY + if self.key_red_choice != self.EMPTY: + self["key_red"].setText("") + self.key_red_choice = self.EMPTY + return + elif self.key_red_choice != self.ZAP: + self["key_red"].setText("Zap") + self.key_red_choice = self.ZAP + + if not event: + if self.key_green_choice != self.EMPTY: + self["key_green"].setText("") + self.key_green_choice = self.EMPTY + return + + serviceref = cur[1] + eventid = event.getEventId() + refstr = serviceref.ref.toString() + isRecordEvent = False + for timer in self.session.nav.RecordTimer.timer_list: + if timer.eit == eventid and timer.service_ref.ref.toString() == refstr: + isRecordEvent = True + break + if isRecordEvent and self.key_green_choice != self.REMOVE_TIMER: + self["key_green"].setText(_("Remove timer")) + self.key_green_choice = self.REMOVE_TIMER + elif not isRecordEvent and self.key_green_choice != self.ADD_TIMER: + self["key_green"].setText(_("Add timer")) + self.key_green_choice = self.ADD_TIMER + def moveTimeLines(self, force=False): + self.updateTimelineTimer.start((60-(int(time())%60))*1000) #keep syncronised l = self["list"] event_rect = l.getEventRect() time_epoch = l.getTimeEpoch() @@ -508,6 +671,7 @@ class GraphMultiEPG(Screen): if event_rect is None or time_epoch is None or time_base is None: return time_steps = time_epoch > 180 and 60 or 30 + num_lines = time_epoch/time_steps incWidth=event_rect.width()/num_lines pos=event_rect.left() @@ -535,8 +699,7 @@ class GraphMultiEPG(Screen): now=time() timeline_now = self["timeline_now"] if now >= time_base and now < (time_base + time_epoch * 60): - bla = (event_rect.width() * 1000) / time_epoch - xpos = ((now/60) - (time_base/60)) * bla / 1000 + xpos = int((((now - time_base) * event_rect.width()) / (time_epoch * 60))-(timeline_now.instance.size().width()/2)) old_pos = timeline_now.position new_pos = (xpos+event_rect.left(), old_pos[1]) if old_pos != new_pos: @@ -544,3 +707,6 @@ class GraphMultiEPG(Screen): timeline_now.visible = True else: timeline_now.visible = False + # here no l.l.invalidate() is needed when the zPosition in the skin is correct! + +