def calc_geometry(self, object, copy_object=0): """ calculate the real values of the object (e.g. content) based on the geometry of the area """ if copy_object: object = copy.copy(object) font_h = 0 if isinstance(object.width, types.TupleType): object.width = int(eval_attr(object.width, self.area_val.width)) if isinstance(object.height, types.TupleType): object.height = int(eval_attr(object.height, self.area_val.height)) object.x += self.area_val.x object.y += self.area_val.y if not object.width: object.width = self.area_val.width if not object.height: object.height = self.area_val.height if object.width + object.x > self.area_val.width + self.area_val.x: object.width = self.area_val.width - object.x if object.height + object.y > self.area_val.height + self.area_val.y: object.height = self.area_val.height + self.area_val.y - object.y return object
def calc_geometry(self, object, copy_object=0): """ calculate the real values of the object (e.g. content) based on the geometry of the area """ if copy_object: object = copy.copy(object) font_h=0 if isinstance(object.width, types.TupleType): object.width = int(eval_attr(object.width, self.area_val.width)) if isinstance(object.height, types.TupleType): object.height = int(eval_attr(object.height, self.area_val.height)) object.x += self.area_val.x object.y += self.area_val.y if not object.width: object.width = self.area_val.width if not object.height: object.height = self.area_val.height if object.width + object.x > self.area_val.width + self.area_val.x: object.width = self.area_val.width - object.x if object.height + object.y > self.area_val.height + self.area_val.y: object.height = self.area_val.height + self.area_val.y - object.y return object
def _draw(self): """ The actual internal draw function. """ _debug_('Window::_draw %s' % self, 2) if not self.width or not self.height: raise TypeError, 'Not all needed variables set.' cheight = self.content.height self.content.layout() # resize when content changed the height because of the layout() if self.content.height - cheight > 0: self.height += self.content.height - cheight self.surface = self.osd.Surface(self.get_size()).convert_alpha() self.surface.fill((0, 0, 0, 0)) for o in self.background_layout: if o[0] == 'rectangle': r = copy.deepcopy(o[1]) r.width = eval_attr(r.width, self.get_size()[0]) r.height = eval_attr(r.height, self.get_size()[1]) if not r.width: r.width = self.get_size()[0] if not r.height: r.height = self.get_size()[1] if r.x + r.width > self.get_size()[0]: r.width = self.get_size()[0] - r.x if r.y + r.height > self.get_size()[1]: r.height = self.get_size()[1] - r.y self.osd.drawroundbox(r.x, r.y, r.x + r.width, r.y + r.height, r.bgcolor, r.size, r.color, r.radius, self.surface) self.get_selected_child = self.content.get_selected_child if not self.content.parent: print '******************************************************************' print 'Error: content has no parent, fixing...' print 'If you can reproduce this error message, please send a' print 'mail with the subject \'[Freevo-Bugreport] GUI\' to' print '[email protected].' print '******************************************************************' self.content.parent = self if not self.parent: print '******************************************************************' print 'Error: window has no parent, not showing...' print 'If you can reproduce this error message, please send a' print 'mail with the subject \'[Freevo-Bugreport] GUI\' to' print '[email protected].' print '******************************************************************' return self.content.surface = self.content.get_surface() self.content.draw() self.blit_parent()
def _draw(self): """ The actual internal draw function. """ logger.log( 9, 'Window::_draw %s', self) if not self.width or not self.height: raise TypeError, 'Not all needed variables set.' cheight = self.content.height self.content.layout() # resize when content changed the height because of the layout() if self.content.height - cheight > 0: self.height += self.content.height - cheight self.surface = self.osd.Surface(self.get_size()).convert_alpha() self.surface.fill((0,0,0,0)) for o in self.background_layout: if o[0] == 'rectangle': r = copy.deepcopy(o[1]) r.width = eval_attr(r.width, self.get_size()[0]) r.height = eval_attr(r.height, self.get_size()[1]) if not r.width: r.width = self.get_size()[0] if not r.height: r.height = self.get_size()[1] if r.x + r.width > self.get_size()[0]: r.width = self.get_size()[0] - r.x if r.y + r.height > self.get_size()[1]: r.height = self.get_size()[1] - r.y self.osd.drawroundbox(r.x, r.y, r.x+r.width, r.y+r.height, r.bgcolor, r.size, r.color, r.radius, self.surface) self.get_selected_child = self.content.get_selected_child if not self.content.parent: print '******************************************************************' print 'Error: content has no parent, fixing...' print 'If you can reproduce this error message, please send a bug report' print 'to the freevo-devel list' print '******************************************************************' self.content.parent = self if not self.parent: print '******************************************************************' print 'Error: window has no parent, not showing...' print 'If you can reproduce this error message, please send a bug report' print 'to the freevo-devel list' print '******************************************************************' return self.content.surface = self.content.get_surface() self.content.draw() self.blit_parent() self.osd.update()
def update_content(self): """ update the listing area """ menuw = self.menuw settings = self.settings layout = self.layout area = self.area_val content = self.calc_geometry(layout.content, copy_object=True) if not hasattr(menuw, "scrollable_text"): return scrollable_text = menuw.scrollable_text if self.scrollable_text != scrollable_text: scrollable_text.layout(content.width, content.height, content.font) self.scrollable_text = scrollable_text page = scrollable_text.get_page() if not len(page): return y = 0 for line in page: self.drawstring(line, content.font, content, content.x, content.y + y, mode="hard") y += content.font.height # print arrow: try: if scrollable_text.more_lines_up() and area.images["uparrow"]: self.drawimage(area.images["uparrow"].filename, area.images["uparrow"]) if (scrollable_text.more_lines_down() or scrollable_text.more_lines_up()) and area.images["scrollbar"]: offset, total_lines, lines_per_page = scrollable_text.get_page_details() v = copy.copy(area.images["scrollbar"]) if isinstance(area.images["scrollbar"].height, types.TupleType): v.height = eval_attr(v.height, content.height) v.y += int(float(v.height) * (float(offset) / float(total_lines))) h = int(float(v.height) * (float(lines_per_page) / float(total_lines))) v.height = min(v.height, h) self.drawimage(area.images["scrollbar"].filename, v) if scrollable_text.more_lines_down() and area.images["downarrow"]: if isinstance(area.images["downarrow"].y, types.TupleType): v = copy.copy(area.images["downarrow"]) v.y = eval_attr(v.y, content.y + content.height) else: v = area.images["downarrow"] self.drawimage(area.images["downarrow"].filename, v) except: # empty menu / missing images pass
def __init__content__(self): x, y, width, height = self.content_layout.x, self.content_layout.y, \ self.content_layout.width, self.content_layout.height width = eval_attr(width, self.width) or self.width height = eval_attr(height, self.height) or self.height self.content = Container('frame', x, y, width, height, vertical_expansion=1) GUIObject.add_child(self, self.content) # adjust left to content self.left += (self.width - width-x) / 2 self.content.internal_h_align = Align.CENTER self.content.internal_v_align = Align.CENTER
def set_size(self, width, height): width -= self.width height -= self.height self.width += width self.height += height width, height = self.content_layout.width, self.content_layout.height self.content.width = eval_attr(width, self.width) or self.width self.content.height = eval_attr(height, self.height) or self.height self.left = self.osd.width / 2 - self.width / 2 self.top = self.osd.height / 2 - self.height / 2 # adjust left to content self.left += (self.width - self.content.width - self.content.left) / 2
def set_size(self, width, height): width -= self.width height -= self.height self.width += width self.height += height width, height = self.content_layout.width, self.content_layout.height self.content.width = eval_attr(width, self.width ) or self.width self.content.height = eval_attr(height, self.height) or self.height self.left = self.osd.width/2 - self.width/2 self.top = self.osd.height/2 - self.height/2 # adjust left to content self.left += (self.width - self.content.width-self.content.left) / 2
def update_content(self): """ update the listing area """ menuw = self.menuw settings = self.settings layout = self.layout area = self.area_val content = self.calc_geometry(layout.content, copy_object=True) if not hasattr(menuw, "scrollable_text"): return scrollable_text = menuw.scrollable_text if self.scrollable_text != scrollable_text: scrollable_text.layout(content.width, content.height, content.font) self.scrollable_text = scrollable_text page = scrollable_text.get_page() if not len(page): return y = 0 for line in page: self.drawstring(line, content.font, content, content.x, content.y + y, mode='hard') y += content.font.height # print arrow: try: if scrollable_text.more_lines_up() and area.images['uparrow']: self.drawimage(area.images['uparrow'].filename, area.images['uparrow']) if scrollable_text.more_lines_down() and area.images['downarrow']: if isinstance(area.images['downarrow'].y, types.TupleType): v = copy.copy(area.images['downarrow']) v.y = eval_attr(v.y, content.y + content.height) else: v = area.images['downarrow'] self.drawimage(area.images['downarrow'].filename, v) except: # empty menu / missing images pass
def get_item_rectangle(self, rectangle, item_w, item_h): """ calculates the values for a rectangle to fit item_w and item_h inside it. """ r = copy.copy(rectangle) # get the x and y value, based on MAX if isinstance(r.x, types.TupleType): r.x = int(eval_attr(r.x, item_w)) if isinstance(r.y, types.TupleType): r.y = int(eval_attr(r.y, item_h)) # set rect width and height to something if not r.width: r.width = item_w if not r.height: r.height = item_h # calc width and height based on MAX settings if isinstance(r.width, types.TupleType): r.width = int(eval_attr(r.width, item_w)) if isinstance(r.height, types.TupleType): r.height = int(eval_attr(r.height, item_h)) # correct item_w and item_h to fit the rect item_w = max(item_w, r.width) item_h = max(item_h, r.height) if r.x < 0: item_w -= r.x if r.y < 0: item_h -= r.y # return needed width and height to fit original width and height # and the rectangle attributes return max(item_w, r.width), max(item_h, r.height), r
def update_content(self): """ update the listing area """ menuw = self.menuw menu = self.menu settings = self.settings layout = self.layout area = self.area_val content = self.calc_geometry(layout.content, copy_object=True) cols, rows, hspace, vspace, hskip, vskip, width = \ self.get_items_geometry(settings, menu, self.display_style) BOX_UNDER_ICON = self.xml_settings.box_under_icon if not len(menu.choices): val = content.types['default'] self.drawstring(_('This directory is empty'), content.font, content) if content.align == 'center': item_x0 = content.x + (content.width - cols * hspace) / 2 else: item_x0 = content.x if content.valign == 'center': item_y0 = content.y + (content.height - rows * vspace) / 2 else: item_y0 = content.y current_col = 1 if content.type == 'image': width = hspace - content.spacing height = vspace - content.spacing last_tvs = ('', 0) all_tvs = True tvs_shortname = True anamorphic = self.xml_settings.anamorphic self.image_loaded = False remove_images = self.loading_images.keys() for choice in menuw.menu_items: if hasattr(choice, 'dirty'): choice.dirty = False items_geometry = self.last_get_items_geometry[1] # Widget Sizes wdg_x = 0 wdg_y = 0 wdg_w = items_geometry[2] wdg_h = items_geometry[3] if content.types.has_key('%s selected' % choice.type): s_val = content.types[ '%s selected' % choice.type ] else: s_val = content.types[ 'selected' ] if content.types.has_key(choice.type): n_val = content.types[ choice.type ] else: n_val = content.types['default'] if choice == menu.selected: val = s_val else: val = n_val text = choice.name if not text: text = "unknown" type_image = None if hasattr(val, 'icon'): type_image = val.icon if not choice.icon and not type_image: if choice.type == 'dir' and choice.parent and \ choice.parent.type != 'mediamenu': text = '%s' % text if (hasattr(choice, 'folder_fxd') or config.SKIN_HANDLES_DETAILS) else '[%s]' % text if content.type == 'text': x0 = item_x0 y0 = item_y0 icon_x = 0 image = None align = val.align or content.align if choice != menu.selected and hasattr(choice, 'outicon') and \ choice.outicon: image, w, h = self.loadimage(choice.outicon, (vspace-content.spacing, vspace-content.spacing)) elif choice.icon: image, w, h = self.loadimage(choice.icon, (vspace-content.spacing, vspace-content.spacing)) if not image and type_image: image, w, h = self.loadimage(settings.icon_dir + '/' + type_image, (vspace-content.spacing, vspace-content.spacing)) x_icon = 0 if image: mx = x0 icon_x = vspace x_icon = icon_x if align == 'right': # know how many pixels to offset (dammed negative and max+X # values in (x,y,width) from skin!) r1 = r2 = None if s_val.rectangle: r1 = self.get_item_rectangle(s_val.rectangle, width, s_val.font.h)[2] if n_val.rectangle: r2 = self.get_item_rectangle(n_val.rectangle, width, n_val.font.h)[2] min_rx = 0 max_rw = width if r1: min_rx = min(min_rx, r1.x) max_rw = max(max_rw, r1.width) if r2: min_rx = min(min_rx, r2.x) max_rw = max(max_rw, r2.width) mx = x0 + width + hskip + (max_rw + min_rx - width) - icon_x x_icon = 0 self.drawimage(image, (mx, y0)) if val.rectangle: r = self.get_item_rectangle(val.rectangle, width, val.font.h)[2] wdg_x = x0 + hskip + r.x + x_icon - BOX_UNDER_ICON * x_icon wdg_y = y0 + vskip + r.y self.drawroundbox(x0 + hskip + r.x + x_icon - BOX_UNDER_ICON * x_icon, y0 + vskip + r.y, r.width - icon_x + BOX_UNDER_ICON * icon_x, r.height, r) # lets draw the image if present. This in 99% caes will be used for hihliting menu items # so no need for fancy sizing, just fill inn whole area if hasattr(val, 'fcontent'): for i in val.fcontent: if isinstance(i, xml_skin.FormatImg): r = self.get_item_rectangle(i, width, val.font.h)[ 2 ] wdg_x = x0 + hskip + r.x + x_icon - BOX_UNDER_ICON * x_icon wdg_y = y0 + vskip + r.y self.drawimage(i.src, (x0 + hskip + r.x + x_icon - BOX_UNDER_ICON * x_icon, y0 + vskip + r.y, r.width - icon_x + BOX_UNDER_ICON * icon_x, r.height)) # special handling for tv shows if choice.type == 'video' and hasattr(choice,'tv_show') and \ choice.tv_show and (val.align=='left' or val.align=='') and \ (content.align=='left' or content.align=='') and not config.SKIN_HANDLES_DETAILS: sn = choice.show_name if last_tvs[0] == sn[0]: tvs_w = last_tvs[1] else: season = 0 episode = 0 for c in menu.choices: if c.type == 'video' and hasattr(c,'tv_show') and \ c.tv_show and c.show_name[0] == sn[0]: # do not use val.font.stringsize because this will # add shadow and outline values we add later for the # normal text again. So just use val.font.font.stringsize stringsize = val.font.font.stringsize season = max(season, stringsize(c.show_name[1])) episode = max(episode, stringsize(c.show_name[2])) if tvs_shortname and not c.image: tvs_shortname = False else: all_tvs = False if all_tvs and not tvs_shortname and len(menu.choices) > 5: tvs_shortname = True if all_tvs and tvs_shortname: tvs_w = val.font.stringsize('x') + season + episode else: tvs_w = val.font.stringsize('%s x' % sn[0]) + season + episode last_tvs = (sn[0], tvs_w) wdg_x = x0 + hskip + icon_x + tvs_w wdg_y = y0 + vskip self.drawstring(' - %s' % sn[3], val.font, content, x=x0 + hskip + icon_x + tvs_w, y=y0 + vskip, width=width-icon_x-tvs_w, height=-1, align_h='left', dim=False, mode='hard') self.drawstring(sn[2], val.font, content, x=x0 + hskip + icon_x + tvs_w - 100, y=y0 + vskip, width=100, height=-1, align_h='right', dim=False, mode='hard') if all_tvs and tvs_shortname: text = '%sx' % sn[1] else: text = '%s %sx' % (sn[0], sn[1]) # if the menu has an attr table, the menu is a table. Each # item _must_ have that many tabs as the table needs!!! if hasattr(menu, 'table'): table_x = x0 + hskip + x_icon if hasattr(choice, 'table_fields'): table_text = choice.table_fields else: table_text = text.split('\t') if len(table_text) < len(menu.table): if not text.lower().find('playlist'): # we only log error if this is a real item, not a playlist logger.error('Menu item: %r doesn\'t have enough table entries!', menu) table_text.extend([''] * (len(menu.table) - len(table_text))) for i in range(len(menu.table)): table_w = ((width-icon_x-len(table_text)*5)*menu.table[i]) / 100 if i != len(menu.table) - 1: table_w += 5 x_mod = 0 if table_text[i].find('ICON_') == 0: x_mod, table_text[i] = text_or_icon(settings, table_text[i], table_x, table_w, val.font) if not isinstance(table_text[i], basestring): self.drawimage(table_text[i], (table_x + x_mod, y0 + vskip)) table_text[i] = '' if table_text[i]: wdg_x = table_x + x_mod wdg_y = y0 + vskip self.drawstring(table_text[i], val.font, content, x=table_x + x_mod, y=y0 + vskip, width=table_w, height=-1, align_h=val.align, mode='hard', dim=False) table_x += table_w + 5 else: wdg_x = x0 + hskip + x_icon wdg_y = y0 + vskip self.drawstring(text, val.font, content, x=x0 + hskip + x_icon, y=y0 + vskip, width=width-icon_x, height=-1, align_h=val.align, mode='hard', dim=True) elif content.type == 'image' or content.type == 'image+text': rec_h = val.height if content.type == 'image+text': rec_h += int(1.1 * val.font.h) if val.align == 'center': x0 = item_x0 + (hspace - val.width) / 2 else: x0 = item_x0 + hskip if val.valign == 'center': y0 = item_y0 + (vspace - rec_h) / 2 else: y0 = item_y0 + vskip if val.rectangle: if content.type == 'image+text': r = self.get_item_rectangle(val.rectangle, val.width, max(rec_h, int(val.font.h * 1.1)))[2] else: r = self.get_item_rectangle(val.rectangle, val.width, rec_h)[2] self.drawroundbox(x0 + r.x, y0 + r.y, r.width, r.height, r) image_key = generate_cache_key(settings, choice, val.width, val.height, True) if image_key in format_imagecache: image, i_w, i_h = format_imagecache[image_key] if image_key in remove_images: # Make sure we remove the selected/unselected version # from the cancel list. for v in (s_val, n_val): i_k = generate_cache_key(settings, choice, v.width, v.height, True) if i_k in remove_images: remove_images.remove(i_k) addx = 0 addy = 0 if val.align == 'center' and i_w < val.width: addx = (val.width - i_w) / 2 if val.align == 'right' and i_w < val.width: addx = val.width - i_w if val.valign == 'center' and i_h < val.height: addy = (val.height - i_h) / 2 if val.valign == 'bottom' and i_h < val.height: addy = val.height - i_h wdg_x = x0 + addx wdg_y = y0 + addy self.drawimage(image, (x0 + addx, y0 + addy)) if val.shadow and val.shadow.visible and image.get_alpha() == None: wdg_x = x0 + addx + val.shadow.x wdg_y = y0 + addy + val.shadow.y self.drawroundbox(x0 + addx + val.shadow.x, y0 + addy + val.shadow.y, image.get_width(), image.get_height(), (val.shadow.color, 0, 0, 0)) else: for v in (s_val, n_val): image_key = generate_cache_key(settings, choice, v.width, v.height, True) if image_key in remove_images: remove_images.remove(image_key) if image_key not in self.loading_images and image_key not in format_imagecache: hp = choice == menu.selected formatter = AsyncImageFormatter(settings, choice, v.width, v.height, True, anamorphic, hp, v == n_val) formatter.connect(self.__image_loaded, image_key) self.loading_images[image_key] = formatter self.drawroundbox(x0, y0, val.width, val.height, (0, 1, 0xffffff, 0)) if content.type == 'image+text': wdg_x = x0 wdg_y = y0 + val.height text = choice.list_name if hasattr(choice, 'list_name') else choice.name self.drawstring(text, val.font, content, x=x0, y=y0 + val.height, width=val.width, height=-1, align_h=val.align, mode='hard', ellipses='', dim=False) else: print 'no support for content type %s' % content.type if current_col == cols: if content.align == 'center': item_x0 = content.x + (content.width - cols * hspace) / 2 else: item_x0 = content.x item_y0 += vspace current_col = 1 else: item_x0 += hspace current_col += 1 choice.rect = pygame.Rect(wdg_x, wdg_y, wdg_w, wdg_h) # print arrow: try: if menuw.menu_items[0] != menu.choices[0] and area.images['uparrow']: self.drawimage(area.images['uparrow'].filename, area.images['uparrow']) if menuw.menu_items[-1] != menu.choices[-1] and area.images['downarrow']: if isinstance(area.images['downarrow'].y, types.TupleType): v = copy.copy(area.images['downarrow']) v.y = eval_attr(v.y, (item_y0-vskip)) else: v = area.images['downarrow'] self.drawimage(area.images['downarrow'].filename, v) except: # empty menu / missing images pass for image_key in remove_images: if image_key in self.loading_images: self.loading_images[image_key].cancelled = True del self.loading_images[image_key] self.last_choices = (menu.selected, copy.copy(menuw.menu_items))
def update_content(self): """ update the listing area """ menuw = self.menuw menu = self.menu settings = self.settings layout = self.layout area = self.area_val content = self.calc_geometry(layout.content, copy_object=True) to_listing = menu.table n_cols = len(to_listing[0])-1 col_time = 30 font_h, label_width, label_txt_width, y0, num_rows, item_h, head_h = \ self.get_items_geometry(settings, menu)[:-1] label_val, head_val, selected_val, default_val, scheduled_val, overlap_val,\ past_val, current_val = self.all_vals leftarrow = None if area.images['leftarrow']: i = area.images['leftarrow'] leftarrow, w, h = self.loadimage(i.filename, i) if leftarrow: leftarrow_size = (leftarrow.get_width(), leftarrow.get_height()) rightarrow = None if area.images['rightarrow']: i = area.images['rightarrow'] rightarrow, w, h = self.loadimage(i.filename, i) if rightarrow: rightarrow_size = (rightarrow.get_width(), rightarrow.get_height()) x_contents = content.x + content.spacing y_contents = content.y + content.spacing w_contents = content.width - 2 * content.spacing h_contents = content.height - 2 * content.spacing # Print the Date of the current list page dateformat = config.TV_DATE_FORMAT timeformat = config.TV_TIME_FORMAT if not timeformat: timeformat = '%H:%M' if not dateformat: dateformat = '%e-%b' r = Geometry( 0, 0, label_width, font_h ) if label_val.rectangle: r = self.get_item_rectangle( label_val.rectangle, label_width, head_h )[ 2 ] pad_x = 0 pad_y = 0 if r.x < 0: pad_x = -1 * r.x if r.y < 0: pad_y = -1 * r.y x_contents += r.width y_contents += r.height w_contents -= r.width h_contents -= r.width # 1 sec = x pixels prop_1sec = float(w_contents) / float(n_cols * col_time * 60) col_size = prop_1sec * 1800 # 30 minutes ig = Geometry( 0, 0, col_size, head_h ) if head_val.rectangle: ig, r2 = self.fit_item_in_rectangle( head_val.rectangle, col_size, head_h, head_h ) self.drawroundbox( x_contents - r.width, y_contents - r.height, r.width+1, head_h+1, r ) # use label padding for x; head padding for y self.drawstring( Unicode(time.strftime(dateformat, time.localtime(to_listing[0][1]))), head_val.font, content, x=( x_contents - r.width + pad_x ), y=( y_contents - r.height + ig.y ), width=( r.width - 2 * pad_x ), height=-1, align_v='center', align_h=head_val.align ) # Print the time at the table's top x0 = x_contents ty0 = y_contents - r.height for i in range( n_cols ): self.drawroundbox(math.floor(x0), ty0, math.floor( col_size + x0 ) - math.floor( x0 ) + 1, head_h + 1, r2) self.drawstring(Unicode(time.strftime(timeformat, time.localtime(to_listing[0][i+1]))), head_val.font, content, x=( x0 + ig.x ), y=( ty0 + ig.y ), width=ig.width, height=-1, align_v='center', align_h=head_val.align) x0 += col_size # define start and stop time date = time.strftime("%x", time.localtime()) start_time = to_listing[0][1] stop_time = to_listing[0][-1] stop_time += (col_time*60) now_time = time.time() # selected program: selected_prog = to_listing[1] for i in range(2,len(to_listing)): ty0 = y0 tx0 = content.x logo_geo = [ tx0, ty0, label_width, font_h ] if label_val.rectangle: r = self.get_item_rectangle(label_val.rectangle, label_width, item_h)[2] if r.x < 0: tx0 -= r.x if r.y < 0: ty0 -= r.y val = default_val self.drawroundbox(tx0 + r.x, ty0 + r.y, r.width+1, item_h, r) logo_geo =[ tx0+r.x+r.size, ty0+r.y+r.size, r.width-2*r.size, r.height-2*r.size ] channel_logo = config.TV_LOGOS + '/' + to_listing[i].id + '.png' if os.path.isfile(channel_logo): channel_logo, w, h = self.loadimage(channel_logo, (r.width+1-2*r.size, item_h-2*r.size)) else: channel_logo = None if channel_logo: self.drawimage(channel_logo, (logo_geo[0], logo_geo[1])) else: self.drawstring(to_listing[i].displayname, label_val.font, content, x=tx0, y=ty0, width=r.width+2*r.x, height=item_h) self.drawroundbox(tx0 + r.x, ty0 + r.y, r.width+1, item_h, r) if to_listing[i].programs: for prg in to_listing[i].programs: flag_left = 0 flag_right = 0 if prg.start < start_time: flag_left = 1 x0 = x_contents t_start = start_time else: x0 = x_contents + int(float(prg.start-start_time) * prop_1sec) t_start = prg.start if prg.stop > stop_time: flag_right = 1 w = w_contents + x_contents - x0 x1 = x_contents + w_contents else: w = int( float(prg.stop - t_start) * prop_1sec ) x1 = x_contents + int(float(prg.stop-start_time) * prop_1sec) if prg.title == selected_prog.title and \ prg.channel_id == selected_prog.channel_id and \ prg.start == selected_prog.start and \ prg.stop == selected_prog.stop: val = selected_val elif hasattr(prg, 'overlap') and prg.overlap: val = overlap_val elif hasattr(prg, 'scheduled') and prg.scheduled: val = scheduled_val elif now_time >= prg.start and now_time <= prg.stop: val = current_val elif now_time > prg.stop: val = past_val else: val = default_val font = val.font try: if prg.title == _('This channel has no data loaded'): val = copy.copy(val) val.align='center' except UnicodeError: pass if x0 > x1: break # text positions tx0 = x0 tx1 = x1 ty0 = y0 # calc the geometry values ig = Geometry(0, 0, tx1-tx0+1, item_h) if val.rectangle: ig, r = self.fit_item_in_rectangle(val.rectangle, tx1-tx0+1, item_h, font_h) self.drawroundbox(tx0+r.x, ty0+r.y, r.width, item_h, r) # draw left flag and reduce width and add to x0 if flag_left: tx0 += leftarrow_size[0] ig.width -= leftarrow_size[0] if tx0 < tx1: self.drawimage(leftarrow, (tx0-leftarrow_size[0], ty0 +\ (item_h-leftarrow_size[1])/2)) # draw right flag and reduce width and x1 if flag_right: tx1 -= rightarrow_size[0] ig.width -= rightarrow_size[0] if tx0 < tx1: self.drawimage(rightarrow, (tx1, ty0 + (item_h-rightarrow_size[1])/2)) # draw the text if tx0 < tx1: self.drawstring(prg.title, font, content, x=tx0+ig.x, y=ty0+ig.y, width=ig.width, height=ig.height, align_v='center', align_h = val.align) i += 1 y0 += item_h - 1 if config.SKIN_GUIDE_SHOW_NOW_LINE and \ start_time < now_time and now_time <= stop_time: tx = x_contents + int(float(now_time-start_time) * prop_1sec) ty = content.y + 1 w = prop_1sec * 60 self.drawroundbox(tx, ty, w, y0 - ty, (current_val.font.color,0,0,0)) # print arrow: if menuw.display_up_arrow and area.images['uparrow']: self.drawimage(area.images['uparrow'].filename, area.images['uparrow']) if menuw.display_down_arrow and area.images['downarrow']: if isinstance(area.images['downarrow'].y, types.TupleType): v = copy.copy(area.images['downarrow']) v.y = eval_attr(v.y, y0) else: v = area.images['downarrow'] self.drawimage(area.images['downarrow'].filename, v)
def update_content(self): """ update the listing area """ menuw = self.menuw menu = self.menu settings = self.settings layout = self.layout area = self.area_val content = self.calc_geometry(layout.content, copy_object=True) cols, rows, hspace, vspace, hskip, vskip, width = \ self.get_items_geometry(settings, menu, self.display_style) BOX_UNDER_ICON = self.xml_settings.box_under_icon if not len(menu.choices): val = content.types['default'] self.drawstring(_('This directory is empty'), content.font, content) if content.align == 'center': item_x0 = content.x + (content.width - cols * hspace) / 2 else: item_x0 = content.x if content.valign == 'center': item_y0 = content.y + (content.height - rows * vspace) / 2 else: item_y0 = content.y current_col = 1 if content.type == 'image': width = hspace - content.spacing height = vspace - content.spacing last_tvs = ('', 0) all_tvs = True tvs_shortname = True anamorphic = self.xml_settings.anamorphic self.image_loaded = False remove_images = self.loading_images.keys() for choice in menuw.menu_items: if hasattr(choice, 'dirty'): choice.dirty = False items_geometry = self.last_get_items_geometry[1] # Widget Sizes wdg_x = 0 wdg_y = 0 wdg_w = items_geometry[2] wdg_h = items_geometry[3] if content.types.has_key('%s selected' % choice.type): s_val = content.types['%s selected' % choice.type] else: s_val = content.types['selected'] if content.types.has_key(choice.type): n_val = content.types[choice.type] else: n_val = content.types['default'] if choice == menu.selected: val = s_val else: val = n_val text = choice.name if not text: text = "unknown" type_image = None if hasattr(val, 'icon'): type_image = val.icon if not choice.icon and not type_image: if choice.type == 'playlist': text = 'PL: %s' % text if choice.type == 'dir' and choice.parent and \ choice.parent.type != 'mediamenu': text = '[%s]' % text if content.type == 'text': x0 = item_x0 y0 = item_y0 icon_x = 0 image = None align = val.align or content.align if choice != menu.selected and hasattr(choice, 'outicon') and \ choice.outicon: image, w, h = self.loadimage( choice.outicon, (vspace - content.spacing, vspace - content.spacing)) elif choice.icon: image, w, h = self.loadimage( choice.icon, (vspace - content.spacing, vspace - content.spacing)) if not image and type_image: image, w, h = self.loadimage( settings.icon_dir + '/' + type_image, (vspace - content.spacing, vspace - content.spacing)) x_icon = 0 if image: mx = x0 icon_x = vspace x_icon = icon_x if align == 'right': # know how many pixels to offset (dammed negative and max+X # values in (x,y,width) from skin!) r1 = r2 = None if s_val.rectangle: r1 = self.get_item_rectangle( s_val.rectangle, width, s_val.font.h)[2] if n_val.rectangle: r2 = self.get_item_rectangle( n_val.rectangle, width, n_val.font.h)[2] min_rx = 0 max_rw = width if r1: min_rx = min(min_rx, r1.x) max_rw = max(max_rw, r1.width) if r2: min_rx = min(min_rx, r2.x) max_rw = max(max_rw, r2.width) mx = x0 + width + hskip + (max_rw + min_rx - width) - icon_x x_icon = 0 self.drawimage(image, (mx, y0)) if val.rectangle: r = self.get_item_rectangle(val.rectangle, width, val.font.h)[2] wdg_x = x0 + hskip + r.x + x_icon - BOX_UNDER_ICON * x_icon wdg_y = y0 + vskip + r.y self.drawroundbox( x0 + hskip + r.x + x_icon - BOX_UNDER_ICON * x_icon, y0 + vskip + r.y, r.width - icon_x + BOX_UNDER_ICON * icon_x, r.height, r) # special handling for tv shows if choice.type == 'video' and hasattr(choice,'tv_show') and \ choice.tv_show and (val.align=='left' or val.align=='') and \ (content.align=='left' or content.align==''): sn = choice.show_name if last_tvs[0] == sn[0]: tvs_w = last_tvs[1] else: season = 0 episode = 0 for c in menu.choices: if c.type == 'video' and hasattr(c,'tv_show') and \ c.tv_show and c.show_name[0] == sn[0]: # do not use val.font.stringsize because this will # add shadow and outline values we add later for the # normal text again. So just use val.font.font.stringsize stringsize = val.font.font.stringsize season = max(season, stringsize(c.show_name[1])) episode = max(episode, stringsize(c.show_name[2])) if tvs_shortname and not c.image: tvs_shortname = False else: all_tvs = False if all_tvs and not tvs_shortname and len( menu.choices) > 5: tvs_shortname = True if all_tvs and tvs_shortname: tvs_w = val.font.stringsize('x') + season + episode else: tvs_w = val.font.stringsize( '%s x' % sn[0]) + season + episode last_tvs = (sn[0], tvs_w) wdg_x = x0 + hskip + icon_x + tvs_w wdg_y = y0 + vskip self.drawstring(' - %s' % sn[3], val.font, content, x=x0 + hskip + icon_x + tvs_w, y=y0 + vskip, width=width - icon_x - tvs_w, height=-1, align_h='left', dim=False, mode='hard') self.drawstring(sn[2], val.font, content, x=x0 + hskip + icon_x + tvs_w - 100, y=y0 + vskip, width=100, height=-1, align_h='right', dim=False, mode='hard') if all_tvs and tvs_shortname: text = '%sx' % sn[1] else: text = '%s %sx' % (sn[0], sn[1]) # if the menu has an attr table, the menu is a table. Each # item _must_ have that many tabs as the table needs!!! if hasattr(menu, 'table'): table_x = x0 + hskip + x_icon if hasattr(choice, 'table_fields'): table_text = choice.table_fields else: table_text = text.split('\t') if len(table_text) < len(menu.table): logger.error( 'Menu item: %r doesn\'t have enough table entries!' ) table_text.extend([''] * (len(menu.table) - len(table_text))) for i in range(len(menu.table)): table_w = ((width - icon_x - len(table_text) * 5) * menu.table[i]) / 100 if i != len(menu.table) - 1: table_w += 5 x_mod = 0 if table_text[i].find('ICON_') == 0: x_mod, table_text[i] = text_or_icon( settings, table_text[i], table_x, table_w, val.font) if not isinstance(table_text[i], basestring): self.drawimage(table_text[i], (table_x + x_mod, y0 + vskip)) table_text[i] = '' if table_text[i]: wdg_x = table_x + x_mod wdg_y = y0 + vskip self.drawstring(table_text[i], val.font, content, x=table_x + x_mod, y=y0 + vskip, width=table_w, height=-1, align_h=val.align, mode='hard', dim=False) table_x += table_w + 5 else: wdg_x = x0 + hskip + x_icon wdg_y = y0 + vskip self.drawstring(text, val.font, content, x=x0 + hskip + x_icon, y=y0 + vskip, width=width - icon_x, height=-1, align_h=val.align, mode='hard', dim=True) elif content.type == 'image' or content.type == 'image+text': rec_h = val.height if content.type == 'image+text': rec_h += int(1.1 * val.font.h) if val.align == 'center': x0 = item_x0 + (hspace - val.width) / 2 else: x0 = item_x0 + hskip if val.valign == 'center': y0 = item_y0 + (vspace - rec_h) / 2 else: y0 = item_y0 + vskip if val.rectangle: if content.type == 'image+text': r = self.get_item_rectangle( val.rectangle, val.width, max(rec_h, int(val.font.h * 1.1)))[2] else: r = self.get_item_rectangle(val.rectangle, val.width, rec_h)[2] self.drawroundbox(x0 + r.x, y0 + r.y, r.width, r.height, r) image_key = generate_cache_key(settings, choice, val.width, val.height, True) if image_key in format_imagecache: image, i_w, i_h = format_imagecache[image_key] if image_key in remove_images: # Make sure we remove the selected/unselected version # from the cancel list. for v in (s_val, n_val): i_k = generate_cache_key(settings, choice, v.width, v.height, True) if i_k in remove_images: remove_images.remove(i_k) addx = 0 addy = 0 if val.align == 'center' and i_w < val.width: addx = (val.width - i_w) / 2 if val.align == 'right' and i_w < val.width: addx = val.width - i_w if val.valign == 'center' and i_h < val.height: addy = (val.height - i_h) / 2 if val.valign == 'bottom' and i_h < val.height: addy = val.height - i_h wdg_x = x0 + addx wdg_y = y0 + addy self.drawimage(image, (x0 + addx, y0 + addy)) if val.shadow and val.shadow.visible and image.get_alpha( ) == None: wdg_x = x0 + addx + val.shadow.x wdg_y = y0 + addy + val.shadow.y self.drawroundbox(x0 + addx + val.shadow.x, y0 + addy + val.shadow.y, image.get_width(), image.get_height(), (val.shadow.color, 0, 0, 0)) else: for v in (s_val, n_val): image_key = generate_cache_key(settings, choice, v.width, v.height, True) if image_key in remove_images: remove_images.remove(image_key) if image_key not in self.loading_images and image_key not in format_imagecache: hp = choice == menu.selected formatter = AsyncImageFormatter( settings, choice, v.width, v.height, True, anamorphic, hp, v == n_val) formatter.connect(self.__image_loaded, image_key) self.loading_images[image_key] = formatter self.drawroundbox(x0, y0, val.width, val.height, (0, 1, 0xffffff, 0)) if content.type == 'image+text': wdg_x = x0 wdg_y = y0 + val.height self.drawstring(choice.name, val.font, content, x=x0, y=y0 + val.height, width=val.width, height=-1, align_h=val.align, mode='hard', ellipses='', dim=False) else: print 'no support for content type %s' % content.type if current_col == cols: if content.align == 'center': item_x0 = content.x + (content.width - cols * hspace) / 2 else: item_x0 = content.x item_y0 += vspace current_col = 1 else: item_x0 += hspace current_col += 1 choice.rect = pygame.Rect(wdg_x, wdg_y, wdg_w, wdg_h) # print arrow: try: if menuw.menu_items[0] != menu.choices[0] and area.images[ 'uparrow']: self.drawimage(area.images['uparrow'].filename, area.images['uparrow']) if menuw.menu_items[-1] != menu.choices[-1] and area.images[ 'downarrow']: if isinstance(area.images['downarrow'].y, types.TupleType): v = copy.copy(area.images['downarrow']) v.y = eval_attr(v.y, (item_y0 - vskip)) else: v = area.images['downarrow'] self.drawimage(area.images['downarrow'].filename, v) except: # empty menu / missing images pass for image_key in remove_images: if image_key in self.loading_images: self.loading_images[image_key].cancelled = True del self.loading_images[image_key] self.last_choices = (menu.selected, copy.copy(menuw.menu_items))
def update_content(self): """ update the listing area """ menuw = self.menuw menu = self.menu settings = self.settings layout = self.layout area = self.area_val content = self.calc_geometry(layout.content, copy_object=True) to_listing = menu.table n_cols = len(to_listing[0]) - 1 col_time = 30 font_h, label_width, label_txt_width, y0, num_rows, item_h, head_h = \ self.get_items_geometry(settings, menu)[:-1] label_val, head_val, selected_val, default_val, scheduled_val, overlap_val,\ past_val, current_val = self.all_vals leftarrow = None if area.images['leftarrow']: i = area.images['leftarrow'] leftarrow = self.loadimage(i.filename, i) if leftarrow: leftarrow_size = (leftarrow.get_width(), leftarrow.get_height()) rightarrow = None if area.images['rightarrow']: i = area.images['rightarrow'] rightarrow = self.loadimage(i.filename, i) if rightarrow: rightarrow_size = (rightarrow.get_width(), rightarrow.get_height()) x_contents = content.x + content.spacing y_contents = content.y + content.spacing w_contents = content.width - 2 * content.spacing h_contents = content.height - 2 * content.spacing # Print the Date of the current list page dateformat = config.TV_DATE_FORMAT timeformat = config.TV_TIME_FORMAT if not timeformat: timeformat = '%H:%M' if not dateformat: dateformat = '%e-%b' r = Geometry(0, 0, label_width, font_h) if label_val.rectangle: r = self.get_item_rectangle(label_val.rectangle, label_width, head_h)[2] pad_x = 0 pad_y = 0 if r.x < 0: pad_x = -1 * r.x if r.y < 0: pad_y = -1 * r.y x_contents += r.width y_contents += r.height w_contents -= r.width h_contents -= r.width # 1 sec = x pixels prop_1sec = float(w_contents) / float(n_cols * col_time * 60) col_size = prop_1sec * 1800 # 30 minutes ig = Geometry(0, 0, col_size, head_h) if head_val.rectangle: ig, r2 = self.fit_item_in_rectangle(head_val.rectangle, col_size, head_h, head_h) self.drawroundbox(x_contents - r.width, y_contents - r.height, r.width + 1, head_h + 1, r) # use label padding for x; head padding for y self.drawstring(Unicode( time.strftime(dateformat, time.localtime(to_listing[0][1]))), head_val.font, content, x=(x_contents - r.width + pad_x), y=(y_contents - r.height + ig.y), width=(r.width - 2 * pad_x), height=-1, align_v='center', align_h=head_val.align) # Print the time at the table's top x0 = x_contents ty0 = y_contents - r.height for i in range(n_cols): self.drawroundbox(math.floor(x0), ty0, math.floor(col_size + x0) - math.floor(x0) + 1, head_h + 1, r2) self.drawstring(Unicode( time.strftime(timeformat, time.localtime(to_listing[0][i + 1]))), head_val.font, content, x=(x0 + ig.x), y=(ty0 + ig.y), width=ig.width, height=-1, align_v='center', align_h=head_val.align) x0 += col_size # define start and stop time date = time.strftime("%x", time.localtime()) start_time = to_listing[0][1] stop_time = to_listing[0][-1] stop_time += (col_time * 60) now_time = time.time() # selected program: selected_prog = to_listing[1] for i in range(2, len(to_listing)): ty0 = y0 tx0 = content.x logo_geo = [tx0, ty0, label_width, font_h] if label_val.rectangle: r = self.get_item_rectangle(label_val.rectangle, label_width, item_h)[2] if r.x < 0: tx0 -= r.x if r.y < 0: ty0 -= r.y val = default_val self.drawroundbox(tx0 + r.x, ty0 + r.y, r.width + 1, item_h, r) logo_geo = [ tx0 + r.x + r.size, ty0 + r.y + r.size, r.width - 2 * r.size, r.height - 2 * r.size ] channel_logo = config.TV_LOGOS + '/' + to_listing[i].id + '.png' if os.path.isfile(channel_logo): channel_logo = self.loadimage( channel_logo, (r.width + 1 - 2 * r.size, item_h - 2 * r.size)) else: channel_logo = None if channel_logo: self.drawimage(channel_logo, (logo_geo[0], logo_geo[1])) else: self.drawstring(to_listing[i].displayname, label_val.font, content, x=tx0, y=ty0, width=r.width + 2 * r.x, height=item_h) self.drawroundbox(tx0 + r.x, ty0 + r.y, r.width + 1, item_h, r) if to_listing[i].programs: for prg in to_listing[i].programs: flag_left = 0 flag_right = 0 if prg.start < start_time: flag_left = 1 x0 = x_contents t_start = start_time else: x0 = x_contents + int( float(prg.start - start_time) * prop_1sec) t_start = prg.start if prg.stop > stop_time: flag_right = 1 w = w_contents + x_contents - x0 x1 = x_contents + w_contents else: w = int(float(prg.stop - t_start) * prop_1sec) x1 = x_contents + int( float(prg.stop - start_time) * prop_1sec) if prg.title == selected_prog.title and \ prg.channel_id == selected_prog.channel_id and \ prg.start == selected_prog.start and \ prg.stop == selected_prog.stop: val = selected_val elif prg.overlap: val = overlap_val elif prg.scheduled: val = scheduled_val elif now_time >= prg.start and now_time <= prg.stop: val = current_val elif now_time > prg.stop: val = past_val else: val = default_val font = val.font try: if prg.title == _('This channel has no data loaded'): val = copy.copy(val) val.align = 'center' except UnicodeError: pass if x0 > x1: break # text positions tx0 = x0 tx1 = x1 ty0 = y0 # calc the geometry values ig = Geometry(0, 0, tx1 - tx0 + 1, item_h) if val.rectangle: ig, r = self.fit_item_in_rectangle( val.rectangle, tx1 - tx0 + 1, item_h, font_h) self.drawroundbox(tx0 + r.x, ty0 + r.y, r.width, item_h, r) # draw left flag and reduce width and add to x0 if flag_left: tx0 += leftarrow_size[0] ig.width -= leftarrow_size[0] if tx0 < tx1: self.drawimage(leftarrow, (tx0-leftarrow_size[0], ty0 +\ (item_h-leftarrow_size[1])/2)) # draw right flag and reduce width and x1 if flag_right: tx1 -= rightarrow_size[0] ig.width -= rightarrow_size[0] if tx0 < tx1: self.drawimage(rightarrow, (tx1, ty0 + (item_h - rightarrow_size[1]) / 2)) # draw the text if tx0 < tx1: self.drawstring(prg.title, font, content, x=tx0 + ig.x, y=ty0 + ig.y, width=ig.width, height=ig.height, align_v='center', align_h=val.align) i += 1 y0 += item_h - 1 # print arrow: if menuw.display_up_arrow and area.images['uparrow']: self.drawimage(area.images['uparrow'].filename, area.images['uparrow']) if menuw.display_down_arrow and area.images['downarrow']: if isinstance(area.images['downarrow'].y, types.TupleType): v = copy.copy(area.images['downarrow']) v.y = eval_attr(v.y, y0) else: v = area.images['downarrow'] self.drawimage(area.images['downarrow'].filename, v)