示例#1
0
class ScrollMenuItem(clutter.Group):
    """A Group containing a Label to which a LoopedPathBehaviour is applied."""
    __gtype_name__ = 'ScrollMenuItem'

    def __init__(self, alpha, text, item_height, font_size, color_name):
        clutter.Group.__init__(self)

        self.label = Label(font_size, color_name, 0, 0)
        self.label.set_text(text)

        self.behaviour = LoopedPathBehaviour(alpha)
        self.behaviour.apply(self)

        self.add(self.label)
示例#2
0
class ScrollMenuItem(clutter.Group):
    """A Group containing a Label to which a LoopedPathBehaviour is applied."""

    __gtype_name__ = "ScrollMenuItem"

    def __init__(self, alpha, text, item_height, font_size, color_name):
        clutter.Group.__init__(self)

        self.label = Label(font_size, color_name, 0, 0)
        self.label.set_text(text)

        self.behaviour = LoopedPathBehaviour(alpha)
        self.behaviour.apply(self)

        self.add(self.label)
示例#3
0
class Album(Screen):
    '''Screen that allows user to browse and play tracks of the music album.'''

    def __init__(self, media_player, music_library, move_to_new_screen_callback,
        album):
        Screen.__init__(self, 'Album', move_to_new_screen_callback)

        self.media_player = media_player
        self.theme = self.config.theme
        self.library = music_library
        self.album = album
        self.art = None
        self.track_menu = None

        # Create and initialize screen items
        self.track_menu = self._create_track_menu()
        self.add(self.track_menu)
        self._create_album_cover_texture()
        self._create_album_info()

        self.screen_title = Label(0.13, "screentitle", 0, 0.87, "")
        self.screen_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.screen_title.width = 0.8
        self.add(self.screen_title)

        #List indicator
        self.li = ListIndicator(0.74, 0.85, 0.2, 0.045, ListIndicator.VERTICAL)
        self.li.set_maximum(len(self.album.tracks))
        self.add(self.li)

        self.track_menu.active = True
        self.track_menu.connect('selected', self._on_menu_selected)
        self.track_menu.connect('moved', self._display_selected_track)

    def _create_album_cover_texture(self):
        """
        Create a texture that is displayed next to track list. This texture
        displays album cover art.
        """
        if(self.album.has_album_art()):
            pixbuf = gtk.gdk.pixbuf_new_from_file(self.album.album_art_url)
        else:
            pixbuf = gtk.gdk.pixbuf_new_from_file(
                self.theme.getImage("default_album_art"))
        self.art = EyeCandyTexture(0.1, 0.13, 0.3148, 0.5599, pixbuf)
        self.art.set_rotation(clutter.Y_AXIS, 25, 0, 0, 0)
        self.add(self.art)

    def _create_album_info(self):
        """
        Create album info labels.
        """
        if self.album.year != 0:
            album_text = self.album.title + ", " + str(self.album.year)
        else:
            album_text = self.album.title
        album = Label(0.0416, "text", 0.5, 0.13, album_text, font_weight="bold")
        album.set_ellipsize(pango.ELLIPSIZE_END)
        album.set_line_wrap(False)
        album.width = 0.45
        self.add(album)

        length = str(self.album.length / 60)
        num_of_tracks_text = _("%(total)s tracks, %(time)s minutes") % \
            {'total': len(self.album.tracks), 'time': length}
        num_of_tracks = Label(0.028, "subtitle", 0.5, 0.18,
            num_of_tracks_text, font_weight="bold")
        self.add(num_of_tracks)

    def _create_track_menu(self):
        """
        Create track menu. This menu contains list of all tracks on album.
        """
        menu = TextMenu(0.4978, 0.2344, 0.4393, 0.0781)

        tracks = self.album.tracks
        tracks_list = [[track.title, track.length_string, track] \
            for track in tracks]
        menu.async_add(tracks_list)

        return menu

    def is_interested_in_play_action(self):
        """
        Override function from Screen class. See Screen class for
        better documentation.
        """
        return True

    def execute_play_action(self):
        """
        Override function from Screen class. See Screen class for
        better documentation.
        """
        track = self.track_menu.selected_userdata
        self.media_player.set_media(track)
        self.media_player.play()

    def _handle_up(self):
        '''Handle UserEvent.NAVIGATE_UP.'''
        self.track_menu.up()

    def _handle_down(self):
        '''Handle UserEvent.NAVIGATE_DOWN.'''
        self.track_menu.down()

    def _handle_select(self, event=None):
        '''Handle UserEvent.NAVIGATE_SELECT.'''
        track = self.track_menu.selected_userdata
        kwargs = { 'track' : track }
        self.callback("audio_play", kwargs)

    def _on_menu_selected(self, actor=None):
        '''Handle a *select command* if an item was selected.'''
        self._handle_select()

    def _display_selected_track(self, actor=None):
        '''Update of the list indicator and the screen's title'''
        self.li.set_current(self.track_menu.selected_index + 1)
        track = self.track_menu.selected_userdata
        self.screen_title.set_text(track.artist)
        self.screen_title.show()
示例#4
0
class VideoClipsTab(Tab):
    """
    Tab can be used as part of the TabGroup

    Tab is a very simple container that contains all the widgets and logic
    of the tab page.
    """

    def __init__(self, media_player, video_library, move_to_new_screen_callback,
        name="clips", tab_title=_("Video clips")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)
        self.media_player = media_player
        self.video_library = video_library
        self.theme = self.config.theme
        self.list_indicator = None
        self.clip_info = None
        self.menu = None
        self.clip_title = None

        if self.video_library.get_number_of_video_clips() == 0:
            self._create_empty_library_notice()
        else:
            # Start the loading animation while the menu is loading
            self.throbber = LoadingAnimation(0.7, 0.1)
            self.throbber.show()
            self.add(self.throbber)

            self.menu = self._create_menu()
            self.add(self.menu)
            self.menu.connect("moved", self._update_clip_info)
            self.menu.connect("selected", self._handle_select)
            self.menu.connect("activated", self._on_activated)
            self.menu.connect("filled", self._on_menu_filled)

            self.connect('activated', self._on_activated)
            self.connect('deactivated', self._on_deactivated)

    def can_activate(self):
        """
        Allow if we have some movies indexed.
        """
        if self.video_library.get_number_of_video_clips() == 0:
            return False
        else:
            return True

    def _create_empty_library_notice(self):
        """
        Create an information box that is displayed if there are no indexed
        movies.
        """
        message = _(
            "There are no indexed Video Clips in the Entertainer media "
            "library. Please add some folders containing video clips "
            "to the Library using the configuration tool.")
        Tab.show_empty_tab_notice(self, _("No video clips available!"), message)

    def _create_menu(self):
        """
        Create a view that is displayed when there are indexed clips in
        the video library.
        """
        menu = ImageMenu(0.04, 0.16, 0.23, self.y_for_x(0.23) * 0.7)
        menu.items_per_col = 2
        menu.visible_rows = 2
        menu.visible_cols = 4

        clips = self.video_library.get_video_clips()
        clips_list = [[clip.thumbnail_url, clip] for clip in clips]
        menu.async_add_clips(clips_list)

        # Create list indicator
        self.list_indicator = ListIndicator(0.7, 0.8, 0.2, 0.045,
            ListIndicator.HORIZONTAL)
        self.list_indicator.set_maximum(len(clips))
        self.list_indicator.show()
        self.add(self.list_indicator)

        # Create information labels
        self.clip_title = Label(0.042, "title", 0.15, 0.77, "",
            font_weight="bold")
        self.clip_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.clip_title.set_line_wrap(False)
        self.clip_title.width = 0.5
        self.add(self.clip_title)

        self.clip_info = Label(0.034, "subtitle", 0.15, 0.85, "")
        self.clip_info.set_ellipsize(pango.ELLIPSIZE_END)
        self.clip_info.set_line_wrap(False)
        self.clip_info.width = 0.5
        self.add(self.clip_info)

        return menu

    def _update_clip_info(self, event=None):
        '''Update the VideoClip information labels.'''
        if self.active:
            clip = self.menu.selected_userdata
            (folder, filename) = os.path.split(clip.filename)
            self.clip_title.set_text(filename)
            self.clip_info.set_text(folder)
            self.list_indicator.show()
            self.list_indicator.set_current(self.menu.selected_index + 1)
        else:
            self.clip_title.set_text("")
            self.clip_info.set_text("")
            self.list_indicator.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        clip = self.menu.selected_userdata
        self.media_player.set_media(clip)
        self.media_player.play()
        self.callback("video_osd")
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_clip_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_clip_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#5
0
class TvEpisodes(Screen):
    '''Screen contains list of all episodes of one specific season.'''

    def __init__(self, media_player, move_to_new_screen_callback, episodes,
        tv_series):
        Screen.__init__(self, 'TvEpisodes', move_to_new_screen_callback)

        self.episodes = episodes
        self.media_player = media_player
        self.theme = self.config.theme
        self.tv_series = tv_series

        # Screen Title (Displayed at the bottom left corner)
        screen_title = Label(0.13, "screentitle", 0, 0.87, self.tv_series.title)
        self.add(screen_title)

        self.scroll_area = None
        self.title = None
        self.thumb = None
        self.menu = self._create_episode_menu()
        self.add(self.menu)
        self._create_episode_info_box()

        #List indicator
        self.li = ListIndicator(0.8, 0.9, 0.2, 0.045, ListIndicator.VERTICAL)
        self.li.set_maximum(len(self.episodes))
        self.add(self.li)

        self.menu.connect("moved", self._update_episode_info)
        self.menu.connect("selected", self._handle_select)
        self.menu.connect("activated", self._on_menu_activated)

    def _create_episode_menu(self):
        """Create a list of available seasons."""
        menu = TextMenu(0.4978, 0.1563, 0.4393, 0.0781)

        episodes_list = [[_("%(num)d. %(title)s") % \
            {'num': episode.number, 'title': episode.title},
            None, episode] for episode in self.episodes]
        menu.async_add(episodes_list)

        menu.active = True

        return menu

    def _create_thumbnail_texture(self):
        """Create a thumbnail texture. This is called as menu is scrolled."""
        if self.thumb:
            self.thumb.hide()

        # Thumbnail. Use cover art if thumbnail doesn't exist
        thumbnail = self.menu.selected_userdata.thumbnail_url
        if(thumbnail is not None):
            pixbuf = gtk.gdk.pixbuf_new_from_file(thumbnail)
            thumb_width = 0.2928
            thumb_height = 0.2799
            thumb_x = 0.05
            thumb_y = 0.2
        else:
            thumb_width = 0.1098
            thumb_height = 0.2799
            thumb_x = 0.20
            thumb_y = 0.15
            if(self.tv_series.has_cover_art()):
                pixbuf = gtk.gdk.pixbuf_new_from_file(
                    self.tv_series.cover_art_url)
            else:
                pixbuf = gtk.gdk.pixbuf_new_from_file(
                    self.theme.getImage("default_movie_art"))

        self.thumb = EyeCandyTexture(thumb_x, thumb_y, thumb_width,
            thumb_height, pixbuf)
        self.add(self.thumb)

    def _create_episode_info_box(self):
        """
        Create a texture that is displayed next to track list. This texture
        displays album cover art.
        """
        self._create_thumbnail_texture()

        # Title
        self.title = Label(0.04, "title", 0.05, 0.55,
            self.menu.selected_userdata.title, font_weight="bold")
        self.title.set_ellipsize(pango.ELLIPSIZE_END)
        self.title.set_line_wrap(False)
        self.title.width = 0.4
        self.add(self.title)

        # Plot
        plot = Label(0.029, "subtitle", 0, 0, self.menu.selected_userdata.plot)
        plot.width = 0.4

        self.scroll_area = ScrollArea(0.05, 0.63, 0.4, 0.15, plot)
        self.scroll_area.connect("activated", self._on_scroll_area_activated)
        self.add(self.scroll_area)

    def _update_episode_info(self, event=None):
        '''Update information from this episode.'''
        self.li.set_current(self.menu.selected_index + 1)

        self._create_thumbnail_texture()
        self.title.set_text(self.menu.selected_userdata.title)
        self.title.width = 0.4

        plot = Label(0.029, "subtitle", 0, 0, self.menu.selected_userdata.plot)
        plot.width = 0.4
        self.scroll_area.set_content(plot)

    def _handle_up(self):
        '''Handle UserEvent.NAVIGATE_UP.'''
        if self.menu.active:
            self.menu.up()
        else:
            self.scroll_area.scroll_up()

    def _handle_down(self):
        '''Handle UserEvent.NAVIGATE_DOWN.'''
        if self.menu.active:
            self.menu.down()
        else:
            self.scroll_area.scroll_down()

    def _handle_left(self):
        '''Handle UserEvent.NAVIGATE_LEFT.'''
        self.menu.active = False
        self.scroll_area.active = True

    def _handle_right(self):
        '''Handle UserEvent.NAVIGATE_RIGHT.'''
        self.menu.active = True
        self.scroll_area.active = False

    def _handle_select(self, event=None):
        '''Handle UserEvent.NAVIGATE_SELECT.'''
        episode = self.menu.selected_userdata
        self.media_player.set_media(episode)
        self.media_player.play()
        self.callback("video_osd")

    def _on_menu_activated(self, event=None):
        '''Handle menu activation.'''
        self.scroll_area.active = False

    def _on_scroll_area_activated(self, event=None):
        '''Handle scroll_area activation.'''
        self.menu.active = False
示例#6
0
class Photographs(Screen):
    '''Screen displays a grid of selectable photograph thumbnails.'''

    def __init__(self, move_to_new_screen_callback, title, images):
        Screen.__init__(self, 'Photographs', move_to_new_screen_callback)

        self.images = images

        # Screen Title (Displayed at the bottom left corner)
        screen_title = Label(0.13, "screentitle", 0, 0.87, title)
        self.add(screen_title)

        # Image Title (over album list)
        self.image_title = Label(0.04167, "title", 0.0586, 0.7943, " ")
        self.image_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.add(self.image_title)

        self.image_desc = Label(0.04167, "subtitle", 0.0586, 0.9115, " ")
        self.image_desc.set_line_wrap(True)
        self.image_desc.set_ellipsize(pango.ELLIPSIZE_END)
        self.add(self.image_desc)

        # Display throbber animation while loading photographs
        self.throbber = LoadingAnimation(0.9, 0.9)
        self.throbber.show()
        self.add(self.throbber)

        # List indicator
        self.li = None
        self._create_list_indicator()

        # Create photomenu
        self.menu = ImageMenu(0.03, 0.08, 0.12, self.y_for_x(0.12))
        self.menu.items_per_col = 3
        self.menu.visible_rows = 3
        self.menu.visible_cols = 8
        self.menu.active = True
        self.add(self.menu)

        photos = self.images
        photos_list = [[Texture(photo.get_thumbnail_url()), photo] \
            for photo in photos]
        self.menu.async_add(photos_list)

        self.menu.connect("selected", self._handle_select)
        self.menu.connect('moved', self._update_image_info)
        self.menu.connect("filled", self._on_menu_filled)

    def _update_image_info(self, event=None):
        """Update image information box."""
        image = self.images[self.menu.selected_index]
        name = image.get_title()
        desc = image.get_description()
        self.image_title.set_text(name)
        self.image_title.set_size(0.366, 0.04167)
        self.image_desc.set_text(desc)
        self.image_desc.set_size(0.366, 0.0911)
        self.li.set_current(self.menu.selected_index + 1)

    def _create_list_indicator(self):
        '''Create list indicator for albums list.'''
        self.li = ListIndicator(0.77, 0.8, 0.18, 0.045,
            ListIndicator.HORIZONTAL)
        self.li.set_maximum(len(self.images))
        self.add(self.li)

    def _handle_up(self):
        '''Handle UserEvent.NAVIGATE_UP.'''
        self.menu.up()

    def _handle_down(self):
        '''Handle UserEvent.NAVIGATE_DOWN.'''
        self.menu.down()

    def _handle_left(self):
        '''Handle UserEvent.NAVIGATE_LEFT.'''
        self.menu.left()

    def _handle_right(self):
        '''Handle UserEvent.NAVIGATE_RIGHT.'''
        self.menu.right()

    def _handle_select(self, event=None):
        '''Handle UserEvent.NAVIGATE_SELECT.'''
        index = self.menu.selected_index
        kwargs = {'current_photo_index' : index, 'images' : self.images}
        self.callback("photo", kwargs)

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#7
0
class TextMenuItem(MenuItem):
    """A menuitem widget that contains one or two labels."""

    def __init__(self, width, height, text, extra_text=None):
        MenuItem.__init__(self)

        self.width = width
        self.height = height
        self.theme = self.config.theme

        self.text = text
        self.extra_text = extra_text
        self.color = "menuitem_inactive"
        self.font_size = 0.03

        self.label = Label(self.font_size, self.color, 0, 0, "",
            "text_label")
        self.add(self.label)

        # Set extra text
        self.extra_label = None
        if extra_text is not None:
            self.extra_label = Label(self.font_size, self.color, 0, 0,
                "", "text_label")
            self.add(self.extra_label)

        self.update(text, extra_text)

    def animate_in(self):
        """Set labels font-size and color when an item gets selected."""
        self.font_size = 0.037
        self.color = "menuitem_active"
        self.update()

    def animate_out(self):
        """Set labels font-size and color when an item gets unselected."""
        self.font_size = 0.03
        self.color = "menuitem_inactive"
        self.update()

    def update(self, text=None, extra_text=None):
        """Updates text and dimensions of a TextMenuItem."""
        if text is None:
            text = self.text
        else:
            self.text = text

        if extra_text is None:
            extra_text = self.extra_text
        else:
            self.extra_text = extra_text

        try:
            first_line = text[:text.index('\n')]
        except ValueError:
            first_line = text

        self.label.font_size = self.font_size
        self.label.set_text(first_line)
        self.label.position = (0.01, (self.height - self.label.height) / 2)
        self.label.set_line_wrap(False)
        self.label.set_ellipsize(pango.ELLIPSIZE_END)

        # Set extra text
        if extra_text is not None:
            self.extra_label.font_size = self.font_size
            self.extra_label.set_text(extra_text)
            self.extra_label.position = (
                self.width * 0.98 - self.extra_label.width,
                (self.height - self.extra_label.height) / 2)

            self.label.width = (self.width - self.extra_label.width) * 0.9
        else:
            self.label.width = self.width * 0.95

        self.label.color = self.color
        if self.extra_label:
            self.extra_label.color = self.color
示例#8
0
class MoviesTab(Tab):
    """
    Tab can be used as part of the TabGroup

    Tab is a very simple container that contains all the widgets and logic
    of the tab page.
    """

    def __init__(self, video_library, move_to_new_screen_callback,
        name="movies", tab_title=_("Movies")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)

        self.video_library = video_library
        self.theme = self.config.theme
        self.list_indicator = None
        self.movie_info = None
        self.menu = None
        self.movie_plot = None
        self.movie_title = None

        if self.video_library.get_number_of_movies() == 0:
            self._create_empty_library_notice()
        else:
            # Start the loading animation while the menu is loading
            self.throbber = LoadingAnimation(0.1, 0.1)
            self.throbber.show()
            self.add(self.throbber)

            self.menu = self._create_menu()
            self.add(self.menu)
            self.menu.connect("moved", self._update_movie_info)
            self.menu.connect("selected", self._handle_select)
            self.menu.connect("activated", self._on_activated)
            self.menu.connect("filled", self._on_menu_filled)

            self.connect('activated', self._on_activated)
            self.connect('deactivated', self._on_deactivated)

    def can_activate(self):
        """
        Allow if we have some movies indexed.
        """
        if self.video_library.get_number_of_movies() == 0:
            return False
        else:
            return True

    def _create_empty_library_notice(self):
        """
        Create an information box that is displayed if there are no indexed
        movies.
        """
        message = _(
            "There are no indexed movies in Entertainer media library.  To "
            "add movies, click on 'content' button on toolbar and open "
            "'videos' tab. Now click on 'add' button and select some folders "
            "which contains movie files.")
        Tab.show_empty_tab_notice(self, _("No movies available!"), message)

    def _create_menu(self):
        """
        Create a view that is displayed when there is indexed movies in
        the video library.
        """
        #Create movie menu
        menu = ImageMenu(0.06, 0.18, 0.12, 0.25)
        menu.items_per_col = 2
        menu.visible_rows = 2
        menu.visible_cols = 7

        movies = self.video_library.get_movies()
        movies_list = [[movie.cover_art_url, movie] for movie in movies]
        menu.async_add_videos(movies_list)

        # Create list indicator
        self.list_indicator = ListIndicator(0.75, 0.76, 0.2, 0.045,
            ListIndicator.HORIZONTAL)
        self.list_indicator.set_maximum(len(movies))
        self.show()
        self.add(self.list_indicator)

        # Create information labels
        self.movie_title = Label(0.042, "title", 0.2, 0.75, "",
            font_weight="bold")
        self.movie_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.movie_title.set_line_wrap(False)
        self.movie_title.width = 0.5
        self.add(self.movie_title)

        self.movie_info = Label(0.034, "subtitle", 0.2, 0.8, "")
        self.movie_info.set_ellipsize(pango.ELLIPSIZE_END)
        self.movie_info.set_line_wrap(False)
        self.movie_info.width = 0.5
        self.add(self.movie_info)

        self.movie_plot = Label(0.025, "subtitle", 0.2, 0.85, "")
        self.movie_plot.width = 0.7
        self.add(self.movie_plot)

        return menu

    def _update_movie_info(self, event=None):
        '''Update the movie information labels.'''
        if self.active:
            movie = self.menu.selected_userdata
            genres = movie.genres
            if len(genres) > 1:
                genre = genres[0] + "/" + genres[1]
            else:
                genre = genres[0]

            self.movie_title.set_text(_("%(title)s (%(year)s)") % \
                {'title': movie.title, 'year': movie.year})
            self.movie_info.set_text(_("%(min)d min, (%(genre)s)") % \
                {'min': movie.runtime, 'genre': genre})
            self.movie_plot.set_text(movie.short_plot)
            self.list_indicator.show()
            self.list_indicator.set_current(self.menu.selected_index + 1)
        else:
            self.movie_title.set_text("")
            self.movie_info.set_text("")
            self.movie_plot.set_text("")
            self.list_indicator.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        movie = self.menu.selected_userdata
        kwargs = { 'movie' : movie }
        self.callback("movie", kwargs)
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_movie_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_movie_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#9
0
class TracksTab(Tab):
    '''Tab for the artist screen to show track listings'''

    def __init__(self, tracks, move_to_new_screen_callback, name="tracks",
        tab_title=_("Tracks")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)

        # Start the loading animation while the menu is loading
        self.throbber = LoadingAnimation(0.1, 0.1)
        self.throbber.show()
        self.add(self.throbber)

        self.menu = TextMenu(0.0586, 0.2083, 0.2928, 0.0781)
        self.menu.items_per_row = 3
        self.menu.visible_rows = 7
        self.menu.visible_cols = 3
        self.menu.active = False
        self.menu.cursor = None
        self.add(self.menu)

        tracks_list = [[track.title, None, track] for track in tracks]
        self.menu.async_add_artists(tracks_list)

        self.track_title = Label(0.045, "title", 0.22, 0.79, "")
        self.track_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.track_title.set_line_wrap(False)
        self.track_title.width = 0.366
        self.add(self.track_title)

        self.track_number = Label(0.037, "subtitle", 0.22, 0.86, "")
        self.track_number.set_ellipsize(pango.ELLIPSIZE_END)
        self.track_number.set_line_wrap(False)
        self.track_number.width = 0.366
        self.add(self.track_number)

        self.track_length = Label(0.037, "subtitle", 0.22, 0.91, "")
        self.add(self.track_length)

        self.li = ListIndicator(0.77, 0.8, 0.18, 0.045,
            ListIndicator.VERTICAL)
        self.li.set_maximum(len(tracks))
        self.li.show()
        self.add(self.li)

        self.connect('activated', self._on_activated)
        self.connect('deactivated', self._on_deactivated)
        self.menu.connect("moved", self._update_track_info)
        self.menu.connect("selected", self._handle_select)
        self.menu.connect("activated", self._on_activated)
        self.menu.connect("filled", self._on_menu_filled)

    def can_activate(self):
        '''Tracks tab will always be created from an existing artist with at
        least one track.'''
        return True

    def _update_track_info(self, event=None):
        '''Update the track information labels'''
        if self.active:
            track = self.menu.selected_userdata
            self.track_title.set_text(track.title)
            self.track_length.set_text(track.length_string)
            self.track_number.set_text(_("Track %(track)d from %(album)s") % \
                {'track': track.number, 'album': track.album.title})
            self.li.show()
            self.li.set_current(self.menu.selected_index + 1)
        else:
            self.track_title.set_text("")
            self.track_length.set_text("")
            self.track_number.set_text("")
            self.li.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        track = self.menu.selected_userdata
        kwargs = { 'track' : track }
        self.callback("audio_play", kwargs)
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_track_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_track_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#10
0
class ListIndicator(Base, clutter.Group):
    """
    ListIndicator displays 'current / maximum' value label and arrows.
    """

    # Direction
    # HORIZONTAL layout: ARROW_LEFT current / maximum ARROW_RIGHT
    # VERITCAL layout:   current / maximum ARROW_UP ARROW_DOWN
    HORIZONTAL = 0
    VERTICAL = 1

    def __init__(self, x, y, width, height, direction):
        Base.__init__(self)
        clutter.Group.__init__(self)

        self.config = Configuration()

        # Size
        self.width = self.get_abs_x(width)
        self.height = self.get_abs_y(height)

        self.direction = direction
        self.delimiter = " | "
        self.current = 1
        self.maximum = 1

        self.theme = self.config.theme
        self.fg = self.theme.get_color("arrow_foreground")
        self.bg = self.theme.get_color("arrow_background")

        if direction == ListIndicator.VERTICAL:
            text_x_pos = width / 3
        else:
            text_x_pos = width / 2

        self.text = Label(
            height * 0.8, "text", text_x_pos, height / 2,
            str(self.maximum) + self.delimiter + str(self.maximum))
        self.text.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
        self.add(self.text)

        # Create arrows and calculate positions on screen
        if direction == ListIndicator.VERTICAL:
            self.arrow1 = ArrowTexture(5 * width / 7, height / 2, height / 2,
                                       self.fg, self.bg, ArrowTexture.UP)
            self.arrow2 = ArrowTexture(6 * width / 7, height / 2, height / 2,
                                       self.fg, self.bg, ArrowTexture.DOWN)

        elif direction == ListIndicator.HORIZONTAL:
            self.arrow1 = ArrowTexture(height / 2, height / 2, height / 2,
                                       self.fg, self.bg, ArrowTexture.LEFT)
            self.arrow2 = ArrowTexture(6 * width / 7, height / 2, height / 2,
                                       self.fg, self.bg, ArrowTexture.RIGHT)

        self.add(self.arrow1)
        self.add(self.arrow2)

        self.set_position(self.get_abs_x(x), self.get_abs_y(y))

    def set_current(self, value):
        """
        Set current value
        @param number: Current value (between 1 - maximum)
        """
        if value > 0 and value <= self.maximum:
            self.current = value
            self._update_text()

            # Bounce arrow if user has reached the limit
            if self.current == 1:
                self.arrow1.bounce()
            elif self.current == self.maximum:
                self.arrow2.bounce()

    def get_current(self):
        """
        Get current value
        @return Current value (integer)
        """
        return self.current

    def set_maximum(self, value):
        """
        Set maximum value of the indicator
        @param number: Set maximum value
        """
        self.maximum = value
        self._update_text()

    def get_maximum(self):
        """
        Get maximum value.
        @return Max value (integer)
        """
        return self.maximum

    def set_delimiter(self, delimiter):
        """
        Set delimiter text that is displayed between current and maximum value.
        Default delimiter text is ' / ' spaces included.
        @param delimiter: delimiter text
        """
        self.delimiter = delimiter
        self._update_text()

    def show_position(self):
        """
        Show position text that indicates the current position of the content.
        """
        self.text.show()

    def hide_position(self):
        """
        Hide position text that indicates the current position of the content.
        If this is called then indicator shows only arrows.
        """
        self.text.hide()

    def _update_text(self):
        """Update the text label"""

        self.text.set_text(
            str(self.current) + self.delimiter + str(self.maximum))
示例#11
0
class Main(Screen):
    '''Screen displayed when frontend is opened and provides main navigation.'''

    # Size of the preview area
    PREVIEW_WIDTH = 830
    PREVIEW_HEIGHT = 580

    # Directions
    UP = 0
    DOWN = 1

    def __init__(self, media_player, move_to_new_screen_callback):
        Screen.__init__(self, 'Main', move_to_new_screen_callback)

        self.media_player = media_player
        self.media_player.connect("stop", self.update)
        self.media_player.connect("play", self.update)
        self.media_player.connect('refresh', self._update_preview_title)

        self.theme = self.config.theme

        self._preview_title = None
        self.preview = clutter.Group() # Group that contains preview actors
        self.preview.set_position(self.get_abs_x(0.07), self.get_abs_y(0.1))
        self.preview.show()
        self.preview.set_opacity(0x00)
        self.add(self.preview)

        self.menu = self._create_main_menu()
        self.add(self.menu)

        self._update_preview_area()

        self.add(ClockLabel(0.13, "screentitle", 0, 0.87))

        self.menu.connect('selected', self._handle_select)
        self.menu.connect('moved', self._on_menu_moved)

        self.menu.active = True

    def get_type(self):
        """Return screen type."""
        return Screen.NORMAL

    def get_name(self):
        """Return screen name (human readble)."""
        return "Main"

    def _create_main_menu(self):
        """Create main menu of the home screen."""
        menu = ScrollMenu(10, 60, 0.045, "menuitem_active")
        menu.set_name("mainmenu")

        menu.add_item(_("Play CD"), "disc")
        menu.add_item(_("Videos"), "videos")
        menu.add_item(_("Music"), "music")
        menu.add_item(_("Photographs"), "photo")

        if self.config.display_weather_in_client:
            menu.add_item(_("Weather"), "weather")

        if self.media_player.has_media():
            menu.add_item(_("Playing now..."), "playing")

        menu.visible_items = 5
        menu.selected_index = 2

        # Menu position
        menu_clip = menu.visible_items * 70
        menu_y = int((self.config.stage_height - menu_clip + 10) / 2)
        menu.set_position(self.get_abs_x(0.75), menu_y)

        return menu

    def _create_playing_preview(self):
        '''Create the Now Playing preview sidebar.'''
        preview = clutter.Group()

        # Video preview of current media
        video_texture = self.media_player.get_texture()
        if video_texture == None:
            video_texture = Texture(self.theme.getImage("default_album_art"))
        width, height = video_texture.get_size()
        x_ratio = (self.PREVIEW_WIDTH - 50) / float(width)
        y_ratio = (self.PREVIEW_HEIGHT - 50) / float(height)

        if x_ratio > y_ratio:
            video_texture.set_scale((self.PREVIEW_HEIGHT - 50) / float(height),
                                    (self.PREVIEW_HEIGHT - 50) / float(height))
            new_width = int(width * \
                ((self.PREVIEW_HEIGHT - 50) / float(height)))
            new_x = int(((self.PREVIEW_WIDTH - 50) - new_width) / 2.0)
            video_texture.set_position(int(new_x), 0)
            # Below are size and position calculations for border rectangle
            rect_x = new_x -3
            rect_y = -3
            new_width = (self.PREVIEW_HEIGHT - 50) / float(height) * width
            new_height = (self.PREVIEW_HEIGHT - 50) / float(height) * height
        else:
            video_texture.set_scale((self.PREVIEW_WIDTH - 50) / float(width),
                                    (self.PREVIEW_WIDTH - 50) / float(width))
            new_height = int(height * \
                ((self.PREVIEW_WIDTH - 50) / float(width)))
            new_y = int(((self.PREVIEW_HEIGHT - 50) - new_height) / 2.0)
            video_texture.set_position(0, int(new_y))
            rect_x = -3
            rect_y = new_y -3
            # Below are size and position calculations for border rectangle
            new_width = (self.PREVIEW_WIDTH - 50) / float(width) * width
            new_height = (self.PREVIEW_WIDTH - 50) / float(width) * height

        # Video frame
        rect = clutter.Rectangle()
        rect.set_size(int(new_width + 6), int(new_height + 6))
        rect.set_position(rect_x, rect_y)
        rect.set_color((128, 128, 128, 192))
        preview.add(rect)

        preview.add(video_texture)

        self._preview_title = Label(0.03, "text", 0.03, 0.74, "")
        preview.add(self._preview_title)

        return preview

    def _update_preview_title(self, event=None):
        '''Update the label showing the currently playing media.'''
        if self._preview_title != None:
            title_text = _("Now Playing: %(title)s (%(pos)s/%(length)s)") % \
                {'title': self.media_player.get_media_title(), 
                'pos': self.media_player.get_media_position_string(),
                'length': self.media_player.get_media_duration_string()}
            self._preview_title.set_text(title_text)

    def _update_preview_area(self):
        '''Update the preview area to display the current menu item.'''
        self.preview.remove_all()
        item = self.menu.get_selected()

        self.preview.set_opacity(0x00)

        update = True

        if item.get_name() == "playing":
            self.preview.add(self._create_playing_preview())
        else:
            update = False

        # If the preview was updated fade it in.
        if update:
            fade_in = clutter.Timeline(500)
            alpha_in = clutter.Alpha(fade_in, clutter.EASE_IN_OUT_SINE)
            self.behaviour = clutter.BehaviourOpacity(0, 255, alpha_in)
            self.behaviour.apply(self.preview)
            fade_in.start()

    def update(self, event=None):
        """
        Update screen widgets. This is called always when screen is poped from
        the screen history. Updates main menu widget.
        """
        if self.media_player.is_playing and \
                (self.menu.get_index("playing") == -1):
            self.menu.add_item(_("Playing now..."), "playing")
        elif not self.media_player.is_playing and \
                (self.menu.get_index("playing") != -1):
            self.menu.remove_item("playing")

        self.menu.refresh()
        self._update_preview_area()

    def _handle_up(self):
        '''Handle UserEvent.NAVIGATE_UP.'''
        self.menu.scroll_up()

    def _handle_down(self):
        '''Handle UserEvent.NAVIGATE_DOWN.'''
        self.menu.scroll_down()

    def _handle_select(self, event=None):
        '''Handle UserEvent.NAVIGATE_SELECT.'''
        item = self.menu.get_selected()

        if item.get_name() == "disc":
            self.callback("audio_cd")
        elif item.get_name() == "playing":
            self.callback("video_osd")
        elif item.get_name() == "music":
            self.callback("music")
        elif item.get_name() == "videos":
            self.callback("video")
        elif item.get_name() == "weather":
            self.callback("weather")
        elif item.get_name() == "photo":
            self.callback("photo_albums")

    def _on_menu_moved(self, event):
        '''Update preview area when selected item changed on the menu.'''
        self._update_preview_area()
示例#12
0
class PlayingTab(Tab):
    '''Tab for the audio play screen to show currently playing audio.'''

    def __init__(self, media_player, track, name="playing",
            tab_title=_("Currently playing")):
        Tab.__init__(self, name, tab_title)

        album = track.album

        # Track name
        if track.number == 0:
            track_label_text = track.title
        else:
            track_label_text =  _("From %(number)d. %(title)s") % \
                {'number': track.number, 'title': track.title}

        self.track_label = Label(0.05, "text", 0.5, 0.33, track_label_text)
        self.track_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.track_label.width = 0.4
        self.add(self.track_label)

        # Album name
        if album.year == 0:
            album_label_text = _("From %(title)s") % {'title': album.title}
        else:
            album_label_text = _("From %(title)s, %(year)s") % \
                {'title': album.title, 'year': album.year}

        self.album_label = Label(0.042, "subtitle", 0.5, 0.43, album_label_text)
        self.album_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.album_label.width = 0.4
        self.add(self.album_label)

        # Artist name
        artist_text = _("By %(artist)s") % {'artist': track.artist}
        self.artist_label = Label(0.042, "subtitle", 0.5, 0.53, artist_text)
        self.artist_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.artist_label.width = 0.4
        self.add(self.artist_label)

        self.progress_bar = ProgressBar(0.5, 0.667, 0.4, 0.04)
        self.progress_bar.media_player = media_player
        self.add(self.progress_bar)

    def update(self, track):
        '''
        Called when currently playing changes tracks. The provided track
        is used to update all the necessary labels.
        '''
        album = track.album

        if track.number == 0:
            self.track_label.set_text(track.title)
        else:
            self.track_label.set_text(str(track.number) + ". " + track.title)

        if album.year != 0:
            self.album_label.set_text(_("From %(title)s, %(year)s") % \
            {'title': album.title, 'year': album.year})
        else:
            self.album_label.set_text(_("From %(album)s") % \
                {'album': album.title})
            self.artist_label.set_text(_("By %(artist)s") % \
                {'artist': track.artist})

    def can_activate(self):
        '''No interaction is available on the PlayingTab.'''
        return False
示例#13
0
class ListIndicator(Base, clutter.Group):
    """
    ListIndicator displays 'current / maximum' value label and arrows.
    """

    # Direction
    # HORIZONTAL layout: ARROW_LEFT current / maximum ARROW_RIGHT
    # VERITCAL layout:   current / maximum ARROW_UP ARROW_DOWN
    HORIZONTAL = 0
    VERTICAL = 1

    def __init__(self, x, y, width, height, direction):
        Base.__init__(self)
        clutter.Group.__init__(self)

        self.config = Configuration()

        # Size
        self.width = self.get_abs_x(width)
        self.height = self.get_abs_y(height)

        self.direction = direction
        self.delimiter = " | "
        self.current = 1
        self.maximum = 1

        self.theme = self.config.theme
        self.fg = self.theme.get_color("arrow_foreground")
        self.bg = self.theme.get_color("arrow_background")

        if direction == ListIndicator.VERTICAL:
            text_x_pos = width / 3
        else:
            text_x_pos = width / 2

        self.text = Label(height * 0.8, "text", text_x_pos, height / 2,
            str(self.maximum) + self.delimiter + str(self.maximum))
        self.text.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
        self.add(self.text)

        # Create arrows and calculate positions on screen
        if direction == ListIndicator.VERTICAL:
            self.arrow1 = ArrowTexture(5 * width / 7, height / 2, height / 2,
                self.fg, self.bg, ArrowTexture.UP)
            self.arrow2 = ArrowTexture(6 * width / 7, height / 2, height / 2,
                self.fg, self.bg, ArrowTexture.DOWN)

        elif direction == ListIndicator.HORIZONTAL:
            self.arrow1 = ArrowTexture(height / 2, height / 2, height / 2,
                self.fg, self.bg, ArrowTexture.LEFT)
            self.arrow2 = ArrowTexture(6 * width / 7, height / 2, height / 2,
                self.fg, self.bg, ArrowTexture.RIGHT)

        self.add(self.arrow1)
        self.add(self.arrow2)

        self.set_position(self.get_abs_x(x), self.get_abs_y(y))

    def set_current(self, value):
        """
        Set current value
        @param number: Current value (between 1 - maximum)
        """
        if value > 0 and value <= self.maximum:
            self.current = value
            self._update_text()

            # Bounce arrow if user has reached the limit
            if self.current == 1:
                self.arrow1.bounce()
            elif self.current == self.maximum:
                self.arrow2.bounce()

    def get_current(self):
        """
        Get current value
        @return Current value (integer)
        """
        return self.current

    def set_maximum(self, value):
        """
        Set maximum value of the indicator
        @param number: Set maximum value
        """
        self.maximum = value
        self._update_text()

    def get_maximum(self):
        """
        Get maximum value.
        @return Max value (integer)
        """
        return self.maximum

    def set_delimiter(self, delimiter):
        """
        Set delimiter text that is displayed between current and maximum value.
        Default delimiter text is ' / ' spaces included.
        @param delimiter: delimiter text
        """
        self.delimiter = delimiter
        self._update_text()

    def show_position(self):
        """
        Show position text that indicates the current position of the content.
        """
        self.text.show()

    def hide_position(self):
        """
        Hide position text that indicates the current position of the content.
        If this is called then indicator shows only arrows.
        """
        self.text.hide()

    def _update_text(self):
        """Update the text label"""

        self.text.set_text(
            str(self.current) + self.delimiter + str(self.maximum))
示例#14
0
class TextMenuItem(MenuItem):
    """A menuitem widget that contains one or two labels."""
    def __init__(self, width, height, text, extra_text=None):
        MenuItem.__init__(self)

        self.width = width
        self.height = height
        self.theme = self.config.theme

        self.text = text
        self.extra_text = extra_text
        self.color = "menuitem_inactive"
        self.font_size = 0.03

        self.label = Label(self.font_size, self.color, 0, 0, "", "text_label")
        self.add(self.label)

        # Set extra text
        self.extra_label = None
        if extra_text is not None:
            self.extra_label = Label(self.font_size, self.color, 0, 0, "",
                                     "text_label")
            self.add(self.extra_label)

        self.update(text, extra_text)

    def animate_in(self):
        """Set labels font-size and color when an item gets selected."""
        self.font_size = 0.037
        self.color = "menuitem_active"
        self.update()

    def animate_out(self):
        """Set labels font-size and color when an item gets unselected."""
        self.font_size = 0.03
        self.color = "menuitem_inactive"
        self.update()

    def update(self, text=None, extra_text=None):
        """Updates text and dimensions of a TextMenuItem."""
        if text is None:
            text = self.text
        else:
            self.text = text

        if extra_text is None:
            extra_text = self.extra_text
        else:
            self.extra_text = extra_text

        try:
            first_line = text[:text.index('\n')]
        except ValueError:
            first_line = text

        self.label.font_size = self.font_size
        self.label.set_text(first_line)
        self.label.position = (0.01, (self.height - self.label.height) / 2)
        self.label.set_line_wrap(False)
        self.label.set_ellipsize(pango.ELLIPSIZE_END)

        # Set extra text
        if extra_text is not None:
            self.extra_label.font_size = self.font_size
            self.extra_label.set_text(extra_text)
            self.extra_label.position = (
                self.width * 0.98 - self.extra_label.width,
                (self.height - self.extra_label.height) / 2)

            self.label.width = (self.width - self.extra_label.width) * 0.9
        else:
            self.label.width = self.width * 0.95

        self.label.color = self.color
        if self.extra_label:
            self.extra_label.color = self.color
示例#15
0
class AlbumsTab(Tab):
    '''Tab to show album listings'''

    def __init__(self, albums, move_to_new_screen_callback, name="albums",
        tab_title=_("Albums")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)

        # Start the loading animation while the menu is loading
        self.throbber = LoadingAnimation(0.6, 0.1)
        self.throbber.show()
        self.add(self.throbber)

        if len(albums) < 4:
            x_percent = 0.2928
            visible_rows = 1
            visible_cols = 3
        elif len(albums) < 13:
            x_percent = 0.1464
            visible_rows = 2
            visible_cols = 6
        else:
            x_percent = 0.1098
            visible_rows = 3
            visible_cols = 8

        # Create albums menu
        self.menu = ImageMenu(0.07, 0.16, x_percent, self.y_for_x(x_percent))
        self.menu.visible_rows = visible_rows
        self.menu.visible_cols = visible_cols
        self.menu.items_per_col = self.menu.visible_rows
        self.add(self.menu)

        albums_list = [[album.album_art_url, album] for album in albums]
        self.menu.async_add_albums(albums_list)

        self.li = ListIndicator(0.77, 0.8, 0.18, 0.045,
            ListIndicator.HORIZONTAL)
        self.li.set_maximum(len(albums))
        self.li.show()
        self.add(self.li)

        # Create album information (displays current menuitem information)
        self.album_title = Label(0.045, "title", 0.22, 0.79, "")
        self.album_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.album_title.set_line_wrap(False)
        self.album_title.width = 0.366
        self.add(self.album_title)

        self.album_artist = Label(0.037, "subtitle", 0.22, 0.86, "")
        self.album_artist.set_ellipsize(pango.ELLIPSIZE_END)
        self.album_artist.set_line_wrap(False)
        self.album_artist.width = 0.366
        self.add(self.album_artist)

        self.album_tracks = Label(0.037, "subtitle", 0.22, 0.91, "")
        self.add(self.album_tracks)

        self.connect('activated', self._on_activated)
        self.connect('deactivated', self._on_deactivated)
        self.menu.connect("moved", self._update_album_info)
        self.menu.connect("selected", self._handle_select)
        self.menu.connect("activated", self._on_activated)
        self.menu.connect("filled", self._on_menu_filled)

    def can_activate(self):
        '''Albums tab will always be created from an existing artist with at
        least one album.'''
        return True

    def _update_album_info(self, event=None):
        '''Update the album information labels.'''
        if self.active:
            album = self.menu.selected_userdata
            self.album_title.set_text(album.title)
            self.album_artist.set_text(album.artist)
            self.album_tracks.set_text(_("%(total)s tracks") % \
                {'total': len(album.tracks)})
            self.li.show()
            self.li.set_current(self.menu.selected_index + 1)
        else:
            self.album_title.set_text("")
            self.album_artist.set_text("")
            self.album_tracks.set_text("")
            self.li.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        album = self.menu.selected_userdata
        kwargs = { 'album' : album }
        self.callback("album", kwargs)
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_album_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_album_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#16
0
class TvEpisodes(Screen):
    '''Screen contains list of all episodes of one specific season.'''
    def __init__(self, media_player, move_to_new_screen_callback, episodes,
                 tv_series):
        Screen.__init__(self, 'TvEpisodes', move_to_new_screen_callback)

        self.episodes = episodes
        self.media_player = media_player
        self.theme = self.config.theme
        self.tv_series = tv_series

        # Screen Title (Displayed at the bottom left corner)
        screen_title = Label(0.13, "screentitle", 0, 0.87,
                             self.tv_series.title)
        self.add(screen_title)

        self.scroll_area = None
        self.title = None
        self.thumb = None
        self.menu = self._create_episode_menu()
        self.add(self.menu)
        self._create_episode_info_box()

        #List indicator
        self.li = ListIndicator(0.8, 0.9, 0.2, 0.045, ListIndicator.VERTICAL)
        self.li.set_maximum(len(self.episodes))
        self.add(self.li)

        self.menu.connect("moved", self._update_episode_info)
        self.menu.connect("selected", self._handle_select)
        self.menu.connect("activated", self._on_menu_activated)

    def _create_episode_menu(self):
        """Create a list of available seasons."""
        menu = TextMenu(0.4978, 0.1563, 0.4393, 0.0781)

        episodes_list = [[_("%(num)d. %(title)s") % \
            {'num': episode.number, 'title': episode.title},
            None, episode] for episode in self.episodes]
        menu.async_add(episodes_list)

        menu.active = True

        return menu

    def _create_thumbnail_texture(self):
        """Create a thumbnail texture. This is called as menu is scrolled."""
        if self.thumb:
            self.thumb.hide()

        # Thumbnail. Use cover art if thumbnail doesn't exist
        thumbnail = self.menu.selected_userdata.thumbnail_url
        if (thumbnail is not None):
            pixbuf = gtk.gdk.pixbuf_new_from_file(thumbnail)
            thumb_width = 0.2928
            thumb_height = 0.2799
            thumb_x = 0.05
            thumb_y = 0.2
        else:
            thumb_width = 0.1098
            thumb_height = 0.2799
            thumb_x = 0.20
            thumb_y = 0.15
            if (self.tv_series.has_cover_art()):
                pixbuf = gtk.gdk.pixbuf_new_from_file(
                    self.tv_series.cover_art_url)
            else:
                pixbuf = gtk.gdk.pixbuf_new_from_file(
                    self.theme.getImage("default_movie_art"))

        self.thumb = EyeCandyTexture(thumb_x, thumb_y, thumb_width,
                                     thumb_height, pixbuf)
        self.add(self.thumb)

    def _create_episode_info_box(self):
        """
        Create a texture that is displayed next to track list. This texture
        displays album cover art.
        """
        self._create_thumbnail_texture()

        # Title
        self.title = Label(0.04,
                           "title",
                           0.05,
                           0.55,
                           self.menu.selected_userdata.title,
                           font_weight="bold")
        self.title.set_ellipsize(pango.ELLIPSIZE_END)
        self.title.set_line_wrap(False)
        self.title.width = 0.4
        self.add(self.title)

        # Plot
        plot = Label(0.029, "subtitle", 0, 0, self.menu.selected_userdata.plot)
        plot.width = 0.4

        self.scroll_area = ScrollArea(0.05, 0.63, 0.4, 0.15, plot)
        self.scroll_area.connect("activated", self._on_scroll_area_activated)
        self.add(self.scroll_area)

    def _update_episode_info(self, event=None):
        '''Update information from this episode.'''
        self.li.set_current(self.menu.selected_index + 1)

        self._create_thumbnail_texture()
        self.title.set_text(self.menu.selected_userdata.title)
        self.title.width = 0.4

        plot = Label(0.029, "subtitle", 0, 0, self.menu.selected_userdata.plot)
        plot.width = 0.4
        self.scroll_area.set_content(plot)

    def _handle_up(self):
        '''Handle UserEvent.NAVIGATE_UP.'''
        if self.menu.active:
            self.menu.up()
        else:
            self.scroll_area.scroll_up()

    def _handle_down(self):
        '''Handle UserEvent.NAVIGATE_DOWN.'''
        if self.menu.active:
            self.menu.down()
        else:
            self.scroll_area.scroll_down()

    def _handle_left(self):
        '''Handle UserEvent.NAVIGATE_LEFT.'''
        self.menu.active = False
        self.scroll_area.active = True

    def _handle_right(self):
        '''Handle UserEvent.NAVIGATE_RIGHT.'''
        self.menu.active = True
        self.scroll_area.active = False

    def _handle_select(self, event=None):
        '''Handle UserEvent.NAVIGATE_SELECT.'''
        episode = self.menu.selected_userdata
        self.media_player.set_media(episode)
        self.media_player.play()
        self.callback("video_osd")

    def _on_menu_activated(self, event=None):
        '''Handle menu activation.'''
        self.scroll_area.active = False

    def _on_scroll_area_activated(self, event=None):
        '''Handle scroll_area activation.'''
        self.menu.active = False
示例#17
0
class VideoClipsTab(Tab):
    """
    Tab can be used as part of the TabGroup

    Tab is a very simple container that contains all the widgets and logic
    of the tab page.
    """
    def __init__(self,
                 media_player,
                 video_library,
                 move_to_new_screen_callback,
                 name="clips",
                 tab_title=_("Video clips")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)
        self.media_player = media_player
        self.video_library = video_library
        self.theme = self.config.theme
        self.list_indicator = None
        self.clip_info = None
        self.menu = None
        self.clip_title = None

        if self.video_library.get_number_of_video_clips() == 0:
            self._create_empty_library_notice()
        else:
            # Start the loading animation while the menu is loading
            self.throbber = LoadingAnimation(0.7, 0.1)
            self.throbber.show()
            self.add(self.throbber)

            self.menu = self._create_menu()
            self.add(self.menu)
            self.menu.connect("moved", self._update_clip_info)
            self.menu.connect("selected", self._handle_select)
            self.menu.connect("activated", self._on_activated)
            self.menu.connect("filled", self._on_menu_filled)

            self.connect('activated', self._on_activated)
            self.connect('deactivated', self._on_deactivated)

    def can_activate(self):
        """
        Allow if we have some movies indexed.
        """
        if self.video_library.get_number_of_video_clips() == 0:
            return False
        else:
            return True

    def _create_empty_library_notice(self):
        """
        Create an information box that is displayed if there are no indexed
        movies.
        """
        message = _(
            "There are no indexed Video Clips in the Entertainer media "
            "library. Please add some folders containing video clips "
            "to the Library using the configuration tool.")
        Tab.show_empty_tab_notice(self, _("No video clips available!"),
                                  message)

    def _create_menu(self):
        """
        Create a view that is displayed when there are indexed clips in
        the video library.
        """
        menu = ImageMenu(0.04, 0.16, 0.23, self.y_for_x(0.23) * 0.7)
        menu.items_per_col = 2
        menu.visible_rows = 2
        menu.visible_cols = 4

        clips = self.video_library.get_video_clips()
        clips_list = [[clip.thumbnail_url, clip] for clip in clips]
        menu.async_add_clips(clips_list)

        # Create list indicator
        self.list_indicator = ListIndicator(0.7, 0.8, 0.2, 0.045,
                                            ListIndicator.HORIZONTAL)
        self.list_indicator.set_maximum(len(clips))
        self.list_indicator.show()
        self.add(self.list_indicator)

        # Create information labels
        self.clip_title = Label(0.042,
                                "title",
                                0.15,
                                0.77,
                                "",
                                font_weight="bold")
        self.clip_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.clip_title.set_line_wrap(False)
        self.clip_title.width = 0.5
        self.add(self.clip_title)

        self.clip_info = Label(0.034, "subtitle", 0.15, 0.85, "")
        self.clip_info.set_ellipsize(pango.ELLIPSIZE_END)
        self.clip_info.set_line_wrap(False)
        self.clip_info.width = 0.5
        self.add(self.clip_info)

        return menu

    def _update_clip_info(self, event=None):
        '''Update the VideoClip information labels.'''
        if self.active:
            clip = self.menu.selected_userdata
            (folder, filename) = os.path.split(clip.filename)
            self.clip_title.set_text(filename)
            self.clip_info.set_text(folder)
            self.list_indicator.show()
            self.list_indicator.set_current(self.menu.selected_index + 1)
        else:
            self.clip_title.set_text("")
            self.clip_info.set_text("")
            self.list_indicator.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True  # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        clip = self.menu.selected_userdata
        self.media_player.set_media(clip)
        self.media_player.play()
        self.callback("video_osd")
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_clip_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_clip_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#18
0
class ArtistsTab(Tab):
    '''Tab for the music screen to show artist listings'''

    def __init__(self, music_library, artists, move_to_new_screen_callback,
        name="artists", tab_title=_("Artists")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)
        self.library = music_library

        # Start the loading animation while the menu is loading
        self.throbber = LoadingAnimation(0.1, 0.1)
        self.throbber.show()
        self.add(self.throbber)

        self.menu = TextMenu(0.057, 0.208, 0.293, 0.078)
        self.menu.items_per_row = 3
        self.menu.visible_rows = 7
        self.menu.visible_cols = 3
        self.menu.active = False
        self.menu.cursor = None
        self.add(self.menu)

        artists_list = [[artist, None, artist] for artist in artists]
        self.menu.async_add_artists(artists_list)

        # Create artist label
        self.artist_title = Label(0.0416, "title", 0.22, 0.794, "")
        self.artist_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.artist_title.set_line_wrap(False)
        self.artist_title.width = 0.366
        self.add(self.artist_title)

        self.artist_albums = Label(0.0365, "subtitle", 0.22, 0.86, "")
        self.add(self.artist_albums)

        self.artist_tracks = Label(0.0365, "subtitle", 0.22, 0.911, "")
        self.add(self.artist_tracks)

        # Create artist menu list indicator
        self.li = ListIndicator(0.77, 0.8, 0.18, 0.045,
            ListIndicator.VERTICAL)
        self.li.set_maximum(len(artists))
        self.add(self.li)

        self.connect('activated', self._on_activated)
        self.connect('deactivated', self._on_deactivated)
        self.menu.connect("moved", self._update_artist_info)
        self.menu.connect("selected", self._handle_select)
        self.menu.connect("activated", self._on_activated)
        self.menu.connect("filled", self._on_menu_filled)

    def can_activate(self):
        '''Albums tab will always be created from an existing artist with at
        least one album.'''
        return True

    def _update_artist_info(self, event=None):
        '''Update the artist information labels'''
        if self.active:
            artist = self.menu.selected_userdata
            self.artist_title.set_text(artist)
            self.artist_albums.set_text(_("%(albums)d albums") %
                {'albums': self.library.number_of_albums_by_artist(artist)})
            self.artist_tracks.set_text(_("%(tracks)d tracks") %
                {'tracks': self.library.number_of_tracks_by_artist(artist)})
            self.li.show()
            self.li.set_current(self.menu.selected_index + 1)
        else:
            self.artist_title.set_text("")
            self.artist_albums.set_text("")
            self.artist_tracks.set_text("")
            self.li.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        artist = self.menu.selected_userdata
        kwargs = { 'artist' : artist }
        self.callback("artist", kwargs)
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_artist_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_artist_info()

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#19
0
class ProgressBar(Base, clutter.Group):
    '''
    Progress bar widget.

    This widget implements simple progress bar.
    '''
    # Cursor's radius in % of the widget's height
    CURSOR_RADIUS = 0.3
    BAR_LENGTH = 0.5
    INFO_LENGTH = (1 - BAR_LENGTH) / 2.0

    def __init__(self, x, y, width, height, color="title"):
        Base.__init__(self)
        clutter.Group.__init__(self)

        self.width = self.get_abs_x(width)
        self.height = self.get_abs_y(height)
        self.bar_width = int(self.width * self.BAR_LENGTH)
        self.bar_x = int(self.width * self.INFO_LENGTH)
        self.media_length_x = (1 - self.INFO_LENGTH + 0.05) * width

        self.set_position(self.get_abs_x(x), self.get_abs_y(y))

        self._color = self._color_to_cairo_color(
            self.config.theme.get_color(color))

        self._background = clutter.CairoTexture(self.bar_width, self.height)
        self._draw_background()
        self._background.set_position(self.bar_x, 0)
        self.add(self._background)

        self._foreground = clutter.CairoTexture(self.height, self.height)
        self._foreground.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
        self._draw_foreground()
        self._foreground.set_position(self.bar_x, 0)
        self.add(self._foreground)

        self.media_position = Label(0.037, "title", 0, 0, "")
        self.add(self.media_position)

        self.media_length = Label(0.037, "title", self.media_length_x, 0, "")
        self.add(self.media_length)

        self._media_player = None
        self._progress_bar_moving = False

        self._hide_timeout_key = None
        self.auto_display = False
        self._visible = None
        self._timeline = clutter.Timeline(500)
        self._alpha = clutter.Alpha(self._timeline, clutter.EASE_IN_OUT_SINE)
        self._behaviour = clutter.BehaviourOpacity(0, 255, self._alpha)
        self._behaviour.apply(self)

        self._progress = None
        # Call the property setter to initialize the displayed position.
        self.progress = 0

        # Preparation to pointer events handling.
        self._motion_handler = 0
        self.set_reactive(True)
        self.connect('scroll-event', self._on_scroll_event)
        self.connect('button-press-event', self._on_button_press_event)
        self.connect('button-release-event', self._on_button_release_event)
        self.connect('enter-event', self._on_enter_event)
        self.connect('leave-event', self._on_leave_event)

    def _get_media_player(self):
        '''media_player property getter.'''
        return self._media_player

    def _set_media_player(self, media_player):
        '''media_player property setter.'''
        self._media_player = media_player
        self._media_player.connect('refresh', self._update_media_position)
        self._media_player.connect('stop', self._update_media_position)
        self._media_player.connect('position-changed',
            self._on_player_position_changed)

    media_player = property(_get_media_player, _set_media_player)

    def _get_progress(self):
        '''progress property getter.'''
        return self._progress

    def _set_progress(self, progress):
        '''progress property setter.'''
        if progress > 1:
            progress = 1
        if progress < 0:
            progress = 0
        self._progress = progress
        self._foreground.set_position(int(self.bar_x + (self.height / 2) +
            int(self.bar_width - self.height) * progress), int(self.height / 2))

    progress = property(_get_progress, _set_progress)

    def _get_visible(self):
        '''visible property getter.'''
        if self._visible == None:
            self._visible = True
        return self._visible

    def _set_visible(self, boolean):
        '''visible property setter.'''
        if self._visible == boolean:
            return

        self._visible = boolean

        if boolean:
            self._timeline.set_direction(clutter.TIMELINE_FORWARD)
            self._timeline.rewind()
            self._timeline.start()
            if self.auto_display:
                if self._hide_timeout_key is not None:
                    gobject.source_remove(self._hide_timeout_key)
                self._hide_timeout_key = gobject.timeout_add(3000,
                    self._hide_progress_bar)

        else:
            self._timeline.set_direction(clutter.TIMELINE_BACKWARD)
            self._timeline.start()

    visible = property(_get_visible, _set_visible)

    def _hide_progress_bar(self):
        '''Update the progress bar.'''
        self.visible = False
        return False

    def _reset_auto_display_timeout(self):
        '''Reset the timeout if auto_display = True.'''
        if self._hide_timeout_key is not None:
            gobject.source_remove(self._hide_timeout_key)
        self._hide_timeout_key = gobject.timeout_add(3000,
            self._hide_progress_bar)

    def _update_media_position(self, event=None):
        '''Update the media's position.'''
        if not self._progress_bar_moving:
            self.progress = self.media_player.get_media_position()
        self.media_position.set_text(
            self.media_player.get_media_position_string())
        self.media_length.set_text(
            self.media_player.get_media_duration_string())

    def _draw_background(self):
        '''Draw background graphics.'''
        context = self._background.cairo_create()
        context.set_line_width(self.height * 0.09)
        context.set_source_rgba(
            self._color[0], self._color[1], self._color[2], 0.7)

        context.arc(self.height / 2,
                    self.height / 2,
                    self.height / 2 -2,
                    math.pi / 2,
                    math.pi * 1.5)
        context.arc(self.bar_width - self.height / 2,
                    self.height / 2,
                    self.height / 2 -2,
                    math.pi * 1.5,
                    math.pi / 2)
        context.close_path()

        context.stroke()
        del context

    def _draw_foreground(self):
        '''Draw foreground graphics.'''
        context = self._foreground.cairo_create()
        context.scale(self.height, self.height)
        context.set_source_rgba(
            self._color[0], self._color[1], self._color[2], 1.0)
        context.arc(0.5, 0.5, self.CURSOR_RADIUS, 0, 2 * math.pi)
        context.fill()
        del context

    def _color_to_cairo_color(self, color):
        '''Transform color to cairo format (0-255 to 0-1).'''
        (int_r, int_g, int_b, int_a) = color
        r = float(int_r) / 255.0
        g = float(int_g) / 255.0
        b = float(int_b) / 255.0
        a = float(int_a) / 255.0
        return r, g, b, a

    def _on_button_press_event(self, actor, event):
        '''button-press-event handler.'''
        if not self.visible:
            self.visible = True
            return

        clutter.grab_pointer(self)

        x = event.x - self.get_x()
        y = event.y - self.get_y()

        dx = x - int(self.bar_x + (self.height / 2) + \
            (self.bar_width - self.height) * self._progress)
        dy = y - int(self.height / 2)

        # Calculation of the distance between our click and the middle of
        # the progress_bar cursor position.
        distance = math.sqrt(dx * dx + dy * dy)

        if distance <= (self.CURSOR_RADIUS * self.height):
            # Clicked around the cursor.
            if not self.handler_is_connected(self._motion_handler):
                self._motion_handler = self.connect('motion-event',
                    self._on_motion_event)
                self._progress_bar_moving = True
        else:
            # Clicked far from the cursor. Change to the pointed position.
            progress = (x - self.bar_x - (self.height / 2.0)) / \
                (self.bar_width - self.height)
            self.progress = progress
            self._progress_bar_moving = False
            self.media_player.set_media_position(self.progress)

        if self._hide_timeout_key is not None:
            gobject.source_remove(self._hide_timeout_key)

        return False

    def _on_button_release_event(self, actor, event):
        '''button-release-event handler.'''
        clutter.ungrab_pointer()

        if self.handler_is_connected(self._motion_handler):
            self.disconnect_by_func(self._on_motion_event)

        self._progress_bar_moving = False
        self.media_player.set_media_position(self.progress)

        if self.auto_display and self.visible:
            self._hide_timeout_key = gobject.timeout_add(3000,
                self._hide_progress_bar)

        return False

    def _on_motion_event(self, actor, event):
        '''motion-event handler.'''
        x_cursor = event.x - self.get_x()
        progress = (x_cursor - self.bar_x - (self.height / 2.0)) / \
            (self.bar_width - self.height)
        self.progress = progress
        self.media_player.set_media_position(self.progress)

        return False

    def _on_scroll_event(self, actor, event):
        '''scroll-event handler (mouse's wheel).'''
        # +/- 2% per scroll event on the position of the media stream.
        self.visible = True
        scroll_progress_ratio = 0.02

        if event.direction == clutter.SCROLL_DOWN:
            self.progress -= scroll_progress_ratio
        else:
            self.progress += scroll_progress_ratio

        self._progress_bar_moving = False
        self.media_player.set_media_position(self.progress)

        return False

    def _on_enter_event(self, stage, clutter_event):
        '''Shows the progress bar.'''
        if self.auto_display and not self._progress_bar_moving:
            self.visible = True

    def _on_leave_event(self, stage, clutter_event):
        '''Hides the progress bar.'''
        if self.auto_display and not self._progress_bar_moving:
            self.visible = False

    def _on_player_position_changed(self, event=None):
        '''Shows the progress bar.'''
        if self.auto_display and not self._progress_bar_moving:
            self.visible = True
            self._reset_auto_display_timeout()
示例#20
0
class Photographs(Screen):
    '''Screen displays a grid of selectable photograph thumbnails.'''
    def __init__(self, move_to_new_screen_callback, title, images):
        Screen.__init__(self, 'Photographs', move_to_new_screen_callback)

        self.images = images

        # Screen Title (Displayed at the bottom left corner)
        screen_title = Label(0.13, "screentitle", 0, 0.87, title)
        self.add(screen_title)

        # Image Title (over album list)
        self.image_title = Label(0.04167, "title", 0.0586, 0.7943, " ")
        self.image_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.add(self.image_title)

        self.image_desc = Label(0.04167, "subtitle", 0.0586, 0.9115, " ")
        self.image_desc.set_line_wrap(True)
        self.image_desc.set_ellipsize(pango.ELLIPSIZE_END)
        self.add(self.image_desc)

        # Display throbber animation while loading photographs
        self.throbber = LoadingAnimation(0.9, 0.9)
        self.throbber.show()
        self.add(self.throbber)

        # List indicator
        self.li = None
        self._create_list_indicator()

        # Create photomenu
        self.menu = ImageMenu(0.03, 0.08, 0.12, self.y_for_x(0.12))
        self.menu.items_per_col = 3
        self.menu.visible_rows = 3
        self.menu.visible_cols = 8
        self.menu.active = True
        self.add(self.menu)

        photos = self.images
        photos_list = [[Texture(photo.get_thumbnail_url()), photo] \
            for photo in photos]
        self.menu.async_add(photos_list)

        self.menu.connect("selected", self._handle_select)
        self.menu.connect('moved', self._update_image_info)
        self.menu.connect("filled", self._on_menu_filled)

    def _update_image_info(self, event=None):
        """Update image information box."""
        image = self.images[self.menu.selected_index]
        name = image.get_title()
        desc = image.get_description()
        self.image_title.set_text(name)
        self.image_title.set_size(0.366, 0.04167)
        self.image_desc.set_text(desc)
        self.image_desc.set_size(0.366, 0.0911)
        self.li.set_current(self.menu.selected_index + 1)

    def _create_list_indicator(self):
        '''Create list indicator for albums list.'''
        self.li = ListIndicator(0.77, 0.8, 0.18, 0.045,
                                ListIndicator.HORIZONTAL)
        self.li.set_maximum(len(self.images))
        self.add(self.li)

    def _handle_up(self):
        '''Handle UserEvent.NAVIGATE_UP.'''
        self.menu.up()

    def _handle_down(self):
        '''Handle UserEvent.NAVIGATE_DOWN.'''
        self.menu.down()

    def _handle_left(self):
        '''Handle UserEvent.NAVIGATE_LEFT.'''
        self.menu.left()

    def _handle_right(self):
        '''Handle UserEvent.NAVIGATE_RIGHT.'''
        self.menu.right()

    def _handle_select(self, event=None):
        '''Handle UserEvent.NAVIGATE_SELECT.'''
        index = self.menu.selected_index
        kwargs = {'current_photo_index': index, 'images': self.images}
        self.callback("photo", kwargs)

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#21
0
class PlayingTab(Tab):
    '''Tab for the audio play screen to show currently playing audio.'''
    def __init__(self,
                 media_player,
                 track,
                 name="playing",
                 tab_title=_("Currently playing")):
        Tab.__init__(self, name, tab_title)

        album = track.album

        # Track name
        if track.number == 0:
            track_label_text = track.title
        else:
            track_label_text =  _("From %(number)d. %(title)s") % \
                {'number': track.number, 'title': track.title}

        self.track_label = Label(0.05, "text", 0.5, 0.33, track_label_text)
        self.track_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.track_label.width = 0.4
        self.add(self.track_label)

        # Album name
        if album.year == 0:
            album_label_text = _("From %(title)s") % {'title': album.title}
        else:
            album_label_text = _("From %(title)s, %(year)s") % \
                {'title': album.title, 'year': album.year}

        self.album_label = Label(0.042, "subtitle", 0.5, 0.43,
                                 album_label_text)
        self.album_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.album_label.width = 0.4
        self.add(self.album_label)

        # Artist name
        artist_text = _("By %(artist)s") % {'artist': track.artist}
        self.artist_label = Label(0.042, "subtitle", 0.5, 0.53, artist_text)
        self.artist_label.set_ellipsize(pango.ELLIPSIZE_END)
        self.artist_label.width = 0.4
        self.add(self.artist_label)

        self.progress_bar = ProgressBar(0.5, 0.667, 0.4, 0.04)
        self.progress_bar.media_player = media_player
        self.add(self.progress_bar)

    def update(self, track):
        '''
        Called when currently playing changes tracks. The provided track
        is used to update all the necessary labels.
        '''
        album = track.album

        if track.number == 0:
            self.track_label.set_text(track.title)
        else:
            self.track_label.set_text(str(track.number) + ". " + track.title)

        if album.year != 0:
            self.album_label.set_text(_("From %(title)s, %(year)s") % \
            {'title': album.title, 'year': album.year})
        else:
            self.album_label.set_text(_("From %(album)s") % \
                {'album': album.title})
            self.artist_label.set_text(_("By %(artist)s") % \
                {'artist': track.artist})

    def can_activate(self):
        '''No interaction is available on the PlayingTab.'''
        return False
示例#22
0
class AlbumsTab(Tab):
    '''Tab to show album listings'''
    def __init__(self,
                 albums,
                 move_to_new_screen_callback,
                 name="albums",
                 tab_title=_("Albums")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)

        # Start the loading animation while the menu is loading
        self.throbber = LoadingAnimation(0.6, 0.1)
        self.throbber.show()
        self.add(self.throbber)

        if len(albums) < 4:
            x_percent = 0.2928
            visible_rows = 1
            visible_cols = 3
        elif len(albums) < 13:
            x_percent = 0.1464
            visible_rows = 2
            visible_cols = 6
        else:
            x_percent = 0.1098
            visible_rows = 3
            visible_cols = 8

        # Create albums menu
        self.menu = ImageMenu(0.07, 0.16, x_percent, self.y_for_x(x_percent))
        self.menu.visible_rows = visible_rows
        self.menu.visible_cols = visible_cols
        self.menu.items_per_col = self.menu.visible_rows
        self.add(self.menu)

        albums_list = [[album.album_art_url, album] for album in albums]
        self.menu.async_add_albums(albums_list)

        self.li = ListIndicator(0.77, 0.8, 0.18, 0.045,
                                ListIndicator.HORIZONTAL)
        self.li.set_maximum(len(albums))
        self.li.show()
        self.add(self.li)

        # Create album information (displays current menuitem information)
        self.album_title = Label(0.045, "title", 0.22, 0.79, "")
        self.album_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.album_title.set_line_wrap(False)
        self.album_title.width = 0.366
        self.add(self.album_title)

        self.album_artist = Label(0.037, "subtitle", 0.22, 0.86, "")
        self.album_artist.set_ellipsize(pango.ELLIPSIZE_END)
        self.album_artist.set_line_wrap(False)
        self.album_artist.width = 0.366
        self.add(self.album_artist)

        self.album_tracks = Label(0.037, "subtitle", 0.22, 0.91, "")
        self.add(self.album_tracks)

        self.connect('activated', self._on_activated)
        self.connect('deactivated', self._on_deactivated)
        self.menu.connect("moved", self._update_album_info)
        self.menu.connect("selected", self._handle_select)
        self.menu.connect("activated", self._on_activated)
        self.menu.connect("filled", self._on_menu_filled)

    def can_activate(self):
        '''Albums tab will always be created from an existing artist with at
        least one album.'''
        return True

    def _update_album_info(self, event=None):
        '''Update the album information labels.'''
        if self.active:
            album = self.menu.selected_userdata
            self.album_title.set_text(album.title)
            self.album_artist.set_text(album.artist)
            self.album_tracks.set_text(_("%(total)s tracks") % \
                {'total': len(album.tracks)})
            self.li.show()
            self.li.set_current(self.menu.selected_index + 1)
        else:
            self.album_title.set_text("")
            self.album_artist.set_text("")
            self.album_tracks.set_text("")
            self.li.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True  # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        album = self.menu.selected_userdata
        kwargs = {'album': album}
        self.callback("album", kwargs)
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_album_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_album_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()
示例#23
0
class ProgressBar(Base, clutter.Group):
    '''
    Progress bar widget.

    This widget implements simple progress bar.
    '''
    # Cursor's radius in % of the widget's height
    CURSOR_RADIUS = 0.3
    BAR_LENGTH = 0.5
    INFO_LENGTH = (1 - BAR_LENGTH) / 2.0

    def __init__(self, x, y, width, height, color="title"):
        Base.__init__(self)
        clutter.Group.__init__(self)

        self.width = self.get_abs_x(width)
        self.height = self.get_abs_y(height)
        self.bar_width = int(self.width * self.BAR_LENGTH)
        self.bar_x = int(self.width * self.INFO_LENGTH)
        self.media_length_x = (1 - self.INFO_LENGTH + 0.05) * width

        self.set_position(self.get_abs_x(x), self.get_abs_y(y))

        self._color = self._color_to_cairo_color(
            self.config.theme.get_color(color))

        self._background = clutter.CairoTexture(self.bar_width, self.height)
        self._draw_background()
        self._background.set_position(self.bar_x, 0)
        self.add(self._background)

        self._foreground = clutter.CairoTexture(self.height, self.height)
        self._foreground.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
        self._draw_foreground()
        self._foreground.set_position(self.bar_x, 0)
        self.add(self._foreground)

        self.media_position = Label(0.037, "title", 0, 0, "")
        self.add(self.media_position)

        self.media_length = Label(0.037, "title", self.media_length_x, 0, "")
        self.add(self.media_length)

        self._media_player = None
        self._progress_bar_moving = False

        self._hide_timeout_key = None
        self.auto_display = False
        self._visible = None
        self._timeline = clutter.Timeline(500)
        self._alpha = clutter.Alpha(self._timeline, clutter.EASE_IN_OUT_SINE)
        self._behaviour = clutter.BehaviourOpacity(0, 255, self._alpha)
        self._behaviour.apply(self)

        self._progress = None
        # Call the property setter to initialize the displayed position.
        self.progress = 0

        # Preparation to pointer events handling.
        self._motion_handler = 0
        self.set_reactive(True)
        self.connect('scroll-event', self._on_scroll_event)
        self.connect('button-press-event', self._on_button_press_event)
        self.connect('button-release-event', self._on_button_release_event)
        self.connect('enter-event', self._on_enter_event)
        self.connect('leave-event', self._on_leave_event)

    def _get_media_player(self):
        '''media_player property getter.'''
        return self._media_player

    def _set_media_player(self, media_player):
        '''media_player property setter.'''
        self._media_player = media_player
        self._media_player.connect('refresh', self._update_media_position)
        self._media_player.connect('stop', self._update_media_position)
        self._media_player.connect('position-changed',
                                   self._on_player_position_changed)

    media_player = property(_get_media_player, _set_media_player)

    def _get_progress(self):
        '''progress property getter.'''
        return self._progress

    def _set_progress(self, progress):
        '''progress property setter.'''
        if progress > 1:
            progress = 1
        if progress < 0:
            progress = 0
        self._progress = progress
        self._foreground.set_position(
            int(self.bar_x + (self.height / 2) +
                int(self.bar_width - self.height) * progress),
            int(self.height / 2))

    progress = property(_get_progress, _set_progress)

    def _get_visible(self):
        '''visible property getter.'''
        if self._visible == None:
            self._visible = True
        return self._visible

    def _set_visible(self, boolean):
        '''visible property setter.'''
        if self._visible == boolean:
            return

        self._visible = boolean

        if boolean:
            self._timeline.set_direction(clutter.TIMELINE_FORWARD)
            self._timeline.rewind()
            self._timeline.start()
            if self.auto_display:
                if self._hide_timeout_key is not None:
                    gobject.source_remove(self._hide_timeout_key)
                self._hide_timeout_key = gobject.timeout_add(
                    3000, self._hide_progress_bar)

        else:
            self._timeline.set_direction(clutter.TIMELINE_BACKWARD)
            self._timeline.start()

    visible = property(_get_visible, _set_visible)

    def _hide_progress_bar(self):
        '''Update the progress bar.'''
        self.visible = False
        return False

    def _reset_auto_display_timeout(self):
        '''Reset the timeout if auto_display = True.'''
        if self._hide_timeout_key is not None:
            gobject.source_remove(self._hide_timeout_key)
        self._hide_timeout_key = gobject.timeout_add(3000,
                                                     self._hide_progress_bar)

    def _update_media_position(self, event=None):
        '''Update the media's position.'''
        if not self._progress_bar_moving:
            self.progress = self.media_player.get_media_position()
        self.media_position.set_text(
            self.media_player.get_media_position_string())
        self.media_length.set_text(
            self.media_player.get_media_duration_string())

    def _draw_background(self):
        '''Draw background graphics.'''
        context = self._background.cairo_create()
        context.set_line_width(self.height * 0.09)
        context.set_source_rgba(self._color[0], self._color[1], self._color[2],
                                0.7)

        context.arc(self.height / 2, self.height / 2, self.height / 2 - 2,
                    math.pi / 2, math.pi * 1.5)
        context.arc(self.bar_width - self.height / 2, self.height / 2,
                    self.height / 2 - 2, math.pi * 1.5, math.pi / 2)
        context.close_path()

        context.stroke()
        del context

    def _draw_foreground(self):
        '''Draw foreground graphics.'''
        context = self._foreground.cairo_create()
        context.scale(self.height, self.height)
        context.set_source_rgba(self._color[0], self._color[1], self._color[2],
                                1.0)
        context.arc(0.5, 0.5, self.CURSOR_RADIUS, 0, 2 * math.pi)
        context.fill()
        del context

    def _color_to_cairo_color(self, color):
        '''Transform color to cairo format (0-255 to 0-1).'''
        (int_r, int_g, int_b, int_a) = color
        r = float(int_r) / 255.0
        g = float(int_g) / 255.0
        b = float(int_b) / 255.0
        a = float(int_a) / 255.0
        return r, g, b, a

    def _on_button_press_event(self, actor, event):
        '''button-press-event handler.'''
        if not self.visible:
            self.visible = True
            return

        clutter.grab_pointer(self)

        x = event.x - self.get_x()
        y = event.y - self.get_y()

        dx = x - int(self.bar_x + (self.height / 2) + \
            (self.bar_width - self.height) * self._progress)
        dy = y - int(self.height / 2)

        # Calculation of the distance between our click and the middle of
        # the progress_bar cursor position.
        distance = math.sqrt(dx * dx + dy * dy)

        if distance <= (self.CURSOR_RADIUS * self.height):
            # Clicked around the cursor.
            if not self.handler_is_connected(self._motion_handler):
                self._motion_handler = self.connect('motion-event',
                                                    self._on_motion_event)
                self._progress_bar_moving = True
        else:
            # Clicked far from the cursor. Change to the pointed position.
            progress = (x - self.bar_x - (self.height / 2.0)) / \
                (self.bar_width - self.height)
            self.progress = progress
            self._progress_bar_moving = False
            self.media_player.set_media_position(self.progress)

        if self._hide_timeout_key is not None:
            gobject.source_remove(self._hide_timeout_key)

        return False

    def _on_button_release_event(self, actor, event):
        '''button-release-event handler.'''
        clutter.ungrab_pointer()

        if self.handler_is_connected(self._motion_handler):
            self.disconnect_by_func(self._on_motion_event)

        self._progress_bar_moving = False
        self.media_player.set_media_position(self.progress)

        if self.auto_display and self.visible:
            self._hide_timeout_key = gobject.timeout_add(
                3000, self._hide_progress_bar)

        return False

    def _on_motion_event(self, actor, event):
        '''motion-event handler.'''
        x_cursor = event.x - self.get_x()
        progress = (x_cursor - self.bar_x - (self.height / 2.0)) / \
            (self.bar_width - self.height)
        self.progress = progress
        self.media_player.set_media_position(self.progress)

        return False

    def _on_scroll_event(self, actor, event):
        '''scroll-event handler (mouse's wheel).'''
        # +/- 2% per scroll event on the position of the media stream.
        self.visible = True
        scroll_progress_ratio = 0.02

        if event.direction == clutter.SCROLL_DOWN:
            self.progress -= scroll_progress_ratio
        else:
            self.progress += scroll_progress_ratio

        self._progress_bar_moving = False
        self.media_player.set_media_position(self.progress)

        return False

    def _on_enter_event(self, stage, clutter_event):
        '''Shows the progress bar.'''
        if self.auto_display and not self._progress_bar_moving:
            self.visible = True

    def _on_leave_event(self, stage, clutter_event):
        '''Hides the progress bar.'''
        if self.auto_display and not self._progress_bar_moving:
            self.visible = False

    def _on_player_position_changed(self, event=None):
        '''Shows the progress bar.'''
        if self.auto_display and not self._progress_bar_moving:
            self.visible = True
            self._reset_auto_display_timeout()
示例#24
0
class MoviesTab(Tab):
    """
    Tab can be used as part of the TabGroup

    Tab is a very simple container that contains all the widgets and logic
    of the tab page.
    """
    def __init__(self,
                 video_library,
                 move_to_new_screen_callback,
                 name="movies",
                 tab_title=_("Movies")):
        Tab.__init__(self, name, tab_title, move_to_new_screen_callback)

        self.video_library = video_library
        self.theme = self.config.theme
        self.list_indicator = None
        self.movie_info = None
        self.menu = None
        self.movie_plot = None
        self.movie_title = None

        if self.video_library.get_number_of_movies() == 0:
            self._create_empty_library_notice()
        else:
            # Start the loading animation while the menu is loading
            self.throbber = LoadingAnimation(0.1, 0.1)
            self.throbber.show()
            self.add(self.throbber)

            self.menu = self._create_menu()
            self.add(self.menu)
            self.menu.connect("moved", self._update_movie_info)
            self.menu.connect("selected", self._handle_select)
            self.menu.connect("activated", self._on_activated)
            self.menu.connect("filled", self._on_menu_filled)

            self.connect('activated', self._on_activated)
            self.connect('deactivated', self._on_deactivated)

    def can_activate(self):
        """
        Allow if we have some movies indexed.
        """
        if self.video_library.get_number_of_movies() == 0:
            return False
        else:
            return True

    def _create_empty_library_notice(self):
        """
        Create an information box that is displayed if there are no indexed
        movies.
        """
        message = _(
            "There are no indexed movies in Entertainer media library.  To "
            "add movies, click on 'content' button on toolbar and open "
            "'videos' tab. Now click on 'add' button and select some folders "
            "which contains movie files.")
        Tab.show_empty_tab_notice(self, _("No movies available!"), message)

    def _create_menu(self):
        """
        Create a view that is displayed when there is indexed movies in
        the video library.
        """
        #Create movie menu
        menu = ImageMenu(0.06, 0.18, 0.12, 0.25)
        menu.items_per_col = 2
        menu.visible_rows = 2
        menu.visible_cols = 7

        movies = self.video_library.get_movies()
        movies_list = [[movie.cover_art_url, movie] for movie in movies]
        menu.async_add_videos(movies_list)

        # Create list indicator
        self.list_indicator = ListIndicator(0.75, 0.76, 0.2, 0.045,
                                            ListIndicator.HORIZONTAL)
        self.list_indicator.set_maximum(len(movies))
        self.show()
        self.add(self.list_indicator)

        # Create information labels
        self.movie_title = Label(0.042,
                                 "title",
                                 0.2,
                                 0.75,
                                 "",
                                 font_weight="bold")
        self.movie_title.set_ellipsize(pango.ELLIPSIZE_END)
        self.movie_title.set_line_wrap(False)
        self.movie_title.width = 0.5
        self.add(self.movie_title)

        self.movie_info = Label(0.034, "subtitle", 0.2, 0.8, "")
        self.movie_info.set_ellipsize(pango.ELLIPSIZE_END)
        self.movie_info.set_line_wrap(False)
        self.movie_info.width = 0.5
        self.add(self.movie_info)

        self.movie_plot = Label(0.025, "subtitle", 0.2, 0.85, "")
        self.movie_plot.width = 0.7
        self.add(self.movie_plot)

        return menu

    def _update_movie_info(self, event=None):
        '''Update the movie information labels.'''
        if self.active:
            movie = self.menu.selected_userdata
            genres = movie.genres
            if len(genres) > 1:
                genre = genres[0] + "/" + genres[1]
            else:
                genre = genres[0]

            self.movie_title.set_text(_("%(title)s (%(year)s)") % \
                {'title': movie.title, 'year': movie.year})
            self.movie_info.set_text(_("%(min)d min, (%(genre)s)") % \
                {'min': movie.runtime, 'genre': genre})
            self.movie_plot.set_text(movie.short_plot)
            self.list_indicator.show()
            self.list_indicator.set_current(self.menu.selected_index + 1)
        else:
            self.movie_title.set_text("")
            self.movie_info.set_text("")
            self.movie_plot.set_text("")
            self.list_indicator.hide()

    def _handle_up(self):
        '''Handle the up user event.'''
        if self.menu.on_top:
            return True  # Move control back to tab bar
        else:
            self.menu.up()
            return False

    def _handle_down(self):
        '''Handle the down user event.'''
        self.menu.down()
        return False

    def _handle_left(self):
        '''Handle the left user event.'''
        self.menu.left()
        return False

    def _handle_right(self):
        '''Handle the right user event.'''
        self.menu.right()
        return False

    def _handle_select(self, event=None):
        '''Handle the select user event.'''
        movie = self.menu.selected_userdata
        kwargs = {'movie': movie}
        self.callback("movie", kwargs)
        return False

    def _on_activated(self, event=None):
        '''Tab activated.'''
        if self.tab_group is not None:
            self.tab_group.active = False
        self.menu.active = True
        self.active = True
        self._update_movie_info()
        return False

    def _on_deactivated(self, event=None):
        '''Tab deactivated.'''
        self.active = False
        self.menu.active = False
        self._update_movie_info()
        return False

    def _on_menu_filled(self, event=None):
        '''Handles filled event.'''
        self.throbber.hide()