def PluginPreferences(self, win): box = Gtk.VBox(spacing=12) # api key section def key_changed(entry, *args): config.set("plugins", "fingerprint_acoustid_api_key", entry.get_text()) button = Button(_("Request API key"), Gtk.STOCK_NETWORK) button.connect("clicked", lambda s: util.website("https://acoustid.org/api-key")) key_box = Gtk.HBox(spacing=6) entry = UndoEntry() entry.set_text(get_api_key()) entry.connect("changed", key_changed) label = Gtk.Label(label=_("API _key:")) label.set_use_underline(True) label.set_mnemonic_widget(entry) key_box.pack_start(label, False, True, 0) key_box.pack_start(entry, True, True, 0) key_box.pack_start(button, False, True, 0) box.pack_start(Frame(_("Acoustid Web Service"), child=key_box), True, True, 0) return box
def __init__(self, parent, default="", **kwargs): if self.is_not_unique(): return super(TextEdit, self).__init__() self.set_title(_("Edit Display")) self.set_transient_for(qltk.get_top_parent(parent)) self.set_border_width(12) self.set_default_size(420, 190) vbox = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) self.box = box = self.Box(default, **kwargs) vbox.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): vbox.pack_start(b, False, True, 0) self.add(vbox) self.apply = box.apply self.revert = box.revert close.grab_focus() self.get_child().show_all()
def __init__(self, browser): if self.is_not_unique(): return super(Preferences, self).__init__() self.set_border_width(12) self.set_title(_("Playlist Browser Preferences")) self.set_default_size(420, 240) self.set_transient_for(qltk.get_top_parent(browser)) box = Gtk.VBox(spacing=6) edit_frame = self.edit_display_pane(browser, _("Playlist display")) box.pack_start(edit_frame, False, True, 12) main_box = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) main_box.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): main_box.pack_start(b, False, True, 0) self.add(main_box) close.grab_focus() self.show_all()
def PluginPreferences(self, win): box = Gtk.VBox(spacing=12) # api key section def key_changed(entry, *args): config.set("plugins", "fingerprint_acoustid_api_key", entry.get_text()) button = Button(_("Request API key"), Icons.NETWORK_WORKGROUP) button.connect("clicked", lambda s: util.website("https://acoustid.org/api-key")) key_box = Gtk.HBox(spacing=6) entry = UndoEntry() entry.set_text(get_api_key()) entry.connect("changed", key_changed) label = Gtk.Label(label=_("API _key:")) label.set_use_underline(True) label.set_mnemonic_widget(entry) key_box.pack_start(label, False, True, 0) key_box.pack_start(entry, True, True, 0) key_box.pack_start(button, False, True, 0) box.pack_start(Frame(_("AcoustID Web Service"), child=key_box), True, True, 0) return box
def __init__(self, browser): if self.is_not_unique(): return super(Preferences, self).__init__() self.set_border_width(12) self.set_title(_("Album List Preferences")) self.set_default_size(420, 380) self.set_transient_for(qltk.get_top_parent(browser)) # Do this config-driven setup at instance-time self._PREVIEW_ITEM["~rating"] = format_rating(0.75) box = Gtk.VBox(spacing=6) vbox = Gtk.VBox(spacing=6) cb = ConfigCheckButton( _("Show album _covers"), "browsers", "album_covers") cb.set_active(config.getboolean("browsers", "album_covers")) cb.connect('toggled', lambda s: browser.toggle_covers()) vbox.pack_start(cb, False, True, 0) cb = ConfigCheckButton( _("Inline _search includes people"), "browsers", "album_substrings") cb.set_active(config.getboolean("browsers", "album_substrings")) vbox.pack_start(cb, False, True, 0) f = qltk.Frame(_("Options"), child=vbox) box.pack_start(f, False, True, 12) display_frame = self.edit_display_pane(browser, _("Album Display")) box.pack_start(display_frame, True, True, 0) main_box = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) main_box.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): main_box.pack_start(b, False, True, 0) self.add(main_box) close.grab_focus() self.show_all()
def __init__(self, filters, browser, parent=None): super(SelectionWindow, self).__init__() self.set_border_width(10) self.set_title(FilterAll.PLUGIN_NAME) self.set_default_size(200, 250) self.set_transient_for(parent) model = Gtk.ListStore(bool, str, str) for key, value in sorted(filters.items()): model.append(row=[False, key, value]) toggle = Gtk.CellRendererToggle() toggle.connect("toggled", self.__toggeled, model, browser) text = Gtk.CellRendererText() toggle_column = Gtk.TreeViewColumn("", toggle, active=0) column = Gtk.TreeViewColumn(_("Tag"), text, text=1) view = Gtk.TreeView(model) view.append_column(toggle_column) view.append_column(column) sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.set_shadow_type(Gtk.ShadowType.IN) sw.add(view) buttons = Gtk.HButtonBox() buttons.set_spacing(6) buttons.set_layout(Gtk.ButtonBoxStyle.END) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) buttons.pack_start(close, True, True, 0) box = Gtk.VBox(spacing=12) box.pack_start(sw, True, True, 0) box.pack_start(buttons, False, True, 0) self.add(box) self.show_all()
def __init__(self, browser): if self.is_not_unique(): return super(Preferences, self).__init__() self._browser = browser self.set_transient_for(qltk.get_top_parent(browser)) self.set_default_size(350, 225) self.set_border_width(12) self.set_title(_("Album Collection Preferences")) vbox = Gtk.VBox(spacing=12) editor = PatternEditor() editor.headers = get_headers() apply = Button(_("_Apply")) connect_obj(apply, "clicked", self.__apply, editor, False) cancel = Button(_("_Cancel")) cancel.connect("clicked", lambda x: self.destroy()) box = Gtk.HButtonBox() box.set_spacing(6) box.set_layout(Gtk.ButtonBoxStyle.END) box.pack_start(apply, True, True, 0) self.use_header_bar() if not self.has_close_button(): box.pack_start(cancel, True, True, 0) vbox.pack_start(editor, True, True, 0) vbox.pack_start(box, False, True, 0) self.add(vbox) apply.grab_focus() self.show_all()
def PluginPreferences(self, *args): vbox = Gtk.VBox(spacing=12) label = Gtk.Label(label=_("Visualiser executable:")) def edited(widget): self.executable = widget.get_text() entry = UndoEntry() entry.connect('changed', edited) entry.set_text(self.executable) hbox = Gtk.HBox(spacing=6) hbox.pack_start(label, False, False, 0) hbox.pack_start(entry, True, True, 0) vbox.pack_start(hbox, True, True, 0) def refresh_clicked(widget): self.disabled() self.enabled() refresh_button = Button(_("Reload"), Icons.VIEW_REFRESH) refresh_button.connect('clicked', refresh_clicked) vbox.pack_start(refresh_button, False, False, 0) return vbox
def __init__(self, browser): if self.is_not_unique(): return super(Preferences, self).__init__() self.set_border_width(12) self.set_title(_("Album List Preferences") + " - Quod Libet") self.set_default_size(420, 380) self.set_transient_for(qltk.get_top_parent(browser)) # Do this config-driven setup at instance-time self._EXAMPLE_ALBUM["~rating"] = format_rating(0.75) box = Gtk.VBox(spacing=6) vbox = Gtk.VBox(spacing=6) cb = ConfigCheckButton( _("Show album _covers"), "browsers", "album_covers") cb.set_active(config.getboolean("browsers", "album_covers")) cb.connect('toggled', lambda s: browser.toggle_covers()) vbox.pack_start(cb, False, True, 0) cb = ConfigCheckButton( _("Inline _search includes people"), "browsers", "album_substrings") cb.set_active(config.getboolean("browsers", "album_substrings")) vbox.pack_start(cb, False, True, 0) f = qltk.Frame(_("Options"), child=vbox) box.pack_start(f, False, True, 12) vbox = Gtk.VBox(spacing=6) label = Gtk.Label() label.set_alignment(0.0, 0.5) label.set_padding(6, 6) eb = Gtk.EventBox() eb.get_style_context().add_class("entry") eb.add(label) edit = PatternEditBox(PATTERN) edit.text = browser._pattern_text edit.apply.connect('clicked', self.__set_pattern, edit, browser) connect_obj( edit.buffer, 'changed', self.__preview_pattern, edit, label) vbox.pack_start(eb, False, True, 3) vbox.pack_start(edit, True, True, 0) self.__preview_pattern(edit, label) f = qltk.Frame(_("Album Display"), child=vbox) box.pack_start(f, True, True, 0) main_box = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) main_box.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): main_box.pack_start(b, False, True, 0) self.add(main_box) close.grab_focus() self.show_all()
def __init__(self): super(PatternEditor, self).__init__(spacing=12) self.__headers = headers = {} buttons = [] group = None for tags in self.PRESETS: tied = "~" + "~".join([t[0] for t in tags]) group = Gtk.RadioButton(group=group, label="_" + util.tag(tied), use_underline=True) headers[group] = tags buttons.append(group) group = Gtk.RadioButton(group=group, label=_("_Custom"), use_underline=True) self.__custom = group headers[group] = [] buttons.append(group) button_box = Gtk.HBox(spacing=6) self.__model = model = Gtk.ListStore(str, bool) radio_box = Gtk.VBox(spacing=6) for button in buttons: radio_box.pack_start(button, False, True, 0) button.connect('toggled', self.__toggled, button_box, model) self.pack_start(radio_box, False, True, 0) cb = TagsComboBoxEntry(self.COMPLETION) view = BaseView(model=model) view.set_reorderable(True) view.set_headers_visible(True) ctrl_box = Gtk.VBox(spacing=6) add = Button(_("_Add"), Icons.LIST_ADD) ctrl_box.pack_start(add, False, True, 0) add.connect('clicked', self.__add, model, cb) remove = Button(_("_Remove"), Icons.LIST_REMOVE) ctrl_box.pack_start(remove, False, True, 0) remove.connect('clicked', self.__remove, view) selection = view.get_selection() selection.connect('changed', self.__selection_changed, remove) selection.emit('changed') sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) sw.set_shadow_type(Gtk.ShadowType.IN) sw.add(view) edit_box = Gtk.VBox(spacing=6) edit_box.pack_start(cb, False, True, 0) edit_box.pack_start(sw, True, True, 0) button_box.pack_start(edit_box, True, True, 0) button_box.pack_start(ctrl_box, False, True, 0) self.pack_start(button_box, True, True, 0) render = Gtk.CellRendererText() render.set_property("editable", True) def edited_cb(render, path, text, model): model[path][0] = text render.connect("edited", edited_cb, model) column = Gtk.TreeViewColumn(_("Tag"), render, text=0) column.set_expand(True) view.append_column(column) toggle = Gtk.CellRendererToggle() toggle.connect("toggled", self.__toggeled, model) toggle_column = Gtk.TreeViewColumn(_("Merge"), toggle, active=1) view.append_column(toggle_column)
class WaitLoadBase(object): """Abstract class providing a label, a progressbar, pause/stop buttons, and the stepping logic.""" def __init__(self, count=0, text="", initial={}, limit=3): """count: the total amount of items expected, 0 for unknown/indefinite text: text to display in the label; may contain % formats initial: initial values for % formats (text % initial) limit: count must be greater than limit (or 0) for pause/stop to appear The current iteration of the counter can be gotten as self.current. count can be gotten as self.count. """ super(WaitLoadBase, self).__init__() self._label = Gtk.Label() self._label.set_use_markup(True) self._progress = Gtk.ProgressBar() self._progress.set_pulse_step(0.08) self.pulse = self._progress.pulse self.set_fraction = self._progress.set_fraction self.set_text = self._label.set_markup self.setup(count, text, initial) if self.count > limit or self.count == 0: # Add stop/pause buttons. count = 0 means an indefinite # number of steps. self._cancel_button = Button(_("_Stop"), Icons.PROCESS_STOP) self._pause_button = ToggleButton(_("P_ause"), Icons.MEDIA_PLAYBACK_PAUSE) self._cancel_button.connect('clicked', self.__cancel_clicked) self._pause_button.connect('clicked', self.__pause_clicked) else: self._cancel_button = None self._pause_button = None def setup(self, count=0, text="", initial=None): self.current = 0 self.count = count self._text = text self.paused = False self.quit = False self._start_time = time.time() initial = initial or {} initial.setdefault("total", self.count) initial.setdefault("current", self.current) initial.setdefault("remaining", _("Unknown")) def localeify(k, v): foo = '%(' + k + ')d' if foo in self._text: self._text = self._text.replace(foo, '%(' + k + ')s') return k, format_int_locale(int(v)) return k, v localed = dict([localeify(k, v) for k, v in iteritems(initial)]) self._label.set_markup(self._text % localed) self._progress.set_fraction(0.0) def __pause_clicked(self, button): self.paused = button.get_active() def __cancel_clicked(self, button): self.quit = True def step(self, **values): """Advance the counter by one. Arguments are applied to the originally-supplied text as a format string. This function doesn't return if the dialog is paused (though the GTK main loop will still run), and returns True if stop was pressed. """ if self.count: self.current += 1 self._progress.set_fraction( max(0, min(1, self.current / float(self.count)))) else: self._progress.pulse() values.setdefault("total", format_int_locale(self.count)) values.setdefault("current", format_int_locale(self.current)) if self.count: t = (time.time() - self._start_time) / self.current remaining = math.ceil((self.count - self.current) * t) values.setdefault("remaining", format_time_display(remaining)) self._label.set_markup(self._text % values) while not self.quit and (self.paused or Gtk.events_pending()): Gtk.main_iteration() return self.quit
def __init__(self, browser): if self.is_not_unique(): return super().__init__() self.set_border_width(12) self.set_title(_("Cover Grid Preferences")) self.set_default_size(420, 380) self.set_transient_for(qltk.get_top_parent(browser)) # Do this config-driven setup at instance-time self._PREVIEW_ITEM["~rating"] = format_rating(0.75) self.mag_lock = False box = Gtk.VBox(spacing=6) vbox = Gtk.VBox(spacing=6) cb = ConfigCheckButton(_("Show album _text"), "browsers", "album_text") cb.set_active(config.getboolean("browsers", "album_text")) cb.connect('toggled', lambda s: browser.toggle_text()) vbox.pack_start(cb, False, True, 0) cb2 = ConfigCheckButton(_("Show \"All Albums\" Item"), "browsers", "covergrid_all") cb2.set_active(config.getboolean("browsers", "covergrid_all", True)) def refilter(s): mod = browser.view.get_model() if mod: mod.refilter() cb2.connect('toggled', refilter) vbox.pack_start(cb2, False, True, 0) cb3 = ConfigCheckButton(_("Wide Mode"), "browsers", "covergrid_wide") cb3.set_active(config.getboolean("browsers", "covergrid_wide", False)) cb3.connect('toggled', lambda s: browser.toggle_wide()) vbox.pack_start(cb3, False, True, 0) # Redraws the covers only when the user releases the slider def mag_button_press(*_): self.mag_lock = True def mag_button_release(mag, _): self.mag_lock = False mag_changed(mag) def mag_changed(mag): if self.mag_lock: return newmag = mag.get_value() oldmag = config.getfloat("browsers", "covergrid_magnification", 3.) if newmag == oldmag: print_d("Covergrid magnification haven't changed: {0}".format( newmag)) return print_d('Covergrid magnification update from {0} to {1}'.format( oldmag, newmag)) config.set("browsers", "covergrid_magnification", mag.get_value()) browser.update_mag() mag_scale = Gtk.HScale(adjustment=Gtk.Adjustment.new( config.getfloat("browsers", "covergrid_magnification", 3), 0., 10., .5, .5, 0)) mag_scale.set_tooltip_text(_("Cover Magnification")) l = Gtk.Label(label=_("Cover Magnification")) mag_scale.set_value_pos(Gtk.PositionType.RIGHT) mag_scale.connect('button-press-event', mag_button_press) mag_scale.connect('button-release-event', mag_button_release) mag_scale.connect('value-changed', mag_changed) vbox.pack_start(l, False, True, 0) vbox.pack_start(mag_scale, False, True, 0) f = qltk.Frame(_("Options"), child=vbox) box.pack_start(f, False, True, 12) display_frame = self.edit_display_pane(browser, _("Album Display")) box.pack_start(display_frame, True, True, 0) main_box = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) main_box.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): main_box.pack_start(b, False, True, 0) self.add(main_box) close.grab_focus() self.show_all()
class ViewLyrics(EventPlugin, UserInterfacePlugin): """The plugin for viewing lyrics in the main window.""" PLUGIN_ID = 'View Lyrics' PLUGIN_NAME = _('View Lyrics') PLUGIN_DESC = _('Automatically displays tag or file-based lyrics ' 'in a sidebar.') PLUGIN_ICON = Icons.FORMAT_JUSTIFY_FILL def enabled(self): self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.adjustment = self.scrolled_window.get_vadjustment() self.textview = Gtk.TextView() self.textbuffer = self.textview.get_buffer() self._italics = self.textbuffer.create_tag("italic", style="italic", foreground="grey") self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_wrap_mode(Gtk.WrapMode.WORD) self.textview.set_justification(Gtk.Justification.CENTER) self.textview.connect('key-press-event', self.key_press_event_cb) add_css(self.textview, "* { padding: 6px; }") vbox = Gtk.VBox() vbox.pack_start(self.textview, True, True, 0) self._edit_button = Button("Edit Lyrics", Icons.EDIT) hbox = Gtk.HBox() hbox.pack_end(self._edit_button, False, False, 3) vbox.pack_start(hbox, False, False, 3) self.scrolled_window.add(vbox) self.textview.show() self.scrolled_window.show() self._sig = None cur = app.player.info if cur is not None: cur = SongWrapper(cur) self.plugin_on_song_started(cur) def create_sidebar(self): vbox = Gtk.VBox(margin=0) vbox.pack_start(self.scrolled_window, True, True, 0) vbox.show_all() return vbox def disabled(self): self.textview.destroy() self.scrolled_window.destroy() def plugin_on_song_started(self, song): """Called when a song is started. Loads the lyrics. If there are lyrics associated with `song`, load them into the lyrics viewer. Otherwise, hides the lyrics viewer. """ lyrics = None if song is not None: print_d("Looking for lyrics for %s" % song("~filename")) lyrics = song("~lyrics") if lyrics: self.textbuffer.set_text(lyrics) self.adjustment.set_value(0) # Scroll to the top. self.textview.show() else: title = _("No lyrics found for\n %s") % song("~basename") self._set_italicised(title) def edit(widget): print_d("Launching lyrics editor for %s" % song("~filename")) assert isinstance(song, SongWrapper) information = Information(app.librarian, [song._song]) information.get_child()._switch_to_lyrics() information.show() if self._sig: self._edit_button.disconnect(self._sig) self._sig = self._edit_button.connect('clicked', edit) def _set_italicised(self, title): self.textbuffer.set_text(title) start = self.textbuffer.get_start_iter() end = self.textbuffer.get_end_iter() self.textbuffer.remove_all_tags(start, end) self.textbuffer.apply_tag(self._italics, start, end) def plugin_on_changed(self, songs): cur = app.player.info if cur: fn = cur("~filename") for s in songs: if s("~filename") == fn: print_d("Active song changed, reloading lyrics") self.plugin_on_song_started(SongWrapper(cur)) else: self._set_italicised(_("No active song")) def key_press_event_cb(self, widget, event): """Handles up/down "key-press-event" in the lyrics view.""" adj = self.scrolled_window.get_vadjustment().props if event.keyval == Gdk.KEY_Up: adj.value = max(adj.value - adj.step_increment, adj.lower) elif event.keyval == Gdk.KEY_Down: adj.value = min(adj.value + adj.step_increment, adj.upper - adj.page_size) elif event.keyval == Gdk.KEY_Page_Up: adj.value = max(adj.value - adj.page_increment, adj.lower) elif event.keyval == Gdk.KEY_Page_Down: adj.value = min(adj.value + adj.page_increment, adj.upper - adj.page_size) elif event.keyval == Gdk.KEY_Home: adj.value = adj.lower elif event.keyval == Gdk.KEY_End: adj.value = adj.upper - adj.page_size else: return False return True
def PluginPreferences(self, win): vb = Gtk.VBox(spacing=6) if not self.player_has_eq: l = Gtk.Label() l.set_markup( _('The current backend does not support equalization.')) vb.pack_start(l, False, True, 0) return vb def format_hertz(band): if band >= 1000: return _('%.1f kHz') % (band / 1000.) return _('%d Hz') % band bands = [format_hertz(band) for band in app.player.eq_bands] levels = get_config() + [0.] * len(bands) table = Gtk.Table(rows=len(bands), columns=3) table.set_col_spacings(6) def set_band(adj, idx): levels[idx] = adj.get_value() config.set('plugins', 'equalizer_levels', ','.join(map(str, levels))) self.apply() adjustments = [] for i, band in enumerate(bands): # align numbers and suffixes in separate rows for great justice lbl = Gtk.Label(label=band.split()[0]) lbl.set_alignment(1, 0.5) lbl.set_padding(0, 4) table.attach(lbl, 0, 1, i, i + 1, xoptions=Gtk.AttachOptions.FILL) lbl = Gtk.Label(label=band.split()[1]) lbl.set_alignment(1, 0.5) table.attach(lbl, 1, 2, i, i + 1, xoptions=Gtk.AttachOptions.FILL) adj = Gtk.Adjustment(levels[i], -24., 12., 0.1) adj.connect('value-changed', set_band, i) adjustments.append(adj) hs = Gtk.HScale(adjustment=adj) hs.set_draw_value(True) hs.set_value_pos(Gtk.PositionType.RIGHT) hs.connect('format-value', lambda s, v: _('%.1f dB') % v) table.attach(hs, 2, 3, i, i + 1) vb.pack_start(table, True, True, 0) def clicked_cb(button): [adj.set_value(0) for adj in adjustments] sorted_presets = sorted(PRESETS.iteritems()) def combo_changed(combo): # custom, skip if not combo.get_active(): return gain = sorted_presets[combo.get_active() - 1][1][1] gain = interp_bands(PRESET_BANDS, app.player.eq_bands, gain) for (g, a) in zip(gain, adjustments): a.set_value(g) combo = Gtk.ComboBoxText() combo.append_text(_("Custom")) combo.set_active(0) for key, (name, gain) in sorted_presets: combo.append_text(name) combo.connect("changed", combo_changed) bbox = Gtk.HButtonBox() clear = Button(_("_Clear"), Icons.EDIT_CLEAR) clear.connect('clicked', clicked_cb) bbox.pack_start(combo, True, True, 0) bbox.pack_start(clear, True, True, 0) vb.pack_start(bbox, True, True, 0) return vb
def __init__(self, browser): if self.is_not_unique(): return super(Preferences, self).__init__() self.set_border_width(12) self.set_title(_("Cover Grid Preferences")) self.set_default_size(420, 380) self.set_transient_for(qltk.get_top_parent(browser)) # Do this config-driven setup at instance-time self._PREVIEW_ITEM["~rating"] = format_rating(0.75) self.mag_lock = False box = Gtk.VBox(spacing=6) vbox = Gtk.VBox(spacing=6) cb = ConfigCheckButton( _("Show album _text"), "browsers", "album_text") cb.set_active(config.getboolean("browsers", "album_text")) cb.connect('toggled', lambda s: browser.toggle_text()) vbox.pack_start(cb, False, True, 0) cb2 = ConfigCheckButton( _("Show \"All Albums\" Item"), "browsers", "covergrid_all") cb2.set_active(config.getboolean("browsers", "covergrid_all", False)) cb2.connect('toggled', lambda s: browser.view.get_model().refilter()) vbox.pack_start(cb2, False, True, 0) cb3 = ConfigCheckButton( _("Wide Mode"), "browsers", "covergrid_wide") cb3.set_active(config.getboolean("browsers", "covergrid_wide", False)) cb3.connect('toggled', lambda s: browser.toggle_wide()) vbox.pack_start(cb3, False, True, 0) # Redraws the covers only when the user releases the slider def mag_button_press(*_): self.mag_lock = True def mag_button_release(mag, _): self.mag_lock = False mag_changed(mag) def mag_changed(mag): if self.mag_lock: return newmag = mag.get_value() oldmag = config.getfloat("browsers", "covergrid_magnification", 3.) if newmag == oldmag: print_d("Covergrid magnification haven't changed: {0}" .format(newmag)) return print_d('Covergrid magnification update from {0} to {1}' .format(oldmag, newmag)) config.set("browsers", "covergrid_magnification", mag.get_value()) browser.update_mag() mag_scale = Gtk.HScale( adjustment=Gtk.Adjustment.new(config.getfloat("browsers", "covergrid_magnification", 3), 0., 10., .5, .5, 0)) mag_scale.set_tooltip_text(_("Cover Magnification")) l = Gtk.Label(label=_("Cover Magnification")) mag_scale.set_value_pos(Gtk.PositionType.RIGHT) mag_scale.connect('button-press-event', mag_button_press) mag_scale.connect('button-release-event', mag_button_release) mag_scale.connect('value-changed', mag_changed) vbox.pack_start(l, False, True, 0) vbox.pack_start(mag_scale, False, True, 0) f = qltk.Frame(_("Options"), child=vbox) box.pack_start(f, False, True, 12) display_frame = self.edit_display_pane(browser, _("Album Display")) box.pack_start(display_frame, True, True, 0) main_box = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) main_box.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): main_box.pack_start(b, False, True, 0) self.add(main_box) close.grab_focus() self.show_all()
def __init__(self, model): songs_text = numeric_phrase("%d duplicate group", "%d duplicate groups", len(model)) super(DuplicateDialog, self).__init__() self.set_destroy_with_parent(True) self.set_title("Quod Libet - %s (%s)" % (Duplicates.PLUGIN_NAME, songs_text)) self.finished = False self.set_default_size(960, 480) self.set_border_width(6) swin = Gtk.ScrolledWindow() swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) swin.set_shadow_type(Gtk.ShadowType.IN) # Set up the browser view view = DuplicateSongsView(model) def cell_text(column, cell, model, iter_, index): text = model[iter_][index] cell.markup = text cell.set_property("markup", text) # Set up the columns for i, (tag, f) in enumerate(DuplicatesTreeModel.TAG_MAP): e = (Pango.EllipsizeMode.START if tag == '~filename' else Pango.EllipsizeMode.END) render = Gtk.CellRendererText() render.set_property("ellipsize", e) col = Gtk.TreeViewColumn(util.tag(tag), render) # Numeric columns are better smaller here. if tag.startswith("~#"): col.set_fixed_width(80) col.set_sizing(Gtk.TreeViewColumnSizing.FIXED) else: col.set_expand(True) col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col.set_resizable(True) col.set_cell_data_func(render, cell_text, i + 1) view.append_column(col) view.connect('popup-menu', self.__songs_popup_menu) swin.add(view) # A basic information area hbox = Gtk.HBox(spacing=6) def expand_all(*args): model = view.get_model() for row in model: if view.row_expanded(row.path): view.collapse_row(row.path) else: for row in model: view.expand_row(row.path, False) expand = Gtk.Button(_("Collapse / Expand all")) connect_obj(expand, "clicked", expand_all, view) hbox.pack_start(expand, False, True, 0) label = Gtk.Label(label=_("Duplicate key expression is '%s'") % Duplicates.get_key_expression()) hbox.pack_start(label, True, True, 0) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', self.__quit) hbox.pack_start(close, False, True, 0) vbox = Gtk.VBox(spacing=6) vbox.pack_start(swin, True, True, 0) vbox.pack_start(hbox, False, True, 0) self.add(vbox) self.show_all()
class WaitLoadBase: """Abstract class providing a label, a progressbar, pause/stop buttons, and the stepping logic.""" def __init__(self, count=0, text="", initial={}, limit=3): """count: the total amount of items expected, 0 for unknown/indefinite text: text to display in the label; may contain % formats initial: initial values for % formats (text % initial) limit: count must be greater than limit (or 0) for pause/stop to appear The current iteration of the counter can be gotten as self.current. count can be gotten as self.count. """ super().__init__() self._label = Gtk.Label() self._label.set_use_markup(True) self._progress = Gtk.ProgressBar() self._progress.set_pulse_step(0.08) self.pulse = self._progress.pulse self.set_fraction = self._progress.set_fraction self.set_text = self._label.set_markup self.setup(count, text, initial) if self.count > limit or self.count == 0: # Add stop/pause buttons. count = 0 means an indefinite # number of steps. self._cancel_button = Button(_("_Stop"), Icons.PROCESS_STOP) self._pause_button = ToggleButton(_("P_ause"), Icons.MEDIA_PLAYBACK_PAUSE) self._cancel_button.connect('clicked', self.__cancel_clicked) self._pause_button.connect('clicked', self.__pause_clicked) else: self._cancel_button = None self._pause_button = None def setup(self, count=0, text="", initial=None): self.current = 0 self.count = count self._text = text self.paused = False self.quit = False self._start_time = time.time() initial = initial or {} initial.setdefault("total", self.count) initial.setdefault("current", self.current) initial.setdefault("remaining", _("Unknown")) def localeify(k, v): foo = '%(' + k + ')d' if foo in self._text: self._text = self._text.replace(foo, '%(' + k + ')s') return k, format_int_locale(int(v)) return k, v localed = dict([localeify(k, v) for k, v in initial.items()]) self._label.set_markup(self._text % localed) self._progress.set_fraction(0.0) def __pause_clicked(self, button): self.paused = button.get_active() def __cancel_clicked(self, button): self.quit = True def step(self, **values): """Advance the counter by one. Arguments are applied to the originally-supplied text as a format string. This function doesn't return if the dialog is paused (though the GTK main loop will still run), and returns True if stop was pressed. """ if self.count: self.current += 1 self._progress.set_fraction( max(0, min(1, self.current / float(self.count)))) else: self._progress.pulse() values.setdefault("total", format_int_locale(self.count)) values.setdefault("current", format_int_locale(self.current)) if self.count: t = (time.time() - self._start_time) / self.current remaining = math.ceil((self.count - self.current) * t) values.setdefault("remaining", format_time_display(remaining)) self._label.set_markup(self._text % values) while not self.quit and (self.paused or Gtk.events_pending()): Gtk.main_iteration() return self.quit
def __init__(self, songs, title=None): super(SearchWindow, self).__init__(default_width=800, default_height=400, border_width=12, title=title) self._thread = AcoustidLookupThread(self.__lookup_cb) sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) sw.set_shadow_type(Gtk.ShadowType.IN) model = ObjectStore() self.view = view = ResultView() view.set_model(model) self.model = model self._iter_map = {} for song in songs: iter_ = self.model.append([SearchEntry(song)]) self._iter_map[song] = iter_ sw.add(view) self.pool = pool = FingerPrintPool() pool.connect("fingerprint-done", self.__fp_done_cb) pool.connect("fingerprint-error", self.__fp_error_cb) pool.connect("fingerprint-started", self.__fp_started_cb) for song in songs: pool.push(song) outer_box = Gtk.VBox(spacing=12) bbox = Gtk.HButtonBox() bbox.set_layout(Gtk.ButtonBoxStyle.END) bbox.set_spacing(6) self.__save = save = Button(_("_Save"), Icons.DOCUMENT_SAVE) save.connect("clicked", self.__on_save) save.set_sensitive(False) cancel = Button(_("_Cancel")) cancel.connect("clicked", lambda *x: self.destroy()) bbox.pack_start(save, True, True, 0) bbox.pack_start(cancel, True, True, 0) inner_box = Gtk.VBox(spacing=6) inner_box.pack_start(sw, True, True, 0) ccb = ConfigCheckButton(_("Write MusicBrainz tags"), "plugins", "fingerprint_write_mb_tags") ccb.set_active(get_write_mb_tags()) inner_box.pack_start(ccb, False, True, 0) ccb = ConfigCheckButton(_("Group by directory"), "plugins", "fingerprint_group_by_dir") ccb.set_active(get_group_by_dir()) ccb.connect("toggled", self.__group_toggled) self._group_ccb = ccb outer_box.pack_start(inner_box, True, True, 0) bottom_box = Gtk.HBox(spacing=12) mode_button = Gtk.ToggleButton(label=_("Album Mode")) mode_button.set_tooltip_text( _("Write album related tags and try to " "reduce the number of different album releases") ) mode_button.set_active(True) mode_button.connect("toggled", self.__mode_toggle) bottom_box.pack_start(mode_button, False, True, 0) bottom_box.pack_start(self._group_ccb, False, True, 0) bottom_box.pack_start(bbox, True, True, 0) outer_box.pack_start(bottom_box, False, True, 0) outer_box.show_all() self.add(outer_box) self.__album_mode = True self.__group_by_dir = True self._release_scores = {} self._directory_scores = {} self.__done = 0 self.connect("destroy", self.__destroy)
def PluginPreferences(self, win): main_vbox = Gtk.VBox(spacing=12) if not self.player_has_eq: l = Gtk.Label() l.set_markup( _('The current backend does not support equalization.')) main_vbox.pack_start(l, False, True, 0) return main_vbox def format_hertz(band): if band >= 1000: return _('%.1f kHz') % (band / 1000.) return _('%d Hz') % band bands = [format_hertz(band) for band in app.player.eq_bands] self._config = get_config() levels = self._config["Current"] # This fixes possible old corrupt config files with extra level values. if len(levels) != len(bands): print_w("Number of bands didn't match current. Using flat EQ.") levels = [0.] * len(bands) table = Gtk.Table(rows=len(bands), columns=3) table.set_col_spacings(6) def set_band(adj, idx): rounded = int(adj.get_value() * 2) / 2.0 adj.set_value(rounded) levels[idx] = rounded self._config["Current"] = levels config.set('plugins', 'equalizer_levels', str(self._config)) self.apply() adjustments = [] for i, band in enumerate(bands): # align numbers and suffixes in separate rows for great justice lbl = Gtk.Label(label=band.split()[0]) lbl.set_alignment(1, 0.5) lbl.set_padding(0, 4) table.attach(lbl, 0, 1, i, i + 1, xoptions=Gtk.AttachOptions.FILL) lbl = Gtk.Label(label=band.split()[1]) lbl.set_alignment(1, 0.5) table.attach(lbl, 1, 2, i, i + 1, xoptions=Gtk.AttachOptions.FILL) adj = Gtk.Adjustment.new(levels[i], -24., 12., 0.5, 3, 0) adj.connect('value-changed', set_band, i) adjustments.append(adj) hs = Gtk.HScale(adjustment=adj) hs.connect('button-press-event', self.__rightclick) hs.set_draw_value(True) hs.set_value_pos(Gtk.PositionType.RIGHT) hs.connect('format-value', lambda s, v: _('%.1f dB') % v) table.attach(hs, 2, 3, i, i + 1) main_vbox.pack_start(table, True, True, 0) # Reset EQ button def clicked_rb(button): [adj.set_value(0) for adj in adjustments] self._combo_default.set_active(0) self._combo_custom.set_active(0) # Delete custom preset button def clicked_db(button): selected_index = self._combo_custom.get_active() if selected_index < 1: return # Select… selected = self._combo_custom.get_active_text() self._combo_custom.set_active(0) self._combo_custom.remove(selected_index) del self._config[selected] config.set('plugins', 'equalizer_levels', str(self._config)) # Save custom preset button def clicked_sb(button): name = self._preset_name_entry.get_text() is_new = not name in self._config.keys() levels = [adj.get_value() for adj in adjustments] self._config[name] = levels config.set('plugins', 'equalizer_levels', str(self._config)) self._preset_name_entry.set_text("") if is_new: self._combo_custom.append_text(name) def find_iter(list_store, text): i = list_store.get_iter_first() while (i is not None): if list_store.get_value(i, 0) == text: return i i = list_store.iter_next(i) return None itr = find_iter(self._combo_custom.get_model(), name) self._combo_custom.set_active_iter(itr) sorted_presets = sorted(PRESETS.items()) def default_combo_changed(combo): if combo.get_active() < 1: return # Select… self._combo_custom.set_active(0) gain = sorted_presets[combo.get_active() - 1][1][1] gain = interp_bands(PRESET_BANDS, app.player.eq_bands, gain) for (g, a) in zip(gain, adjustments): a.set_value(g) def custom_combo_changed(combo): if combo.get_active() < 1: # Case: Select… self._delete_button.set_sensitive(False) return self._combo_default.set_active(0) self._delete_button.set_sensitive(True) gain = self._config[combo.get_active_text()] for (g, a) in zip(gain, adjustments): a.set_value(g) def save_name_changed(entry): name = entry.get_text() if not name or name == "Current" or name.isspace(): self._save_button.set_sensitive(False) else: self._save_button.set_sensitive(True) frame = Gtk.Frame(label=_("Default presets"), label_xalign=0.5) main_middle_hbox = Gtk.HBox(spacing=6) # Default presets combo = Gtk.ComboBoxText() self._combo_default = combo combo.append_text(_("Select…")) combo.set_active(0) for key, (name, gain) in sorted_presets: combo.append_text(name) combo.connect("changed", default_combo_changed) # This block is just for padding. padboxv = Gtk.VBox() padboxv.pack_start(combo, True, True, 6) padboxh = Gtk.HBox() padboxh.pack_start(padboxv, True, True, 6) frame.add(padboxh) main_middle_hbox.pack_start(frame, True, True, 0) reset = Button(_("_Reset EQ"), Icons.EDIT_UNDO) reset.connect('clicked', clicked_rb) main_middle_hbox.pack_start(reset, False, False, 0) main_vbox.pack_start(main_middle_hbox, False, False, 0) frame = Gtk.Frame(label=_("Custom presets"), label_xalign=0.5) main_bottom_vbox = Gtk.VBox() # Custom presets combo = Gtk.ComboBoxText() self._combo_custom = combo combo.append_text(_("Select…")) combo.set_active(0) custom_presets = self._config.keys() - {"Current"} for key in custom_presets: combo.append_text(key) combo.connect("changed", custom_combo_changed) hb = Gtk.HBox(spacing=6) hb.pack_start(combo, True, True, 0) delete = Button(_("_Delete selected"), Icons.EDIT_DELETE) delete.connect('clicked', clicked_db) delete.set_sensitive(False) self._delete_button = delete hb.pack_start(delete, False, False, 0) main_bottom_vbox.pack_start(hb, True, True, 6) hs = Gtk.HSeparator() main_bottom_vbox.pack_start(hs, True, True, 6) hb = Gtk.HBox() l = Gtk.Label(label=_("Preset name for saving:")) hb.pack_start(l, False, False, 0) main_bottom_vbox.pack_start(hb, False, False, 0) e = Gtk.Entry() e.connect("changed", save_name_changed) self._preset_name_entry = e hb = Gtk.HBox(spacing=6) hb.pack_start(e, True, True, 0) save = Button(_("_Save"), Icons.DOCUMENT_SAVE) save.connect('clicked', clicked_sb) save.set_sensitive(False) self._save_button = save hb.pack_start(save, False, False, 0) main_bottom_vbox.pack_start(hb, True, True, 6) # This block is just for padding. padboxh = Gtk.HBox() padboxh.pack_start(main_bottom_vbox, True, True, 6) frame.add(padboxh) main_vbox.pack_start(frame, True, True, 0) return main_vbox
def PluginPreferences(self, win): vb = Gtk.VBox(spacing=6) if not self.player_has_eq: l = Gtk.Label() l.set_markup( _('The current backend does not support equalization.')) vb.pack_start(l, False, True, 0) return vb def format_hertz(band): if band >= 1000: return _('%.1f kHz') % (band / 1000.) return _('%d Hz') % band bands = [format_hertz(band) for band in app.player.eq_bands] levels = get_config() + [0.] * len(bands) table = Gtk.Table(rows=len(bands), columns=3) table.set_col_spacings(6) def set_band(adj, idx): rounded = int(adj.get_value() * 2) / 2.0 adj.set_value(rounded) levels[idx] = rounded config.set('plugins', 'equalizer_levels', ','.join(str(lv) for lv in levels)) self.apply() adjustments = [] for i, band in enumerate(bands): # align numbers and suffixes in separate rows for great justice lbl = Gtk.Label(label=band.split()[0]) lbl.set_alignment(1, 0.5) lbl.set_padding(0, 4) table.attach(lbl, 0, 1, i, i + 1, xoptions=Gtk.AttachOptions.FILL) lbl = Gtk.Label(label=band.split()[1]) lbl.set_alignment(1, 0.5) table.attach(lbl, 1, 2, i, i + 1, xoptions=Gtk.AttachOptions.FILL) adj = Gtk.Adjustment.new(levels[i], -24., 12., 0.5, 3, 0) adj.connect('value-changed', set_band, i) adjustments.append(adj) hs = Gtk.HScale(adjustment=adj) hs.connect('button-press-event', self.__rightclick) hs.set_draw_value(True) hs.set_value_pos(Gtk.PositionType.RIGHT) hs.connect('format-value', lambda s, v: _('%.1f dB') % v) table.attach(hs, 2, 3, i, i + 1) vb.pack_start(table, True, True, 0) def clicked_cb(button): [adj.set_value(0) for adj in adjustments] sorted_presets = sorted(PRESETS.items()) def combo_changed(combo): # custom, skip if not combo.get_active(): return gain = sorted_presets[combo.get_active() - 1][1][1] gain = interp_bands(PRESET_BANDS, app.player.eq_bands, gain) for (g, a) in zip(gain, adjustments): a.set_value(g) combo = Gtk.ComboBoxText() combo.append_text(_("Custom")) combo.set_active(0) for key, (name, gain) in sorted_presets: combo.append_text(name) combo.connect("changed", combo_changed) bbox = Gtk.HButtonBox() clear = Button(_("_Clear"), Icons.EDIT_CLEAR) clear.connect('clicked', clicked_cb) bbox.pack_start(combo, True, True, 0) bbox.pack_start(clear, True, True, 0) vb.pack_start(bbox, True, True, 0) return vb
def __init__(self, songs, title=None): super().__init__( default_width=800, default_height=400, border_width=12, title=title) self._thread = AcoustidLookupThread(self.__lookup_cb) sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) sw.set_shadow_type(Gtk.ShadowType.IN) model = ObjectStore() self.view = view = ResultView() view.set_model(model) self.model = model self._iter_map = {} for song in songs: iter_ = self.model.append([SearchEntry(song)]) self._iter_map[song] = iter_ sw.add(view) self.pool = pool = FingerPrintPool() pool.connect('fingerprint-done', self.__fp_done_cb) pool.connect('fingerprint-error', self.__fp_error_cb) pool.connect('fingerprint-started', self.__fp_started_cb) for song in songs: pool.push(song) outer_box = Gtk.VBox(spacing=12) bbox = Gtk.HButtonBox() bbox.set_layout(Gtk.ButtonBoxStyle.END) bbox.set_spacing(6) self.__save = save = Button(_("_Save"), Icons.DOCUMENT_SAVE) save.connect("clicked", self.__on_save) save.set_sensitive(False) cancel = Button(_("_Cancel")) cancel.connect("clicked", lambda *x: self.destroy()) bbox.pack_start(save, True, True, 0) bbox.pack_start(cancel, True, True, 0) inner_box = Gtk.VBox(spacing=6) inner_box.pack_start(sw, True, True, 0) ccb = ConfigCheckButton( _("Write MusicBrainz tags"), "plugins", "fingerprint_write_mb_tags") ccb.set_active(get_write_mb_tags()) inner_box.pack_start(ccb, False, True, 0) ccb = ConfigCheckButton( _("Group by directory"), "plugins", "fingerprint_group_by_dir") ccb.set_active(get_group_by_dir()) ccb.connect("toggled", self.__group_toggled) self._group_ccb = ccb outer_box.pack_start(inner_box, True, True, 0) bottom_box = Gtk.HBox(spacing=12) mode_button = Gtk.ToggleButton(label=_("Album Mode")) mode_button.set_tooltip_text( _("Write album related tags and try to " "reduce the number of different album releases")) mode_button.set_active(True) mode_button.connect("toggled", self.__mode_toggle) bottom_box.pack_start(mode_button, False, True, 0) bottom_box.pack_start(self._group_ccb, False, True, 0) bottom_box.pack_start(bbox, True, True, 0) outer_box.pack_start(bottom_box, False, True, 0) outer_box.show_all() self.add(outer_box) self.__album_mode = True self.__group_by_dir = True self._release_scores = {} self._directory_scores = {} self.__done = 0 self.connect("destroy", self.__destroy)
def __init__(self, browser): if self.is_not_unique(): return super(Preferences, self).__init__() self.set_border_width(12) self.set_title(_("Album List Preferences")) self.set_default_size(420, 380) self.set_transient_for(qltk.get_top_parent(browser)) # Do this config-driven setup at instance-time self._EXAMPLE_ALBUM["~rating"] = format_rating(0.75) box = Gtk.VBox(spacing=6) vbox = Gtk.VBox(spacing=6) cb = ConfigCheckButton(_("Show album _covers"), "browsers", "album_covers") cb.set_active(config.getboolean("browsers", "album_covers")) cb.connect('toggled', lambda s: browser.toggle_covers()) vbox.pack_start(cb, False, True, 0) cb = ConfigCheckButton(_("Inline _search includes people"), "browsers", "album_substrings") cb.set_active(config.getboolean("browsers", "album_substrings")) vbox.pack_start(cb, False, True, 0) f = qltk.Frame(_("Options"), child=vbox) box.pack_start(f, False, True, 12) vbox = Gtk.VBox(spacing=6) label = Gtk.Label() label.set_alignment(0.0, 0.5) label.set_padding(6, 6) eb = Gtk.EventBox() eb.get_style_context().add_class("entry") eb.add(label) edit = PatternEditBox(PATTERN) edit.text = browser._pattern_text edit.apply.connect('clicked', self.__set_pattern, edit, browser) connect_obj(edit.buffer, 'changed', self.__preview_pattern, edit, label) vbox.pack_start(eb, False, True, 3) vbox.pack_start(edit, True, True, 0) self.__preview_pattern(edit, label) f = qltk.Frame(_("Album Display"), child=vbox) box.pack_start(f, True, True, 0) main_box = Gtk.VBox(spacing=12) close = Button(_("_Close"), Icons.WINDOW_CLOSE) close.connect('clicked', lambda *x: self.destroy()) b = Gtk.HButtonBox() b.set_layout(Gtk.ButtonBoxStyle.END) b.pack_start(close, True, True, 0) main_box.pack_start(box, True, True, 0) self.use_header_bar() if not self.has_close_button(): main_box.pack_start(b, False, True, 0) self.add(main_box) close.grab_focus() self.show_all()