Пример #1
0
    def __init__(self):
        widgetset.SolidBackground.__init__(self, itemlistwidgets.StandardView.BACKGROUND_COLOR)
        bg = widgetutil.RoundedSolidBackground(widgetutil.WHITE)
        vbox = widgetset.VBox()
        title = widgetset.HBox()
        logo = imagepool.get_image_display(resources.path("images/icon-search_large.png"))
        title.pack_start(widgetutil.align_middle(logo))
        label = widgetset.Label(self.TITLE)
        label.set_bold(True)
        label.set_size(widgetutil.font_scale_from_osx_points(30))
        title.pack_start(widgetutil.align_middle(label, left_pad=5))
        vbox.pack_start(widgetutil.align_center(title, bottom_pad=20))
        desc = widgetset.Label(self.DESC)
        vbox.pack_start(widgetutil.align_center(desc, bottom_pad=40))

        engine_width = int((desc.get_width() - 30) / 2)

        engine_widgets = self.build_engine_widgets()
        for widgets in engine_widgets[:-1]:  # widgets with borders
            hbox = widgetset.HBox(spacing=30)
            for widget in widgets:
                widget.set_size_request(engine_width, 45)
                hbox.pack_start(widget, expand=True)
            vbox.pack_start(hbox)

        hbox = widgetset.HBox(spacing=30)
        for widget in engine_widgets[-1]:  # has no border
            widget.set_has_border(False)
            widget.set_size_request(engine_width, 45)
            hbox.pack_start(widget, expand=True)

        vbox.pack_start(hbox)

        bg.add(widgetutil.pad(vbox, 45, 45, 45, 45))
        self.add(widgetutil.align(bg, xalign=0.5, top_pad=50))
Пример #2
0
    def __init__(self):
        widgetset.VBox.__init__(self)

        if not app.sharing_manager.mdns_present:
            sharing_broken = SharingBroken()
            sharing_broken.connect('install-clicked',
                                   self.daap_install_clicked)
            self.pack_start(widgetutil.align_center(sharing_broken))

        title = widgetset.HBox()
        logo = widgetset.ImageDisplay(
            imagepool.get(resources.path('images/icon-connect_large.png')))
        title.pack_start(widgetutil.align_middle(logo))
        label = widgetset.Label(_("Connect"))
        label.set_size(widgetutil.font_scale_from_osx_points(30))
        label.set_bold(True)
        title.pack_start(widgetutil.align_middle(label, left_pad=5))
        self.pack_start(
            widgetutil.align_center(title, top_pad=30, bottom_pad=20))

        bottom = widgetset.VBox()

        self._build_daap_section(bottom)
        self._build_sync_section(bottom)
        self._build_app_store_section(bottom)
        self._build_android_section(bottom)

        self.pack_start(widgetutil.align_center(bottom))

        self.callback_handle = app.backend_config_watcher.connect_weak(
            'changed', self.on_config_changed)
Пример #3
0
    def __init__(self):
        widgetset.VBox.__init__(self)

        if not app.sharing_manager.mdns_present:
            sharing_broken = SharingBroken()
            sharing_broken.connect('install-clicked',
                                   self.daap_install_clicked)
            self.pack_start(widgetutil.align_center(sharing_broken))

        title = widgetset.HBox()
        logo = widgetset.ImageDisplay(imagepool.get(
            resources.path('images/icon-connect_large.png')))
        title.pack_start(widgetutil.align_middle(logo))
        label = widgetset.Label(_("Connect"))
        label.set_size(widgetutil.font_scale_from_osx_points(30))
        label.set_bold(True)
        title.pack_start(widgetutil.align_middle(label, left_pad=5))
        self.pack_start(widgetutil.align_center(title, top_pad=30,
                                                bottom_pad=20))

        bottom = widgetset.VBox()

        self._build_daap_section(bottom)
        self._build_sync_section(bottom)
        self._build_app_store_section(bottom)
        self._build_android_section(bottom)

        self.pack_start(widgetutil.align_center(bottom))
Пример #4
0
 def __init__(self, engine):
     widgetset.Background.__init__(self)
     hbox = widgetset.HBox(spacing=15)
     self.pack(hbox, imagepool.get_image_display(searchengines.icon_path_for_engine(engine)))
     label = widgetset.Label(engine.title)
     label.set_size(widgetutil.font_scale_from_osx_points(14))
     label.set_bold(True)
     self.pack(hbox, widgetutil.align_left(label), expand=True)
     self.add(hbox)
     self.has_border = True
Пример #5
0
 def __init__(self, engine):
     widgetset.Background.__init__(self)
     hbox = widgetset.HBox(spacing=15)
     self.pack(hbox, imagepool.get_image_display(
             searchengines.icon_path_for_engine(engine)))
     label = widgetset.Label(engine.title)
     label.set_size(widgetutil.font_scale_from_osx_points(14))
     label.set_bold(True)
     self.pack(hbox, widgetutil.align_left(label), expand=True)
     self.add(hbox)
     self.has_border = True
Пример #6
0
    def __init__(self):
        self.device = None
        widgetset.VBox.__init__(self)

        self.button_row = segmented.SegmentedButtonsRow()

        for key, name in (
            ('main', _('Main')),
            ('podcasts', _('Podcasts')),
            ('playlists', _('Playlists')),
            ('settings', _('Settings'))):
            button = DeviceTabButtonSegment(key, name,
                                            self._tab_clicked)
            self.button_row.add_button(name.lower(), button)

        self.button_row.set_active('main')
        self.pack_start(widgetutil.align_center(
                        self.button_row.make_widget(), top_pad=50))

        self.tabs = {}
        self.tab_container = widgetset.Background()
        self.pack_start(self.tab_container, expand=True)


        label_size = widgetutil.font_scale_from_osx_points(16)
        vbox = widgetset.VBox()
        label = widgetset.Label(_("Drag individual video and audio files "
                                  "onto the device in the sidebar to copy "
                                  "them."))
        label.set_size(label_size)
        vbox.pack_start(widgetutil.align_center(label, top_pad=50))
        label = widgetset.Label(_("Use these options and the tabs above for "
                                  "automatic syncing."))
        label.set_size(label_size)
        vbox.pack_start(widgetutil.align_center(label, top_pad=10))

        self.device_size = SizeWidget()
        self.device_size.sync_button.connect('clicked', self.sync_clicked)
        self.pack_end(self.device_size)

        self.sync_container = widgetset.Background()
        self.pack_end(widgetutil.align_center(self.sync_container))

        self.add_tab('main', vbox)
        self.add_tab('podcasts', widgetutil.align_center(PodcastSyncWidget()))
        self.add_tab('playlists',
                     widgetutil.align_center(PlaylistSyncWidget()))
        self.add_tab('settings',
                     widgetutil.align_center(DeviceSettingsWidget()))
Пример #7
0
    def __init__(self):
        self.device = None
        widgetset.VBox.__init__(self)

        self.button_row = segmented.SegmentedButtonsRow()

        for key, name in (('main', _('Main')), ('podcasts', _('Podcasts')),
                          ('playlists', _('Playlists')), ('settings',
                                                          _('Settings'))):
            button = DeviceTabButtonSegment(key, name, self._tab_clicked)
            self.button_row.add_button(name.lower(), button)

        self.button_row.set_active('main')
        self.pack_start(
            widgetutil.align_center(self.button_row.make_widget(), top_pad=50))

        self.tabs = {}
        self.tab_container = widgetset.Background()
        self.pack_start(self.tab_container, expand=True)

        label_size = widgetutil.font_scale_from_osx_points(16)
        vbox = widgetset.VBox()
        label = widgetset.Label(
            _("Drag individual video and audio files "
              "onto the device in the sidebar to copy "
              "them."))
        label.set_size(label_size)
        vbox.pack_start(widgetutil.align_center(label, top_pad=50))
        label = widgetset.Label(
            _("Use these options and the tabs above for "
              "automatic syncing."))
        label.set_size(label_size)
        vbox.pack_start(widgetutil.align_center(label, top_pad=10))

        self.device_size = SizeWidget()
        self.device_size.sync_button.connect('clicked', self.sync_clicked)
        self.pack_end(self.device_size)

        self.sync_container = widgetset.Background()
        self.pack_end(widgetutil.align_center(self.sync_container))

        self.add_tab('main', vbox)
        self.add_tab('podcasts', widgetutil.align_center(PodcastSyncWidget()))
        self.add_tab('playlists',
                     widgetutil.align_center(PlaylistSyncWidget()))
        self.add_tab('settings',
                     widgetutil.align_center(DeviceSettingsWidget()))
Пример #8
0
    def __init__(self):
        widgetset.VBox.__init__(self)

        title = widgetset.HBox()
        logo = widgetset.ImageDisplay(
            imagepool.get(resources.path('images/icon-playlist_large.png')))
        title.pack_start(widgetutil.align_middle(logo))
        label = widgetset.Label(_("Playlists"))
        label.set_size(widgetutil.font_scale_from_osx_points(30))
        label.set_bold(True)
        title.pack_start(widgetutil.align_middle(label, left_pad=5))
        self.pack_start(
            widgetutil.align_center(title, top_pad=30, bottom_pad=20))

        bottom = widgetset.VBox()

        self._build_add_playlist_section(bottom)

        self.pack_start(widgetutil.align_center(bottom))
Пример #9
0
class ListViewRendererText(widgetset.ItemListRendererText):
    """Renderer for list view columns that are just plain text"""

    bold = False
    color = widgetutil.BLACK
    font_size = widgetutil.font_scale_from_osx_points(11)
    min_width = 50
    right_aligned = False

    def __init__(self):
        widgetset.ItemListRendererText.__init__(self)
        self.set_bold(self.bold)
        self.set_color(self.color)
        self.set_font_scale(self.font_size)
        if self.right_aligned:
            self.set_align('right')

    def get_value(self, info):
        return getattr(info, self.attr_name)
Пример #10
0
    def __init__(self):
        widgetset.VBox.__init__(self)

        title = widgetset.HBox()
        logo = widgetset.ImageDisplay(imagepool.get(
                resources.path('images/icon-playlist_large.png')))
        title.pack_start(widgetutil.align_middle(logo))
        label = widgetset.Label(_("Playlists"))
        label.set_size(widgetutil.font_scale_from_osx_points(30))
        label.set_bold(True)
        title.pack_start(widgetutil.align_middle(label, left_pad=5))
        self.pack_start(widgetutil.align_center(
                title, top_pad=30, bottom_pad=20))

        bottom = widgetset.VBox()

        self._build_add_playlist_section(bottom)

        self.pack_start(widgetutil.align_center(bottom))
Пример #11
0
 def __init__(self, tab_type, selected_tabs):
     Display.__init__(self)
     self.type = tab_type
     self.child_count = self.folder_count = self.folder_child_count = 0
     tab_list = app.tabs[tab_type]
     for tab in selected_tabs:
         if hasattr(tab, "is_folder") and tab.is_folder:
             self.folder_count += 1
             self.folder_child_count += tab_list.get_child_count(tab.id)
         else:
             self.child_count += 1
     vbox = widgetset.VBox(spacing=20)
     label = self._make_label(tab_type, selected_tabs)
     label.set_size(widgetutil.font_scale_from_osx_points(30))
     label.set_bold(True)
     label.set_color((0.3, 0.3, 0.3))
     vbox.pack_start(widgetutil.align_center(label))
     vbox.pack_start(widgetutil.align_center(self._make_buttons(tab_type)))
     self.widget = widgetutil.align_middle(vbox)
Пример #12
0
 def __init__(self, tab_type, selected_tabs):
     Display.__init__(self)
     self.type = tab_type
     self.child_count = self.folder_count = self.folder_child_count = 0
     tab_list = app.tabs[tab_type]
     for tab in selected_tabs:
         if hasattr(tab, "is_folder") and tab.is_folder:
             self.folder_count += 1
             self.folder_child_count += tab_list.get_child_count(tab.id)
         else:
             self.child_count += 1
     vbox = widgetset.VBox(spacing=20)
     label = self._make_label(tab_type, selected_tabs)
     label.set_size(widgetutil.font_scale_from_osx_points(30))
     label.set_bold(True)
     label.set_color((0.3, 0.3, 0.3))
     vbox.pack_start(widgetutil.align_center(label))
     vbox.pack_start(widgetutil.align_center(
         self._make_buttons(tab_type)))
     self.widget = widgetutil.align_middle(vbox)
Пример #13
0
class ListViewRenderer(widgetset.ItemListRenderer):
    """Renderer for more complex list view columns.

    This class is useful for renderers that use the cellpack.Layout class.
    """
    font_size = widgetutil.font_scale_from_osx_points(11)
    default_text_color = widgetutil.BLACK
    selected_text_color = widgetutil.WHITE
    min_width = 5
    min_height = 16  # 21px total - 5px spacing

    def hotspot_test(self, style, layout_manager, x, y, width, height):
        layout = self.layout_all(layout_manager, width, height, False)
        hotspot_info = layout.find_hotspot(x, y)
        if hotspot_info is None:
            return None
        hotspot, x, y = hotspot_info
        return hotspot

    def get_size(self, style, layout_manager):
        layout_manager.set_font(self.font_size)
        height = max(self.min_height,
                     layout_manager.current_font.line_height())
        return (self.min_width, height)

    def render(self, context, layout_manager, selected, hotspot, hover):
        layout = self.layout_all(layout_manager, context.width, context.height,
                                 selected)
        layout.draw(context)

    def layout_all(self, layout_manager, width, height, selected):
        """Layout the contents of this cell

        Subclasses must implement this method

        :param layout_manager: LayoutManager object
        :param width: width of the area to lay the cell out in
        :param height: height of the area to lay the cell out in
        :returns: cellpack.Layout object
        """
        raise NotImplementedError()
Пример #14
0
    def __init__(self):
        widgetset.SolidBackground.__init__(
            self, itemlistwidgets.StandardView.BACKGROUND_COLOR)
        bg = widgetutil.RoundedSolidBackground(widgetutil.WHITE)
        vbox = widgetset.VBox()
        title = widgetset.HBox()
        logo = imagepool.get_image_display(
            resources.path('images/icon-search_large.png'))
        title.pack_start(widgetutil.align_middle(logo))
        label = widgetset.Label(self.TITLE)
        label.set_bold(True)
        label.set_size(widgetutil.font_scale_from_osx_points(30))
        title.pack_start(widgetutil.align_middle(label, left_pad=5))
        vbox.pack_start(widgetutil.align_center(title, bottom_pad=20))
        desc = widgetset.Label(self.DESC)
        vbox.pack_start(widgetutil.align_center(desc, bottom_pad=40))

        engine_width = int((desc.get_width() - 30) / 2)

        engine_widgets = self.build_engine_widgets()
        for widgets in engine_widgets[:-1]:  # widgets with borders
            hbox = widgetset.HBox(spacing=30)
            for widget in widgets:
                widget.set_size_request(engine_width, 45)
                hbox.pack_start(widget, expand=True)
            vbox.pack_start(hbox)

        hbox = widgetset.HBox(spacing=30)
        for widget in engine_widgets[-1]:  # has no border
            widget.set_has_border(False)
            widget.set_size_request(engine_width, 45)
            hbox.pack_start(widget, expand=True)

        vbox.pack_start(hbox)

        bg.add(widgetutil.pad(vbox, 45, 45, 45, 45))
        self.add(widgetutil.align(bg, xalign=0.5, top_pad=50))
Пример #15
0
class MultiRowAlbumRenderer(widgetset.ItemListRenderer):
    """Renderer for album view."""

    IGNORE_PADDING = True
    DRAW_BACKGROUND = False

    IMAGE_MARGIN_TOP = 4
    IMAGE_MARGIN_BOTTOM = 3
    IMAGE_MARGIN_LEFT = 7
    IMAGE_MARGIN_RIGHT = 6

    MIN_TEXT_WIDTH = 78
    TEXT_PADDING_RIGHT = 6
    TRACK_NUMBER_MARGIN_RIGHT = 13

    BACKGROUND_COLOR = widgetutil.WHITE
    TEXT_COLOR = widgetutil.BLACK
    TRACK_TEXT_COLOR = widgetutil.css_to_color('#969696')
    BOTTOM_LINE_COLOR = widgetutil.css_to_color('#dddddd')
    FONT_SIZE = widgetutil.font_scale_from_osx_points(11)

    min_width = 260

    def __init__(self):
        widgetset.ItemListRenderer.__init__(self)
        self._render_strategy = _StandardRenderStrategy()
        self._setup_default_image_map()

    def _setup_default_image_map(self):
        """Setup the _default_image_map attribute.

        _default_image_map maps the default images for things to a default
        image that looks better in album view.
        """
        # check if we're using one of the default image files and switch to an
        # album-view-specific default file in that case
        mappings = [
            ('thumb-default-audio.png', 'album-view-default-audio.png'),
            ('thumb-default-video.png', 'album-view-default-video.png'),
            ('icon-podcast-small.png', 'album-view-default-podcast.png'),
            ('icon-watched-folder.png', 'album-view-watched-folder.png'),
        ]
        self._default_image_map = {}
        for src, dest in mappings:
            src_path = resources.path('images/%s' % src)
            dest_path = resources.path('images/%s' % dest)
            self._default_image_map[src_path] = dest_path

    def get_image_path(self):
        image_path = self._render_strategy.get_image_path(
            self.info, self.get_first_info())
        if image_path in self._default_image_map:
            return self._default_image_map[image_path]
        else:
            return image_path

    def get_album(self):
        return self._render_strategy.get_album(self.info,
                                               self.get_first_info())

    def get_artist(self):
        return self._render_strategy.get_artist(self.info,
                                                self.get_first_info())

    def get_track_number(self):
        return self._render_strategy.get_track_number(self.info,
                                                      self.get_first_info())

    def get_current_row(self):
        return self.group_info[0]

    def get_total_rows(self):
        return self.group_info[1]

    def get_first_info(self):
        return self.group_info[2]

    def switch_mode(self, new_mode):
        """Switch which mode we use to render the album art.

        Currently there are 3 modes:

        - 'standard' -- standard view of the data
        - 'feed' -- use feed info instead of album info
        - 'video' -- mode for the all videos tab
        """
        if new_mode == 'standard':
            self._render_strategy = _StandardRenderStrategy()
        elif new_mode == 'feed':
            self._render_strategy = _FeedRenderStrategy()
        elif new_mode == 'video':
            self._render_strategy = _VideoRenderStrategy()
        else:
            raise ValueError("Unknown mode: %s" % new_mode)

    def get_size(self, style, layout_manager):
        # return 0 for height because we render to multiple columns.  We let
        # the other columns determin the row height
        return self.min_width, 0

    def hotspot_test(self, style, layout_manager, x, y, width, height):
        return 'album-click'

    def render(self, context, layout_manager, selected, hotspot, hover):
        if not self.sanity_check_before_render(context):
            return

        # draw our background color behind everything.  We need this in case
        # there's transparency in our album art
        context.set_color(self.BACKGROUND_COLOR)
        context.rectangle(0, 0, context.width, context.height)
        context.fill()

        self.calc_album_art_size(context)
        self.render_album_art(context)
        self.render_track_number(context, layout_manager)
        self.render_album_or_artist(context, layout_manager)

    def sanity_check_before_render(self, context):
        """Do some sanity checking before starting to render things.

        Returns True if we're okay to render, False if we should bail
        """
        if self.group_info is None:
            # we can't render if group_info isn't set
            logging.warn("group_info is None in MultiRowAlbumRenderer")
            return False
        if context.height == 0:
            # not sure how this would happen, but we need to avoid
            # divide-by-zero errors if it does
            logging.warn("row height is 0 in MultiRowAlbumRenderer")
            return False
        return True

    def calc_album_art_size(self, context):
        """Calculate how big we are going to draw album art.

        This is currently big enough so it fits in 6 rows with the top/bottom
        padding.
        """
        self.album_art_size = context.height * 6
        self.album_art_size -= (self.IMAGE_MARGIN_TOP +
                                self.IMAGE_MARGIN_BOTTOM)

    def make_album_art(self, context):
        """Make an image to draw as album art.

        Returns ImageSurface to draw or None if we don't have anything
        """
        if self.get_total_rows() < 6:
            # don't draw album art if we have less than 6 items in the group
            return None

        album_art_path = self.get_image_path()
        if album_art_path is None:
            return None
        return imagepool.get_surface(
            album_art_path,
            size=(self.album_art_size, self.album_art_size),
            invalidator=util.mtime_invalidator(album_art_path))

    def render_album_art(self, context):
        album_art = self.make_album_art(context)
        if (album_art is not None
                and self.cell_contains_album_art(context, album_art)):
            self.render_album_art_slice(context, album_art)

    def cell_contains_album_art(self, context, album_art):
        """Does this cell contain a portion of the album art?
        """
        album_art_bottom = album_art.height + self.IMAGE_MARGIN_TOP
        cell_top = self.get_current_row() * context.height
        cell_bottom = cell_top + context.height
        return (cell_bottom > self.IMAGE_MARGIN_TOP
                and cell_top < album_art_bottom)

    def render_album_art_slice(self, context, image):
        """Render the slice of the album art for this cell."""

        if context.width < image.width:
            # not enough width to draw
            return

        # setup variables to track where we are copying from and to

        dest_x = self.IMAGE_MARGIN_LEFT
        width = image.width

        dest_y = 0
        height = context.height

        src_x = 0
        src_y = self.get_current_row() * context.height - self.IMAGE_MARGIN_TOP

        if src_y < 0:
            # The cell is contains the top padding for our image.
            # move dest_y and src_y down
            dest_y -= src_y
            src_y = 0
            # descrease height
            height -= dest_y
        src_y_bottom = src_y + height
        if src_y_bottom > image.height:
            # The cell is contains the bottom padding for our image.
            # decrease height
            extra_space = src_y_bottom - image.height
            height -= extra_space
        # draw our image slice
        if height > 0:
            image.draw_rect(context, dest_x, dest_y, src_x, src_y, width,
                            height)

    def render_album_or_artist(self, context, layout_manager):
        x = (self.album_art_size + self.IMAGE_MARGIN_LEFT +
             self.IMAGE_MARGIN_RIGHT)
        if self.get_current_row() == 0:
            text = self.get_artist()
            bold = True
        elif self.get_current_row() == 1:
            text = self.get_album()
            bold = False
        else:
            return

        width = self.album_artist_text_end - x
        if width < 10:
            # don't try to render if we have a really small, or negative
            # amount of space
            return
        # setup a textbox for the text
        layout_manager.set_font(self.FONT_SIZE, bold=bold)
        layout_manager.set_text_color(self.TEXT_COLOR)
        textbox = layout_manager.textbox(text)
        # truncate the textbox to the area we have in a cell.
        textbox.set_wrap_style('truncated-char')
        textbox.set_width(width)
        # middle-align the text to line-up with the other cells
        line_height = textbox.font.line_height()
        y = (context.height - line_height) / 2.0
        # okay, ready to draw
        textbox.draw(context, x, y, width, line_height)

    def render_track_number(self, context, layout_manager):
        # setup a textbox for the text
        layout_manager.set_font(self.FONT_SIZE)
        layout_manager.set_text_color(self.TRACK_TEXT_COLOR)
        textbox = layout_manager.textbox(str(self.get_track_number()))
        # place the text on the right-side of the cell
        text_width, text_height = textbox.get_size()
        x = context.width - self.TEXT_PADDING_RIGHT - text_width
        # middle-align the text to line-up with the other cells
        y = (context.height - text_height) // 2
        # okay, ready to draw
        textbox.draw(context, x, y, text_width, text_height)
        self.album_artist_text_end = x - self.TEXT_PADDING_RIGHT
Пример #16
0
    def __init__(self):
        self.device = None
        widgetset.VBox.__init__(self)

        self.button_row = segmented.SegmentedButtonsRow()

        for key, name in (
            ('main', _('Main')),
            ('podcasts', _('Podcasts')),
            ('playlists', _('Playlists')),
            ('settings', _('Settings'))):
            button = DeviceTabButtonSegment(key, name,
                                            self._tab_clicked)
            self.button_row.add_button(name.lower(), button)

        self.button_row.set_active('main')
        self.pack_start(widgetutil.align_center(
                        self.button_row.make_widget(), top_pad=50))

        self.tabs = {}
        self.tab_container = widgetset.Background()
        self.pack_start(self.tab_container, expand=True)


        label_size = widgetutil.font_scale_from_osx_points(16)
        vbox = widgetset.VBox()
        label = widgetset.Label(_("Drag individual video and audio files "
                                  "onto the device in the sidebar to copy "
                                  "them."))
        label.set_size(label_size)
        vbox.pack_start(widgetutil.align_center(label, top_pad=50))
        label = widgetset.Label(_("Use these options and the tabs above for "
                                  "automatic syncing."))
        label.set_size(label_size)
        vbox.pack_start(widgetutil.align_center(label, top_pad=10))

        self.auto_sync = widgetset.Checkbox(_("Sync automatically?"))
        self.auto_sync.connect('toggled', self._auto_sync_changed)
        vbox.pack_start(widgetutil.align_center(self.auto_sync,
                                                top_pad=20))
        max_fill_label = _(
            "Don't fill more than %(count)i percent of the "
            "free space on my device",
            {'count': id(self)})
        checkbox_label, text_label = max_fill_label.split(unicode(id(self)), 1)
        self.max_fill_enabled = widgetset.Checkbox(checkbox_label)
        self.max_fill_enabled.connect('toggled',
                                      self._max_fill_enabled_changed)
        self.max_fill_percent = widgetset.TextEntry()
        self.max_fill_percent.set_size_request(50, -1)
        self.max_fill_percent.connect('focus-out',
                                      self._max_fill_percent_changed)
        label = widgetset.Label(text_label)
        vbox.pack_start(widgetutil.align_center(
                widgetutil.build_hbox([self.max_fill_enabled,
                                       self.max_fill_percent,
                                       label], 0),
                top_pad=10))

        self.auto_fill = widgetset.Checkbox(
            _("After syncing my selections in the tabs above, "
              "fill remaining space with:"))
        self.auto_fill.connect('toggled', self._auto_fill_changed)
        vbox.pack_start(widgetutil.align_center(self.auto_fill,
                                                top_pad=20))
        names = [
            (_('Newest Music'), u'recent_music'),
            (_('Random Music'), u'random_music'),
            (_('Most Played Songs'), u'most_played_music'),
            (_('New Playlists'), u'new_playlists'),
            (_('Most Recent Podcasts'), u'recent_podcasts')]
        longest = max(names, key=lambda x: len(x[0]))[0]
        width = widgetset.Label(longest).get_width()
        less_label = widgetset.Label(_('Less').upper())
        less_label.set_size(label_size / 2)
        more_label = widgetset.Label(_('More').upper())
        more_label.set_size(label_size / 2)
        label_hbox = widgetutil.build_hbox([
                less_label,
                widgetutil.pad(more_label,
                               left=(200 - less_label.get_width() -
                                     more_label.get_width()))],
                                           padding=0)
        label_hbox.set_size_request(200, -1)
        scrollers = [widgetutil.align_right(label_hbox,
                                            right_pad=20)]
        self.auto_fill_sliders = {}
        for name, setting in names:
            label = widgetutil.align_right(widgetset.Label(name))
            label.set_size_request(width, -1)
            dragger = AutoFillSlider()
            dragger.connect('released', self._auto_fill_slider_changed,
                            setting)
            self.auto_fill_sliders[setting] = dragger
            hbox = widgetutil.build_hbox([label, dragger], 20)
            scrollers.append(hbox)
        vbox.pack_start(widgetutil.align_center(
                widgetutil.build_vbox(scrollers, 10)))

        self.device_size = SizeWidget()
        self.device_size.sync_button.connect('clicked', self.sync_clicked)
        self.pack_end(self.device_size)

        self.sync_container = widgetset.Background()
        self.pack_end(widgetutil.align_center(self.sync_container))

        self.add_tab('main', vbox)
        self.add_tab('podcasts', widgetutil.align_center(PodcastSyncWidget()))
        self.add_tab('playlists',
                     widgetutil.align_center(PlaylistSyncWidget()))
        self.add_tab('settings',
                     widgetutil.align_center(DeviceSettingsWidget()))