1
# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2
2
'''Albums tab which displays albums and allows users to select them'''
3
# pylint: disable-msg=W1001
9
from entertainerlib.gui.tabs.tab import Tab
10
from entertainerlib.gui.widgets.image_menu import ImageMenu
11
from entertainerlib.gui.widgets.image_menu_item import ImageMenuItem
12
from entertainerlib.gui.widgets.label import Label
13
from entertainerlib.gui.widgets.list_indicator import ListIndicator
14
from entertainerlib.gui.widgets.loading_animation import (
16
from entertainerlib.gui.widgets.texture import Texture
19
'''Tab to show album listings'''
21
def __init__(self, albums, move_to_new_screen_callback, name="albums",
22
tab_title=_("Albums")):
23
Tab.__init__(self, name, tab_title, move_to_new_screen_callback)
25
# Start the loading animation while the menu is loading
26
self.throbber = LoadingAnimation(40,
27
clutter.Color(255, 255, 255, 255),
28
clutter.Color(128, 128, 128, 128))
29
self.throbber.set_position(self.get_abs_x(0.1), self.get_abs_y(0.1))
31
self.add(self.throbber)
34
# XXX: laymansterms - This is "less than elegant." I'm not fixing
35
# ImageMenu right now so we can't get rid of tex_size_x and y yet.
36
# We really need to eliminate the concept tex_size_y, but it will
37
# have to wait for now.
39
tex_size_x = self.get_abs_x(x_percent)
40
tex_size_y = self.get_abs_y(0.5208)
43
elif len(albums) < 13:
45
tex_size_x = self.get_abs_x(x_percent)
46
tex_size_y = self.get_abs_y(0.2604)
51
tex_size_x = self.get_abs_x(x_percent)
52
tex_size_y = self.get_abs_y(0.1953)
57
self.menu = ImageMenu(self.theme)
58
self.menu.set_row_count(row_count)
59
self.menu.set_visible_column_count(visible)
60
self.menu.set_item_size(tex_size_x, tex_size_y)
63
self.default_cover = Texture(self.theme.getImage("default_album_art"))
65
gobject.timeout_add(50, self._async_menu_build, albums, x_percent)
67
self.menu.set_position(self.get_abs_x(0.0586), self.get_abs_y(0.1823))
68
self.menu.set_active(False)
71
if self.config.show_effects():
72
self.menu.set_animate(True)
76
self.li = ListIndicator(0.18, 0.045, ListIndicator.HORIZONTAL)
77
self.li.set_position(self.get_abs_x(0.9297) - self.li.get_width(),
78
self.get_abs_y(0.7943))
79
self.li.set_delimiter(" | ")
80
self.li.set_maximum(len(albums))
81
self.li.set_current(1)
85
# Create album information (displays current menuitem information)
86
self.album_title = Label(0.045, "title", 0.22, 0.79, "")
87
self.album_title.set_ellipsize(pango.ELLIPSIZE_END)
88
self.album_title.width = 0.366
89
self.add(self.album_title)
91
self.album_artist = Label(0.037, "subtitle", 0.22, 0.86, "")
92
self.album_artist.set_ellipsize(pango.ELLIPSIZE_END)
93
self.album_artist.width = 0.366
94
self.add(self.album_artist)
96
self.album_tracks = Label(0.037, "subtitle", 0.22, 0.91, "")
97
self.add(self.album_tracks)
99
self._selected_album = None
100
gobject.timeout_add(50, self._init_selected_album)
102
def _async_menu_build(self, albums, item_size_percent):
104
This function is called as an async callback. It is also a recursive
105
function. This allows us to load menu items in the background without
106
blocking the user interface.
109
# Check if we should stop recursive calls (menu is complete)
112
if album.has_album_art():
113
texture = Texture(album.get_album_art_url())
115
texture = clutter.CloneTexture(self.default_cover)
117
item = ImageMenuItem(item_size_percent, 1, texture)
118
item.set_userdata(album)
119
self.menu.add_actor(item)
120
# Recursive call, remove first album from the list
121
gobject.timeout_add(25, self._async_menu_build, albums[1:],
126
# Done loading the albums, notify gobject to stop calling menu build
129
def _init_selected_album(self):
130
'''The menu is loaded dynamically so the current menu item may not be
131
available initially. Keep trying until the value is available'''
133
self._selected_album = \
134
self.menu.get_current_menuitem().get_userdata()
138
# Item must not be available yet, continue to call
141
def _get_selected_album(self):
142
'''Get the currently selected album from the menu'''
143
return self.menu.get_current_menuitem().get_userdata()
145
selected_album = property(_get_selected_album)
147
def can_activate(self):
148
'''Albums tab will always be created from an existing artist with at
152
def set_active(self, boolean):
154
Override method from parent class.
155
@param boolean: True to set this tab active, False to set inactive
157
Tab.set_active(self, boolean)
159
self._update_album_info(
160
self.menu.get_current_menuitem().get_userdata())
161
self.menu.set_active(True)
163
self.menu.set_active(False)
165
def _update_album_info(self, album):
166
'''Update the album information labels'''
167
self.album_title.set_text(album.get_title())
168
self.album_artist.set_text(album.get_artist())
169
self.album_tracks.set_text(_("%(total)s tracks") % \
170
{'total': album.get_number_of_tracks()})
172
def _update_menu(self, direction):
173
'''Update the menu based on the provided menu direction'''
174
self.menu.move(direction)
175
self._update_album_info(self.menu.get_current_menuitem().get_userdata())
176
self.li.set_current(self.menu.get_current_position() + 1)
179
def _handle_up(self):
180
'''Handle the up user event'''
181
if self.menu.get_cursor_position()[1] == 0:
182
return True # Move control back to tab bar
184
return self._update_menu(self.menu.UP)
186
def _handle_down(self):
187
'''Handle the down user event'''
188
return self._update_menu(self.menu.DOWN)
190
def _handle_left(self):
191
'''Handle the left user event'''
192
return self._update_menu(self.menu.LEFT)
194
def _handle_right(self):
195
'''Handle the right user event'''
196
return self._update_menu(self.menu.RIGHT)
198
def _handle_select(self):
199
'''Handle the select user event'''
200
album = self.menu.get_current_menuitem().get_userdata()
201
kwargs = { 'album' : album }
202
self.callback("album", kwargs)