def switch_page(notebook, page, page_num): action_widget = notebook.get_action_widget(gtk.PACK_END) if action_widget.child is not None: action_widget.remove(action_widget.child) page = notebook.get_nth_page(page_num) blacfg.set("general", "metadata.view", page_num) if page_num == blaconst.METADATA_TAGS: widget = page.get_control_widget() elif page_num == blaconst.METADATA_LYRICS: button = gtk.Button() button.set_tooltip_text("Edit lyrics") button.set_relief(gtk.RELIEF_NONE) button.set_focus_on_click(False) button.add( gtk.image_new_from_stock(gtk.STOCK_EDIT, gtk.ICON_SIZE_MENU)) style = gtk.RcStyle() style.xthickness = style.ythickness = 0 button.modify_style(style) # TODO: Implement a widget to edit metadata. button.connect("clicked", lambda *x: False) button.show_all() widget = button action_widget.set_visible(False) return else: action_widget.set_visible(False) return action_widget.add(widget) action_widget.set_visible(True) action_widget.show_all()
def set_view(self, view): view_prev = blacfg.getint("general", "view") blacfg.set("general", "view", view) if player.video: # If the previous view was the video view coerce the cover art # display into acting as new video canvas. self.__side_pane.cover_display.use_as_video_canvas( view != blaconst.VIEW_VIDEO) child = self.__container.get_child() if view == view_prev and child is not None: return if child is not None: self.__container.remove(child) child = self.__views[view] if child.get_parent() is not None: child.unparent() self.__container.add(child) child.update_statusbar() # Not all menu items are available for all views so update them # accordingly. ui_manager.update_menu(view) self.__side_pane.set_active_view(view)
def __add_directory(self, button, treeview): filediag = gtk.FileChooserDialog( "Select a directory", action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) # TODO: Remember the last directory. filediag.set_current_folder(os.path.expanduser("~")) response = filediag.run() directory = None if response == gtk.RESPONSE_OK: directory = filediag.get_filename() filediag.destroy() if directory: model = treeview.get_model() for row in model: if row[0] == directory: return model.append([directory]) directories = blacfg.getdotliststr("library", "directories") blacfg.set("library", "directories", ":".join(directories + [directory])) if (os.path.realpath(directory) not in map(os.path.realpath, directories)): library.scan_directory(directory)
def columns_changed(treeview, view_id): if view_id == blaconst.VIEW_PLAYLISTS: view = "playlist" elif view_id == blaconst.VIEW_QUEUE: view = "queue" columns = [column.id_ for column in treeview.get_columns()] blacfg.set("general", "columns.%s" % view, ", ".join(map(str, columns)))
def __save_playlist(self, window): diag = gtk.FileChooserDialog( "Save playlist", action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) diag.set_do_overwrite_confirmation(True) self.__set_file_chooser_directory(diag) items = [ ("M3U", "audio/x-mpegurl", "m3u"), ("PlS", "audio/x-scpls", "pls", ), ("XSPF", "application/xspf+xml", "xspf"), ("Decide by extension", None, None) ] for label, mime_type, extension in items: filt = gtk.FileFilter() filt.set_name(label) filt.add_pattern("*.%s" % extension) if mime_type: filt.add_mime_type(mime_type) diag.add_filter(filt) # Add combobox to the dialog to choose whether to save relative or # absolute paths in the playlist. box = diag.child hbox = gtk.HBox() cb = gtk.combo_box_new_text() hbox.pack_end(cb, expand=False, fill=False) box.pack_start(hbox, expand=False, fill=False) box.show_all() map(cb.append_text, ["Relative paths", "Absolute paths"]) cb.set_active(0) def filter_changed(diag, filt): filt = diag.get_filter() if diag.list_filters().index(filt) == 2: sensitive = False else: sensitive = True cb.set_sensitive(sensitive) diag.connect("notify::filter", filter_changed) response = diag.run() path = diag.get_filename() if response == gtk.RESPONSE_OK and path: filt = diag.get_filter() type_ = items[diag.list_filters().index(filt)][-1] path = path.strip() if type_ is None: type_ = blautil.get_extension(path) playlist_manager.save(path, type_, cb.get_active() == 0) blacfg.set("general", "filechooser.directory", os.path.dirname(path)) diag.destroy()
def __volume_changed(self, scale): state = blacfg.getboolean("player", "muted") if state: volume = self.__volume else: volume = scale.get_value() blacfg.set("player", "volume", volume / 100.0) player.set_volume(scale.get_value()) self.__update_icon(state)
def __filter_changed(self, radiobutton, filt): # The signal of the new active radiobutton arrives last so only change # the config then. if radiobutton.get_active(): blacfg.set("general", "releases.filter", filt) self.__treeview.set_model(self.__models[filt]) if filt == blaconst.NEW_RELEASES_FROM_LIBRARY: count = self.__count_library else: count = self.__count_recommended self.emit("count_changed", blaconst.VIEW_RELEASES, count)
def __configure_event(self, window, event): if self.__maximized: return self.__size = (event.width, event.height) if self.__is_main_window: blacfg.set("general", "size", "%d, %d" % self.__size) if self.get_property("visible"): self.__position = self.get_position() if self.__is_main_window: blacfg.set("general", "position", "%d, %d" % self.__position)
def __filter_changed(self, radiobutton, filt, hbox): # The signal of the new active radiobutton arrives last so only change # the config when that happens. if radiobutton.get_active(): blacfg.set("general", "events.filter", filt) self.__treeview.set_model(self.__models[filt]) if filt == blaconst.EVENTS_RECOMMENDED: hbox.set_visible(False) else: hbox.set_visible(True) if filt == blaconst.EVENTS_RECOMMENDED: count = self.__count_recommended else: count = self.__count_all self.emit("count_changed", blaconst.VIEW_EVENTS, count)
def column_selected(m, column_id, view_id, view): if m.get_active(): if column_id not in columns: columns.append(column_id) else: try: columns.remove(column_id) except ValueError: pass blacfg.set("general", "columns.%s" % view, ", ".join(map(str, columns))) if view_id == blaconst.VIEW_PLAYLISTS: for treeview in BlaTreeView.playlist_instances: update_columns(treeview, view_id) else: update_columns(BlaTreeView.queue_instance, view_id)
def __remove_directory(self, button, treeview): model, iterator = treeview.get_selection().get_selected() if iterator: directories = blacfg.getdotliststr("library", "directories") directory = model[iterator][0] model.remove(iterator) try: directories.remove(directory) except ValueError: pass blacfg.set("library", "directories", ":".join(directories)) if (os.path.realpath(directory) not in map(os.path.realpath, directories)): library.remove_directory(directory)
def __open_playlist(self, window): diag = gtk.FileChooserDialog( "Select playlist", buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) diag.set_local_only(True) self.__set_file_chooser_directory(diag) response = diag.run() path = diag.get_filename() diag.destroy() if response == gtk.RESPONSE_OK and path: path = path.strip() if playlist_manager.open_playlist(path): self.__view.set_view(blaconst.VIEW_PLAYLISTS) blacfg.set("general", "filechooser.directory", os.path.dirname(path))
def __equalizer_value_changed(self, scale, band, combobox): profile_name = combobox.get_active_text() if not profile_name: return # Store new equalizer values in config. values = [] for s in self.__scales: values.append(s.get_value()) values[band] = scale.get_value() blacfg.set("equalizer.profiles", profile_name, ("%.1f, " * (blaconst.EQUALIZER_BANDS-1) + "%.1f") % tuple(values)) blacfg.set("player", "equalizer.profile", profile_name) # Update the specified band in the playback device. player.set_equalizer_value(band, scale.get_value())
def update_columns(treeview, view_id): treeview.disconnect_changed_signal() if view_id == blaconst.VIEW_PLAYLISTS: default = COLUMNS_DEFAULT_PLAYLIST view = "playlist" elif view_id == blaconst.VIEW_QUEUE: default = COLUMNS_DEFAULT_QUEUE view = "queue" map(treeview.remove_column, treeview.get_columns()) columns = blacfg.getlistint("general", "columns.%s" % view) if columns is None: columns = default blacfg.set( "general", "columns.%s" % view, ", ".join(map(str, columns))) xpad = gtk.CellRendererText().get_property("xpad") for column_id in columns: column = BlaColumn(column_id) title = COLUMN_TITLES[column_id] label = gtk.Label(title) width = label.create_pango_layout(title).get_pixel_size()[0] column.set_widget(label) if column_id not in [COLUMN_QUEUE_POSITION, COLUMN_PLAYING, COLUMN_TRACK, COLUMN_DURATION]: column.set_expand(True) column.set_resizable(True) column.set_fixed_width(1) else: column.set_min_width(width + 12 + xpad) widget = column.get_widget() widget.show() treeview.append_column(column) widget.get_ancestor(gtk.Button).connect( "button_press_event", _header_popup, view_id) column.connect( "clicked", lambda c=column, i=column_id: treeview.sort_column(c, i)) treeview.connect_changed_signal()
def get_session_key(cls, create=False): session_key = blacfg.getstring("lastfm", "sessionkey") if session_key: return session_key if not create or cls.__requested_authorization: return None if not cls.__token: cls.__token = get_request_token() if not cls.__token: return None cls.__request_authorization() return None # FIXME: on start when there are unsubmitted scrobbles and no session # key but a user name the request auth window will pop up which # causes the statusbar to not update properly # TODO: check this more than once # We have a token, but it still might be unauthorized, i.e. we can't # create a session key from it. If that is the case ignore the # situation until the next start of blaplay. In order to avoid sending # requests to last.fm all the time we set an escape variable when we # encounter an unauthorized token. method = "auth.getSession" params = [ ("method", method), ("api_key", blaconst.LASTFM_APIKEY), ("token", cls.__token) ] api_signature = sign_api_call(params) string = "&".join(["%s=%s" % p for p in params]) url = "%s&api_sig=%s&%s" % ( blaconst.LASTFM_BASEURL, api_signature, string) response = get_response(url, "session") if isinstance(response, ResponseError): session_key = None cls.__requested_authorization = True else: session_key = response.content["key"] blacfg.set("lastfm", "sessionkey", session_key) return session_key
def __change_location(self, button, location): diag = blaguiutils.BlaDialog(title="Change location") # Country list country = blacfg.getstring("general", "events.country") entry1 = gtk.Entry() entry1.set_text(country) city = blacfg.getstring("general", "events.city") entry2 = gtk.Entry() entry2.set_text(city) table = gtk.Table(rows=2, columns=2, homogeneous=False) table.set_border_width(10) items = [("Country", entry1), ("City", entry2)] for idx, (label, entry) in enumerate(items): entry.connect( "activate", lambda *x: diag.response(gtk.RESPONSE_OK)) label = gtk.Label("%s:" % label) label.set_alignment(xalign=0.0, yalign=0.5) table.attach(label, idx, idx+1, 0, 1) table.attach(entry, idx, idx+1, 1, 2) diag.vbox.pack_start(table) diag.show_all() response = diag.run() if response == gtk.RESPONSE_OK: country = entry1.get_text() city = entry2.get_text() diag.destroy() if not city: location.set_markup("<i>Unspecified</i>") else: location.set_text( ", ".join([city, country] if country else [city])) blacfg.set("general", "events.country", country) blacfg.set("general", "events.city", city)
def __add_tracks(self, files=True): if files: action = gtk.FILE_CHOOSER_ACTION_OPEN else: action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER diag = gtk.FileChooserDialog( "Select files", action=action, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) diag.set_select_multiple(True) diag.set_local_only(True) self.__set_file_chooser_directory(diag) response = diag.run() filenames = diag.get_filenames() diag.destroy() if response == gtk.RESPONSE_OK and filenames: filenames = map(str.strip, filenames) playlist_manager.add_to_current_playlist(filenames, resolve=True) blacfg.set("general", "filechooser.directory", os.path.dirname(filenames[0]))
def __init__(self): super(BlaBrowsers, self).__init__() type(self).__library_browser = BlaLibraryBrowser(self) self.__file_browser = BlaFileBrowser(self) self.append_page(self.__library_browser, gtk.Label("Library")) self.append_page(self.__file_browser, gtk.Label("Filesystem")) self.show_all() page_num = blacfg.getint("general", "browser.view") if page_num not in (0, 1): page_num = 0 self.set_current_page(page_num) self.connect("switch_page", lambda *x: blacfg.set("general", "browser.view", x[-1]))
def __profile_changed(self, combobox): profile_name = combobox.get_active_text() if profile_name: values = blacfg.getlistfloat( "equalizer.profiles", profile_name) blacfg.set("player", "equalizer.profile", profile_name) if not values: values = [0.0] * blaconst.EQUALIZER_BANDS blacfg.set( "equalizer.profiles", profile_name, ("%.1f, " * (blaconst.EQUALIZER_BANDS-1) + "%.1f") % tuple(values)) for idx, s in enumerate(self.__scales): s.set_value(values[idx]) else: blacfg.set("player", "equalizer.profile", "") for s in self.__scales: s.set_value(0) self.__scale_box.set_sensitive(False) player.enable_equalizer(True)
def __update_directory(self, directory=None, refresh=False, add_to_history=True): if not refresh: if directory is None: print_w("Directory must not be None") return False directory = os.path.expanduser(directory) # Got a relative path? if not os.path.isabs(directory): directory = os.path.join(self.__directory, directory) if not os.path.exists(directory): blaguiutils.error_dialog( "Could not find \"%s\"." % directory, "Please check the spelling and try again.") return False self.__directory = directory self.__entry.set_text(self.__directory) blacfg.set("general", "filesystem.directory", self.__directory) if add_to_history: self.__history.add(self.__directory) # FIXME: don't use gtk's model filter capabilities # TODO: keep the selection after updating the model model = self.__filt.get_model() self.__treeview.freeze_child_notify() model.clear() for dirpath, dirnames, filenames in os.walk(self.__directory): for d in sorted(dirnames, key=str.lower): if d.startswith("."): continue path = os.path.join(self.__directory, d) model.append([path, self.__pixbufs["directory"], d]) for f in sorted(filenames, key=str.lower): if f.startswith("."): continue path = os.path.join(self.__directory, f) # TODO: use this instead (profile the overhead first though): # f = gio.File(path) # info = f.query_info("standard::content-type") # mimetype = info.get_content_type() mimetype = gio.content_type_guess(path) try: pb = self.__pixbufs[mimetype] except KeyError: icon_names = gio.content_type_get_icon(mimetype) pb = self.__pixbufs["file"] if icon_names: for icon_name in icon_names.get_names(): pb_new = self.__get_pixbuf(icon_name) if pb_new: self.__pixbufs[mimetype] = pb_new pb = pb_new model.append([path, pb, f]) break try: self.__monitor.cancel() except AttributeError: pass # FIXME: this seems to cease working after handling an event self.__monitor = gio.File(self.__directory).monitor_directory( flags=gio.FILE_MONITOR_NONE) self.__monitor.connect("changed", self.__process_event) self.__treeview.thaw_child_notify() return False
def __organize_by_changed(self, combobox): view = combobox.get_active() blacfg.set("library", "organize.by", view) self.__queue_model_update(view)
def cb_changed(combobox, key): blacfg.set("library", "%s.action" % key, combobox.get_active())
def edited(renderer, path, key, mod, *args): action = actions[int(path)][-1] accel = gtk.accelerator_name(key, mod) blakeys.bind(action, accel) bindings.set_value(bindings.get_iter(path), 1, accel) blacfg.set("keybindings", action, accel)
def cleared(renderer, path): bindings.set_value(bindings.get_iter(path), 1, None) action = actions[int(path)][-1] blakeys.unbind(blacfg.getstring("keybindings", action)) blacfg.set("keybindings", action, "")
def __save(self, *args): blacfg.set("lastfm", "user", self.__user_entry.get_text()) blacfg.set( "lastfm", "ignore.pattern", self.__ignore_entry.get_text())
def set_order(cls, radioaction, current): order = current.get_current_value() cls.__instance.__order.set_active(order) blacfg.set("general", "play.order", order)
def __init__(self): super(BlaEventBrowser, self).__init__() self.set_shadow_type(gtk.SHADOW_NONE) vbox = gtk.VBox() vbox.set_border_width(10) # Heading hbox = gtk.HBox() items = [ ("<b><span size=\"xx-large\">Events</span></b>", 0.0, 0.5, 0), ("<b><span size=\"x-small\">powered by</span></b>", 1.0, 1.0, 5) ] for markup, xalign, yalign, padding in items: label = gtk.Label() label.set_markup(markup) alignment = gtk.Alignment(xalign, yalign) alignment.add(label) hbox.pack_start(alignment, expand=True, fill=True, padding=padding) image = gtk.image_new_from_file(blaconst.LASTFM_LOGO) alignment = gtk.Alignment(1.0, 0.5) alignment.add(image) hbox.pack_start(alignment, expand=False) vbox.pack_start(hbox, expand=False) # Location hbox_location = gtk.HBox(spacing=5) label = gtk.Label() label.set_markup("<b>Location:</b>") location = gtk.Label() country = blacfg.getstring("general", "events.country") city = blacfg.getstring("general", "events.city") if not city: location.set_markup("<i>Unspecified</i>") else: location.set_text( ", ".join([city, country] if country else [city])) button = gtk.Button("Change location") button.set_focus_on_click(False) button.connect( "clicked", self.__change_location, location) for widget, padding in [(label, 0), (location, 0), (button, 5)]: alignment = gtk.Alignment(0.0, 0.5) alignment.add(widget) hbox_location.pack_start(alignment, expand=False, padding=padding) vbox.pack_start(hbox_location, expand=False) # Type selector self.__hbox = gtk.HBox(spacing=5) self.__hbox.set_border_width(10) items = [ ("Recommended events", blaconst.EVENTS_RECOMMENDED), ("All events", blaconst.EVENTS_ALL) ] active = blacfg.getint("general", "events.filter") radiobutton = None for label, filt in items: radiobutton = gtk.RadioButton(radiobutton, label) if filt == active: radiobutton.set_active(True) radiobutton.connect( "toggled", self.__filter_changed, filt, hbox_location) self.__hbox.pack_start(radiobutton, expand=False) button = gtk.Button("Refresh") button.set_focus_on_click(False) button.connect_object("clicked", BlaEventBrowser.__update_models, self) self.__hbox.pack_start(button, expand=False) vbox.pack_start(self.__hbox, expand=False) hbox = gtk.HBox(spacing=5) hbox.pack_start(gtk.Label("Maximum number of results:"), expand=False) limit = blacfg.getint("general", "events.limit") adjustment = gtk.Adjustment(limit, 1.0, 100.0, 1.0, 5.0, 0.0) spinbutton = gtk.SpinButton(adjustment) spinbutton.set_numeric(True) spinbutton.connect( "value_changed", lambda sb: blacfg.set("general", "events.limit", sb.get_value())) hbox.pack_start(spinbutton, expand=False) vbox.pack_start(hbox, expand=False) # Events list def cell_data_func_pixbuf(column, renderer, model, iterator): event = model[iterator][0] try: renderer.set_property("content", event.image) except AttributeError: renderer.set_property("content", event) def cell_data_func_text(column, renderer, model, iterator): event = model[iterator][0] # FIXME: Too much code in the try-block. try: limit = 8 markup = "<b>%s</b>\n%%s" % event.event_name artists = ", ".join(event.artists[:limit]) if len(event.artists) > limit: artists += ", and more" markup %= artists except AttributeError: markup = "" renderer.set_property("markup", markup.replace("&", "&")) def cell_data_func_text2(column, renderer, model, iterator): event = model[iterator][0] try: markup = "<b>%s</b>\n%s\n%s" % ( event.venue, event.city, event.country) except AttributeError: markup = "" renderer.set_property("markup", markup.replace("&", "&")) def cell_data_func_text3(column, renderer, model, iterator): event = model[iterator][0] markup = "" try: if event.cancelled: markup = "<span size=\"x-large\"><b>Cancelled</b></span>" except AttributeError: pass renderer.set_property("markup", markup.replace("&", "&")) self.__treeview = blaguiutils.BlaTreeViewBase( set_button_event_handlers=False) self.__treeview.set_rules_hint(True) self.__treeview.get_selection().set_mode(gtk.SELECTION_SINGLE) self.__treeview.set_headers_visible(False) # Image r = BlaCellRendererPixbuf() column = gtk.TreeViewColumn() column.pack_start(r, expand=False) column.set_cell_data_func(r, cell_data_func_pixbuf) # Title and artists r = gtk.CellRendererText() r.set_alignment(0.0, 0.0) r.set_property("wrap_mode", pango.WRAP_WORD) r.set_property("wrap_width", 350) column.pack_start(r, expand=False) column.set_cell_data_func(r, cell_data_func_text) # Location r = gtk.CellRendererText() r.set_alignment(0.0, 0.0) r.set_property("ellipsize", pango.ELLIPSIZE_END) column.pack_start(r) column.set_cell_data_func(r, cell_data_func_text2) # Event cancelled status r = gtk.CellRendererText() r.set_property("ellipsize", pango.ELLIPSIZE_END) column.pack_start(r) column.set_cell_data_func(r, cell_data_func_text3) self.__treeview.append_column(column) self.__treeview.connect("row_activated", self.__row_activated) self.__treeview.connect_object( "key_press_event", BlaEventBrowser.__key_press_event, self) self.__treeview.connect_object( "button_press_event", BlaEventBrowser.__button_press_event, self) self.__models = map(gtk.ListStore, [gobject.TYPE_PYOBJECT] * 2) self.__treeview.set_model(self.__models[active]) vbox.pack_start(self.__treeview, expand=True, padding=10) self.add_with_viewport(vbox) self.show_all() if active == blaconst.EVENTS_RECOMMENDED: hbox_location.set_visible(False) blaplay.bla.register_for_cleanup(self)
def notify(pane, propspec, key): blacfg.set("general", key, str(pane.get_position()))
def __init__(self): super(BlaPreferences.LibraryBrowsersSettings, self).__init__( "Library/Browsers") restrict_string = blacfg.getstring("library", "restrict.to") exclude_string = blacfg.getstring("library", "exclude") def destroy(*args): if (restrict_string != blacfg.getstring("library", "restrict.to") or exclude_string != blacfg.getstring("library", "exclude")): library.sync() self.connect("destroy", destroy) hbox = gtk.HBox(spacing=10) model = gtk.ListStore(gobject.TYPE_STRING) treeview = gtk.TreeView(model) treeview.set_property("rules_hint", True) r = gtk.CellRendererText() treeview.insert_column_with_attributes( -1, "Directories", r, text=0) sw = BlaScrolledWindow() sw.set_shadow_type(gtk.SHADOW_IN) sw.set_size_request(-1, 140) sw.add(treeview) directories = blacfg.getdotliststr("library", "directories") for f in directories: model.append([f]) table = gtk.Table(rows=2, columns=1) items = [ ("Add...", self.__add_directory), ("Remove", self.__remove_directory), ("Rescan all", self.__rescan_all) ] for idx, (label, callback) in enumerate(items): button = gtk.Button(label) button.connect("clicked", callback, treeview) table.attach(button, 0, 1, idx, idx+1, yoptions=not gtk.EXPAND) hbox.pack_start(sw, expand=True) hbox.pack_start(table, expand=False, fill=False) # Update library checkbutton update_library = gtk.CheckButton("Update library on startup") update_library.set_active( blacfg.getboolean("library", "update.on.startup")) update_library.connect( "toggled", lambda cb: blacfg.setboolean("library", "update.on.startup", cb.get_active())) # The file types restrict_to_entry = gtk.Entry() restrict_to_entry.set_tooltip_text( "Comma-separated list, works on filenames") restrict_to_entry.set_text( blacfg.getstring("library", "restrict.to")) restrict_to_entry.connect( "changed", lambda entry: blacfg.set("library", "restrict.to", entry.get_text())) exclude_entry = gtk.Entry() exclude_entry.set_tooltip_text( "Comma-separated list, works on filenames") exclude_entry.set_text( blacfg.getstring("library", "exclude")) exclude_entry.connect( "changed", lambda entry: blacfg.set("library", "exclude", entry.get_text())) pairs = [ (blaconst.ACTION_SEND_TO_CURRENT, "send to current playlist"), (blaconst.ACTION_ADD_TO_CURRENT, "add to current playlist"), (blaconst.ACTION_SEND_TO_NEW, "send to new playlist"), (blaconst.ACTION_EXPAND_COLLAPSE, "expand/collapse") ] # FIXME: Ugly!! actions = [""] * 4 for idx, label in pairs: actions[idx] = label comboboxes = [] def cb_changed(combobox, key): blacfg.set("library", "%s.action" % key, combobox.get_active()) for key in ["doubleclick", "middleclick", "return"]: cb = gtk.combo_box_new_text() map(cb.append_text, actions) if key == "return": cb.remove_text(3) cb.set_active(blacfg.getint("library", "%s.action" % key)) cb.connect("changed", cb_changed, key) comboboxes.append(cb) widgets = [restrict_to_entry, exclude_entry] + comboboxes labels = ["Restrict to", "Exclude", "Double-click", "Middle-click", "Return"] action_table = gtk.Table(rows=len(labels), columns=2, homogeneous=False) count = 0 for label, widget in zip(labels, widgets): label = gtk.Label("%s:" % label) label.set_alignment(xalign=0.0, yalign=0.5) action_table.attach(label, 0, 1, count, count+1, xoptions=gtk.FILL, xpadding=5) action_table.attach(widget, 1, 2, count, count+1) count += 1 hbox2 = gtk.HBox(spacing=10) draw_tree_lines = gtk.CheckButton("Draw tree lines in browsers") draw_tree_lines.set_active( blacfg.getboolean("library", "draw.tree.lines")) draw_tree_lines.connect("toggled", self.__tree_lines_changed) custom_library_browser = gtk.CheckButton( "Use custom treeview as library browser") custom_library_browser.set_active( blacfg.getboolean("library", "custom.browser")) custom_library_browser.connect( "toggled", self.__custom_library_browser_changed) hbox2.pack_start(draw_tree_lines) hbox2.pack_start(custom_library_browser) self.pack_start(hbox, expand=False) self.pack_start(update_library, expand=False) self.pack_start(action_table, expand=False) self.pack_start(hbox2, expand=False)