Ejemplo n.º 1
0
 def recalcEntrySize(self):
     esize = self.l.getItemSize()
     width = esize.width()
     height = esize.height()
     xpos = 0
     w = width / 10 * 2
     self.service_rect = Rect(xpos, 0, w - 10, height)
     xpos += w
     w = width / 10 * 8
     self.event_rect = Rect(xpos, 0, w, height)
Ejemplo n.º 2
0
	def recalcEntrySize(self):
		super(EPGSearchList, self).recalcEntrySize()
		self.listSizeWidth = self.l.getItemSize().width()
		width = self.descr_rect.x + self.descr_rect.w
		if allowShowOrbital and config.plugins.epgsearch.showorbital.value:
			fontSize = self.eventFontSizeSingle + config.epgselection.enhanced_eventfs.value
			orbitalPosWidth = int(fontSize * 4.4)
		else:
			orbitalPosWidth = 0

		self.orbpos_rect = Rect(self.descr_rect.x, self.descr_rect.y, orbitalPosWidth, self.descr_rect.h)
		orbpos_r = self.orbpos_rect.x + self.orbpos_rect.w
		self.descr_rect = Rect(orbpos_r, self.orbpos_rect.y, width - orbpos_r, self.orbpos_rect.h)
Ejemplo n.º 3
0
	def recalcEntrySize(self):
		esize = self.l.getItemSize()
		width = esize.width()
		height = esize.height()
		if self.showServiceTitle:
			w = width // 10 * 2;
		else:     # if self.showPicon:    # this must be set if showServiceTitle is None
			w = 2 * height - 2 * self.serviceBorderWidth  # FIXME: could do better...
		self.service_rect = Rect(0, 0, w, height)
		self.event_rect = Rect(w, 0, width - w, height)
		piconHeight = height - 2 * self.serviceBorderWidth
		piconWidth = 2 * piconHeight  # FIXME: could do better...
		if piconWidth > w - 2 * self.serviceBorderWidth:
			piconWidth = w - 2 * self.serviceBorderWidth
		self.picon_size = eSize(piconWidth, piconHeight)
Ejemplo n.º 4
0
 def recalcEntrySize(self):
     esize = self.l.getItemSize()
     width = esize.width()
     height = esize.height()
     xpos = 0
     w = width / 10 * 2
     self.service_rect = Rect(xpos, 0, w - 10, height)
     xpos += w
     w = width / 10 * 8
     self.event_rect = Rect(xpos, 0, w, height)
Ejemplo n.º 5
0
	def selEntry(self, dir, visible = True):
		cur_service = self.cur_service    #(service, service_name, events, picon)
		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 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 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
			elif dir == +2: #next page
				self.offs += 1
				self.fillMultiEPG(None) # refill
				return True
			elif dir == -2: #prev
				if self.offs > 0:
					self.offs -= 1
					self.fillMultiEPG(None) # refill
					return True
			elif dir == +3: #next day
				self.offs += 60 * 24 / self.time_epoch
				self.fillMultiEPG(None) # refill
				return True
			elif dir == -3: #prev day
				self.offs -= 60 * 24 / self.time_epoch
				if self.offs < 0:
					self.offs = 0;
				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])
			self.select_rect = Rect(xpos, 0, width, self.event_rect.height)
			self.l.setSelectionClip(eRect(xpos, 0, width, self.event_rect.h), visible and update)
		else:
			self.select_rect = self.event_rect
			self.l.setSelectionClip(eRect(self.event_rect.x, self.event_rect.y, self.event_rect.w, self.event_rect.h), False)
		self.selectionChanged()
		return False
Ejemplo n.º 6
0
	def getServiceRect(self):
		rc = self.service_rect
		return Rect( rc.left() + (self.instance and self.instance.position().x() or 0), rc.top(), rc.width(), rc.height() )
Ejemplo n.º 7
0
	def getEventRect(self):
		rc = self.event_rect
		return Rect( rc.left() + (self.instance and self.instance.position().x() or 0), rc.top(), rc.width(), rc.height() )
Ejemplo n.º 8
0
class EPGList(HTMLComponent, GUIComponent):
    def __init__(self, selChangedCB=None, timer=None, time_epoch=120, overjump_empty=True):
        self.cur_event = None
        self.cur_service = None
        self.offs = 0
        self.timer = timer
        self.onSelChanged = []
        if selChangedCB is not None:
            self.onSelChanged.append(selChangedCB)
        GUIComponent.__init__(self)
        self.l = eListboxPythonMultiContent()
        self.l.setItemHeight(54)
        self.l.setBuildFunc(self.buildEntry)
        if overjump_empty:
            self.l.setSelectableFunc(self.isSelectable)
        self.epgcache = eEPGCache.getInstance()
        self.clock_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "750S/icons/epgclock.png"))
        self.clock_add_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "750S/icons/epgclock_add.png"))
        self.clock_pre_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "750S/icons/epgclock_pre.png"))
        self.clock_post_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "750S/icons/epgclock_post.png"))
        self.clock_prepost_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "750S/icons/epgclock_prepost.png"))
        self.time_base = None
        self.time_epoch = time_epoch
        self.list = None
        self.event_rect = None

        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

    def getEventFromId(self, service, eventid):
        event = None
        if self.epgcache is not None and eventid is not None:
            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:
            return (None, None)
        old_service = self.cur_service  # (service, service_name, events)
        events = self.cur_service[2]
        refstr = self.cur_service[0]
        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)
        event = self.getEventFromId(service, eventid)
        return (event, service)

    def connectSelectionChanged(func):
        if not self.onSelChanged.count(func):
            self.onSelChanged.append(func)

    def disconnectSelectionChanged(func):
        self.onSelChanged.remove(func)

    def serviceChanged(self):
        cur_sel = self.l.getCurrentSelection()
        if cur_sel:
            self.findBestEvent()

    def findBestEvent(self):
        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]
            if events and len(events):
                if last_time:
                    best_diff = 0
                    best = len(events)  # set invalid
                    idx = 0
                    for event in events:  # iterate all events
                        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
                        idx += 1
                    if best != len(events):
                        self.cur_event = best
            else:
                self.cur_event = None
        self.selEntry(0)

    def selectionChanged(self):
        for x in self.onSelChanged:
            if x is not None:
                x()

    # 				try:
    # 					x()
    # 				except: # FIXME!!!
    # 					print "FIXME in EPGList.selectionChanged"
    # 					pass

    GUI_WIDGET = eListbox

    def postWidgetCreate(self, instance):
        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()
        width = esize.width()
        height = esize.height()
        xpos = 0
        w = width / 10 * 2
        self.service_rect = Rect(xpos, 0, w - 10, height)
        xpos += w
        w = width / 10 * 8
        self.event_rect = Rect(xpos, 0, w, height)

    def calcEntryPosAndWidthHelper(self, stime, duration, start, end, width):
        xpos = (stime - start) * width / (end - start)
        ewidth = (stime + duration - start) * width / (end - start)
        ewidth -= xpos
        if xpos < 0:
            ewidth += xpos
            xpos = 0
        if (xpos + ewidth) > width:
            ewidth = width - xpos
        return xpos, ewidth

    def calcEntryPosAndWidth(self, event_rect, time_base, time_epoch, ev_start, ev_duration):
        xpos, width = self.calcEntryPosAndWidthHelper(
            ev_start, ev_duration, time_base, time_base + time_epoch * 60, event_rect.width()
        )
        return xpos + event_rect.left(), width

    def buildEntry(self, service, service_name, events):
        r1 = self.service_rect
        r2 = self.event_rect
        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
            end = start + self.time_epoch * 60
            left = r2.left()
            top = r2.top()
            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 = ev[2] and self.timer.isInTimer(ev[0], ev[2], ev[3], service)
                xpos, ewidth = self.calcEntryPosAndWidthHelper(ev[2], ev[3], start, end, width)
                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(
                        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)
        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 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 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])
            self.l.setSelectionClip(eRect(xpos, 0, width, self.event_rect.height()), visible and update)
        else:
            self.l.setSelectionClip(
                eRect(self.event_rect.left(), self.event_rect.top(), self.event_rect.width(), self.event_rect.height()),
                False,
            )
        self.selectionChanged()
        return False

    def queryEPG(self, list, buildFunc=None):
        if self.epgcache is not None:
            if buildFunc is not None:
                return self.epgcache.lookupEvent(list, buildFunc)
            else:
                return self.epgcache.lookupEvent(list)
        return []

    def fillMultiEPG(self, services, stime=-1):
        if services is None:
            time_base = self.time_base + self.offs * self.time_epoch * 60
            test = [(service[0], 0, time_base, self.time_epoch) for service in self.list]
        else:
            self.cur_event = None
            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, "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 = ""
        sname = ""
        for x in epg_data:
            if service != x[0]:
                if tmp_list is not None:
                    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] is not None and tmp_list or None))

        self.l.setList(self.list)
        self.findBestEvent()

    def getEventRect(self):
        rc = self.event_rect
        return Rect(
            rc.left() + (self.instance and self.instance.position().x() or 0), rc.top(), rc.width(), rc.height()
        )

    def getTimeEpoch(self):
        return self.time_epoch

    def getTimeBase(self):
        return self.time_base + (self.offs * self.time_epoch * 60)

    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
Ejemplo n.º 9
0
	def recalcEntrySize(self):
		esize = self.l.getItemSize()
		width = esize.width()
		height = esize.height()
		try:
			self.iconSize = self.clocks[0].size().height()
		except:
			pass
		self.space = self.iconSize + self.iconDistance
		self.nextIcon = self.iconSize + 2 * self.iconDistance
		self.height = height
		self.dy = int((height - self.iconSize)/2.)

		if self.type == EPG_TYPE_SINGLE:
			if self.skinColumns:
				x = 0
				self.weekday_rect = Rect(0, 0, self.gap(self.col[0]), height)
				x += self.col[0]
				self.datetime_rect = Rect(x, 0, self.gap(self.col[1]), height)
				x += self.col[1]
				self.descr_rect = Rect(x, 0, width-x, height)
			else:
				self.weekday_rect = Rect(0, 0, width/20*2-10, height)
				self.datetime_rect = Rect(width/20*2, 0, width/20*5-15, height)
				self.descr_rect = Rect(width/20*7, 0, width/20*13, height)
		elif self.type == EPG_TYPE_MULTI:
			if self.skinColumns:
				x = 0
				self.service_rect = Rect(x, 0, self.gap(self.col[0]), height)
				x += self.col[0]
				self.progress_rect = Rect(x, 8, self.gap(self.col[1]), height-16)
				self.start_end_rect = Rect(x, 0, self.gap(self.col[1]), height)
				x += self.col[1]
				self.descr_rect = Rect(x, 0, width-x, height)
			else:
				xpos = 0;
				w = width/10*3;
				self.service_rect = Rect(xpos, 0, w-10, height)
				xpos += w;
				w = width/10*2;
				self.start_end_rect = Rect(xpos, 0, w-10, height)
				self.progress_rect = Rect(xpos, 4, w-10, height-8)
				xpos += w
				w = width/10*5;
				self.descr_rect = Rect(xpos, 0, width, height)
		else: # EPG_TYPE_SIMILAR
			if self.skinColumns:
				x = 0
				self.weekday_rect = Rect(0, 0, self.gap(self.col[0]), height)
				x += self.col[0]
				self.datetime_rect = Rect(x, 0, self.gap(self.col[1]), height)
				x += self.col[1]
				self.descr_rect = Rect(x, 0, width-x, height)
			else:
				self.weekday_rect = Rect(0, 0, width/20*2-10, height)
				self.datetime_rect = Rect(width/20*2, 0, width/20*5-15, height)
				self.service_rect = Rect(width/20*7, 0, width/20*13, height)
Ejemplo n.º 10
0
class EPGList(HTMLComponent, GUIComponent):
    GUI_WIDGET = eListbox
    SKIN_COMPONENT_KEY = "MultiEPGList"
    SKIN_COMPONENT_ICON_HEIGHT = "iconHeight"
    SKIN_COMPONENT_ICON_WIDTH = "iconWidth"

    def __init__(self,
                 selChangedCB=None,
                 timer=None,
                 time_epoch=120,
                 overjump_empty=True):
        sizes = componentSizes[EPGList.SKIN_COMPONENT_KEY]
        self._iconWidth = sizes.get(EPGList.SKIN_COMPONENT_ICON_WIDTH, 22)
        self._iconHeight = sizes.get(EPGList.SKIN_COMPONENT_ICON_HEIGHT, 21)

        self.cur_event = None
        self.cur_service = None
        self.offs = 0
        self.timer = timer
        self.onSelChanged = []
        if selChangedCB is not None:
            self.onSelChanged.append(selChangedCB)
        GUIComponent.__init__(self)
        self.l = eListboxPythonMultiContent()
        self.l.setItemHeight(54)
        self.l.setBuildFunc(self.buildEntry)
        if overjump_empty:
            self.l.setSelectableFunc(self.isSelectable)
        self.epgcache = eEPGCache.getInstance()
        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

        self.foreColor = None
        self.foreColorSelected = None
        self.borderColor = None
        self.backColor = 0x586d88
        self.backColorSelected = 0x808080
        self.backColorActive = 0x33aa33
        self.backColorActiveSelected = 0x33ee33
        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)
                elif attrib == "EntryForegroundColorSelected":
                    self.foreColorSelected = parseColor(value)
                elif attrib == "EntryActiveBackgroundColor":
                    self.backColorActive = parseColor(value)
                elif attrib == "EntryActiveBackgroundColorSelected":
                    self.backColorActiveSelected = parseColor(value)
                elif attrib == "EntryBorderColor":
                    self.borderColor = parseColor(value)
                elif attrib == "EntryBackgroundColor":
                    self.backColor = parseColor(value)
                elif attrib == "EntryBackgroundColorSelected":
                    self.backColorSelected = parseColor(value)
                elif attrib == "ServiceNameForegroundColor":
                    self.foreColorService = parseColor(value)
                elif attrib == "ServiceNameBackgroundColor":
                    self.backColorService = parseColor(value)
                elif attrib == "EntryFont":
                    self.l.setFont(
                        1,
                        gFont(value.split(";")[0], int(value.split(";")[1])))
                elif attrib == "ServiceFont":
                    self.l.setFont(
                        0,
                        gFont(value.split(";")[0], int(value.split(";")[1])))
                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

    def getEventFromId(self, service, eventid):
        event = None
        if self.epgcache is not None and eventid is not None:
            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:
            return (None, None)
        old_service = self.cur_service  #(service, service_name, events)
        events = self.cur_service[2]
        refstr = self.cur_service[0]
        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)
        event = self.getEventFromId(service, eventid)
        return (event, service)

    def connectSelectionChanged(self, func):
        if not self.onSelChanged.count(func):
            self.onSelChanged.append(func)

    def disconnectSelectionChanged(self, func):
        self.onSelChanged.remove(func)

    def serviceChanged(self):
        cur_sel = self.l.getCurrentSelection()
        if cur_sel:
            self.findBestEvent()

    def findBestEvent(self):
        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]
            if events and len(events):
                if last_time:
                    best_diff = 0
                    best = len(events)  #set invalid
                    idx = 0
                    for event in events:  #iterate all events
                        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
                        idx += 1
                    if best != len(events):
                        self.cur_event = best
            else:
                self.cur_event = None
        self.selEntry(0)

    def selectionChanged(self):
        for x in self.onSelChanged:
            if x is not None:
                x()

    def postWidgetCreate(self, instance):
        instance.setWrapAround(True)
        self.selectionChanged_conn = instance.selectionChanged.connect(
            self.serviceChanged)
        instance.setContent(self.l)
        tlf = TemplatedListFonts()
        self.l.setFont(0, gFont(tlf.face(tlf.MEDIUM), tlf.size(tlf.MEDIUM)))
        self.l.setFont(1, gFont(tlf.face(tlf.SMALL), tlf.size(tlf.SMALL)))
        self.l.setSelectionClip(eRect(0, 0, 0, 0), False)

    def preWidgetRemove(self, instance):
        self.selectionChanged_conn = None
        instance.setContent(None)

    def recalcEntrySize(self):
        esize = self.l.getItemSize()
        width = esize.width()
        height = esize.height()
        xpos = 0
        w = width / 10 * 2
        self.service_rect = Rect(xpos, 0, w - 10, height)
        xpos += w
        w = width / 10 * 8
        self.event_rect = Rect(xpos, 0, w, height)

    def calcEntryPosAndWidthHelper(self, stime, duration, start, end, width):
        xpos = (stime - start) * width / (end - start)
        ewidth = (stime + duration - start) * width / (end - start)
        ewidth -= xpos
        if xpos < 0:
            ewidth += xpos
            xpos = 0
        if (xpos + ewidth) > width:
            ewidth = width - xpos
        return xpos, ewidth

    def calcEntryPosAndWidth(self, event_rect, time_base, time_epoch, ev_start,
                             ev_duration):
        xpos, width = self.calcEntryPosAndWidthHelper(
            ev_start, ev_duration, time_base, time_base + time_epoch * 60,
            event_rect.width())
        return xpos + event_rect.left(), width

    def buildEntry(self, service, service_name, events):
        r1 = self.service_rect
        r2 = self.event_rect
        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
            end = start + self.time_epoch * 60
            left = r2.left()
            top = r2.top()
            width = r2.width()
            height = r2.height()
            foreColor = self.foreColor
            foreColorSelected = self.foreColorSelected
            borderColor = self.borderColor

            now = time()

            for ev in events:  #(event_id, event_title, begin_time, duration)
                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 ev[2] < now and now < (ev[2] + ev[3]):
                    backColor = self.backColorActive
                    backColorSelected = self.backColorActiveSelected
                else:
                    backColor = self.backColor
                    backColorSelected = self.backColorSelected
                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(
                        MultiContentEntryPixmapAlphaTest(
                            pos=(left + xpos + ewidth - 5 - self._iconWidth,
                                 top + height - 5 - self._iconHeight),
                            size=(self._iconWidth, self._iconHeight),
                            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)
        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 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 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])
            self.l.setSelectionClip(
                eRect(xpos, 0, width, self.event_rect.height()), visible
                and update)
        else:
            self.l.setSelectionClip(
                eRect(self.event_rect.left(), self.event_rect.top(),
                      self.event_rect.width(), self.event_rect.height()),
                False)
        self.selectionChanged()
        return False

    def queryEPG(self, list, buildFunc=None):
        if self.epgcache is not None:
            if buildFunc is not None:
                return self.epgcache.lookupEvent(list, buildFunc)
            else:
                return self.epgcache.lookupEvent(list)
        return []

    def fillMultiEPG(self, services, stime=-1):
        if services is None:
            time_base = self.time_base + self.offs * self.time_epoch * 60
            test = [(service[0], 0, time_base, self.time_epoch)
                    for service in self.list]
        else:
            self.cur_event = None
            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, '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 = ""
        sname = ""
        for x in epg_data:
            if service != x[0]:
                if tmp_list is not None:
                    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] is not None and tmp_list
                 or None))

        self.l.setList(self.list)
        self.findBestEvent()

    def getEventRect(self):
        rc = self.event_rect
        return Rect(
            rc.left() + (self.instance and self.instance.position().x() or 0),
            rc.top(), rc.width(), rc.height())

    def getTimeEpoch(self):
        return self.time_epoch

    def getTimeBase(self):
        return self.time_base + (self.offs * self.time_epoch * 60)

    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