mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8c0c1fe59e | ||
![]() |
364faf67be | ||
![]() |
7cd76f34bb | ||
![]() |
113d07a70a | ||
![]() |
1e5b894d82 | ||
![]() |
5815ca79a7 | ||
![]() |
d54cf001d7 | ||
![]() |
3bdf185788 | ||
![]() |
87786099ea | ||
![]() |
60afc4e412 | ||
![]() |
b32a065b66 | ||
![]() |
1660f26fa5 | ||
![]() |
3474c027f5 | ||
![]() |
4d1b20f7a5 | ||
![]() |
3caac937b7 |
531
bin/mpdevil
531
bin/mpdevil
@@ -36,7 +36,7 @@ if os.path.isfile("/.flatpak-info"): # test for flatpak environment
|
||||
else:
|
||||
bindtextdomain("mpdevil", localedir=None) # replace "None" by a static path if needed (e.g when installing on a non-FHS distro)
|
||||
|
||||
VERSION="1.2.0" # sync with setup.py
|
||||
VERSION="1.2.1" # sync with setup.py
|
||||
COVER_REGEX=r"^\.?(album|cover|folder|front).*\.(gif|jpeg|jpg|png)$"
|
||||
|
||||
|
||||
@@ -930,7 +930,6 @@ class GeneralSettings(Gtk.Box):
|
||||
def __init__(self, settings):
|
||||
super().__init__(orientation=Gtk.Orientation.VERTICAL, spacing=6, border_width=18)
|
||||
self._settings=settings
|
||||
self._settings_handlers=[]
|
||||
|
||||
# int settings
|
||||
int_settings={}
|
||||
@@ -943,10 +942,7 @@ class GeneralSettings(Gtk.Box):
|
||||
for label, (vmin, vmax, step), key in int_settings_data:
|
||||
int_settings[key]=(Gtk.Label(label=label, xalign=0), Gtk.SpinButton.new_with_range(vmin, vmax, step))
|
||||
int_settings[key][1].set_value(self._settings.get_int(key))
|
||||
int_settings[key][1].connect("value-changed", self._on_int_changed, key)
|
||||
self._settings_handlers.append(
|
||||
self._settings.connect("changed::{}".format(key), self._on_int_settings_changed, int_settings[key][1])
|
||||
)
|
||||
int_settings[key][1].connect("value-changed", lambda widget,key: self._settings.set_int(key, int(widget.get_value())), key)
|
||||
|
||||
# check buttons
|
||||
check_buttons={}
|
||||
@@ -963,21 +959,16 @@ class GeneralSettings(Gtk.Box):
|
||||
(_("Support “MPRIS”"), "mpris"),
|
||||
]
|
||||
for label, key in check_buttons_data:
|
||||
check_buttons[key]=Gtk.CheckButton(label=label)
|
||||
check_buttons[key]=Gtk.CheckButton(label=label, margin_start=12)
|
||||
check_buttons[key].set_active(self._settings.get_boolean(key))
|
||||
check_buttons[key].set_margin_start(12)
|
||||
check_buttons[key].connect("toggled", self._on_toggled, key)
|
||||
self._settings_handlers.append(
|
||||
self._settings.connect("changed::{}".format(key), self._on_check_settings_changed, check_buttons[key])
|
||||
)
|
||||
check_buttons[key].connect("toggled", lambda widget,key: self._settings.set_boolean(key, widget.get_active()), key)
|
||||
|
||||
# headings
|
||||
view_heading=Gtk.Label(label=_("<b>View</b>"), use_markup=True, xalign=0)
|
||||
behavior_heading=Gtk.Label(label=_("<b>Behavior</b>"), use_markup=True, xalign=0)
|
||||
|
||||
# view grid
|
||||
view_grid=Gtk.Grid(row_spacing=6, column_spacing=12)
|
||||
view_grid.set_margin_start(12)
|
||||
view_grid=Gtk.Grid(row_spacing=6, column_spacing=12, margin_start=12)
|
||||
view_grid.add(int_settings["track-cover"][0])
|
||||
view_grid.attach_next_to(int_settings["album-cover"][0], int_settings["track-cover"][0], Gtk.PositionType.BOTTOM, 1, 1)
|
||||
view_grid.attach_next_to(int_settings["icon-size"][0], int_settings["album-cover"][0], Gtk.PositionType.BOTTOM, 1, 1)
|
||||
@@ -987,9 +978,6 @@ class GeneralSettings(Gtk.Box):
|
||||
view_grid.attach_next_to(int_settings["icon-size"][1], int_settings["icon-size"][0], Gtk.PositionType.RIGHT, 1, 1)
|
||||
view_grid.attach_next_to(int_settings["icon-size-sec"][1], int_settings["icon-size-sec"][0], Gtk.PositionType.RIGHT, 1, 1)
|
||||
|
||||
# connect
|
||||
self.connect("destroy", self._remove_handlers)
|
||||
|
||||
# packing
|
||||
csd_box=Gtk.Box(spacing=12)
|
||||
csd_box.pack_start(check_buttons["use-csd"], False, False, 0)
|
||||
@@ -1011,41 +999,20 @@ class GeneralSettings(Gtk.Box):
|
||||
self.pack_start(check_buttons["force-mode"], False, False, 0)
|
||||
self.pack_start(check_buttons["stop-on-quit"], False, False, 0)
|
||||
|
||||
def _remove_handlers(self, *args):
|
||||
for handler in self._settings_handlers:
|
||||
self._settings.disconnect(handler)
|
||||
|
||||
def _on_int_settings_changed(self, settings, key, entry):
|
||||
entry.set_value(settings.get_int(key))
|
||||
|
||||
def _on_check_settings_changed(self, settings, key, button):
|
||||
button.set_active(settings.get_boolean(key))
|
||||
|
||||
def _on_int_changed(self, widget, key):
|
||||
self._settings.set_int(key, int(widget.get_value()))
|
||||
|
||||
def _on_toggled(self, widget, key):
|
||||
self._settings.set_boolean(key, widget.get_active())
|
||||
|
||||
class ProfileSettings(Gtk.Grid):
|
||||
def __init__(self, parent, client, settings):
|
||||
super().__init__(row_spacing=6, column_spacing=12, border_width=18)
|
||||
self._client=client
|
||||
self._settings=settings
|
||||
self._gui_modification=False # indicates whether the settings were changed from the settings dialog
|
||||
|
||||
# widgets
|
||||
self._profiles_combo=Gtk.ComboBoxText(entry_text_column=0, hexpand=True)
|
||||
|
||||
self._profiles_combo=ComboBoxEntry()
|
||||
add_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("list-add-symbolic", Gtk.IconSize.BUTTON))
|
||||
delete_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("list-remove-symbolic", Gtk.IconSize.BUTTON))
|
||||
add_delete_buttons=Gtk.ButtonBox(layout_style=Gtk.ButtonBoxStyle.EXPAND)
|
||||
add_delete_buttons.pack_start(add_button, True, True, 0)
|
||||
add_delete_buttons.pack_start(delete_button, True, True, 0)
|
||||
|
||||
connect_button=Gtk.Button.new_with_mnemonic(_("_Connect"))
|
||||
|
||||
self._profile_entry=Gtk.Entry(hexpand=True)
|
||||
self._host_entry=Gtk.Entry(hexpand=True)
|
||||
self._port_entry=Gtk.SpinButton.new_with_range(0, 65535, 1)
|
||||
address_entry=Gtk.Box(spacing=6)
|
||||
@@ -1053,19 +1020,14 @@ class ProfileSettings(Gtk.Grid):
|
||||
address_entry.pack_start(self._port_entry, False, False, 0)
|
||||
self._password_entry=PasswordEntry(hexpand=True)
|
||||
self._path_entry=Gtk.Entry(hexpand=True, placeholder_text=GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC))
|
||||
self._path_select_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("folder-open-symbolic", Gtk.IconSize.BUTTON))
|
||||
path_box=Gtk.Box(spacing=6)
|
||||
path_box.pack_start(self._path_entry, True, True, 0)
|
||||
path_box.pack_start(self._path_select_button, False, False, 0)
|
||||
self._path_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "folder-open-symbolic")
|
||||
self._regex_entry=Gtk.Entry(hexpand=True, placeholder_text=COVER_REGEX)
|
||||
self._regex_entry.set_tooltip_text(
|
||||
_("The first image in the same directory as the song file "\
|
||||
"matching this regex will be displayed. %AlbumArtist% and "\
|
||||
"%Album% will be replaced by the corresponding tags of the song.")
|
||||
)
|
||||
|
||||
profiles_label=Gtk.Label(label=_("Profile:"), xalign=1)
|
||||
profile_label=Gtk.Label(label=_("Name:"), xalign=1)
|
||||
host_label=Gtk.Label(label=_("Host:"), xalign=1)
|
||||
password_label=Gtk.Label(label=_("Password:"), xalign=1)
|
||||
path_label=Gtk.Label(label=_("Music lib:"), xalign=1)
|
||||
@@ -1077,44 +1039,34 @@ class ProfileSettings(Gtk.Grid):
|
||||
connect_button.connect("clicked", self._on_connect_button_clicked)
|
||||
style_context=connect_button.get_style_context()
|
||||
style_context.add_class("suggested-action")
|
||||
self._path_select_button.connect("clicked", self._on_path_select_button_clicked, parent)
|
||||
self._profiles_changed=self._profiles_combo.connect("changed", self._on_profiles_changed)
|
||||
self._path_entry.connect("icon-release", self._on_path_entry_icon_release, parent)
|
||||
self._profiles_select=self._profiles_combo.connect("select", self._on_profiles_select)
|
||||
self.entry_changed_handlers=[]
|
||||
self.entry_changed_handlers.append((self._profile_entry, self._profile_entry.connect("changed", self._on_profile_entry_changed)))
|
||||
self.entry_changed_handlers.append((self._profiles_combo, self._profiles_combo.connect("text", self._on_profile_entry_changed)))
|
||||
self.entry_changed_handlers.append((self._host_entry, self._host_entry.connect("changed", self._on_host_entry_changed)))
|
||||
self.entry_changed_handlers.append((self._port_entry, self._port_entry.connect("value-changed", self._on_port_entry_changed)))
|
||||
self.entry_changed_handlers.append((self._password_entry, self._password_entry.connect("changed", self._on_password_entry_changed)))
|
||||
self.entry_changed_handlers.append((self._path_entry, self._path_entry.connect("changed", self._on_path_entry_changed)))
|
||||
self.entry_changed_handlers.append((self._regex_entry, self._regex_entry.connect("changed", self._on_regex_entry_changed)))
|
||||
self._settings_handlers=[]
|
||||
self._settings_handlers.append(self._settings.connect("changed::profiles", self._on_settings_changed))
|
||||
self._settings_handlers.append(self._settings.connect("changed::hosts", self._on_settings_changed))
|
||||
self._settings_handlers.append(self._settings.connect("changed::ports", self._on_settings_changed))
|
||||
self._settings_handlers.append(self._settings.connect("changed::passwords", self._on_settings_changed))
|
||||
self._settings_handlers.append(self._settings.connect("changed::paths", self._on_settings_changed))
|
||||
self._settings_handlers.append(self._settings.connect("changed::regex", self._on_settings_changed))
|
||||
self.connect("destroy", self._remove_handlers)
|
||||
|
||||
self._profiles_combo_reload()
|
||||
self._profiles_combo.set_active(0)
|
||||
|
||||
# packing
|
||||
self.add(profiles_label)
|
||||
self.attach_next_to(profile_label, profiles_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
self.attach_next_to(host_label, profile_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
self.attach_next_to(host_label, profiles_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
self.attach_next_to(password_label, host_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
self.attach_next_to(path_label, password_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
self.attach_next_to(regex_label, path_label, Gtk.PositionType.BOTTOM, 1, 1)
|
||||
self.attach_next_to(self._profiles_combo, profiles_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(add_delete_buttons, self._profiles_combo, Gtk.PositionType.RIGHT, 1, 1)
|
||||
self.attach_next_to(self._profile_entry, profile_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(address_entry, host_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(self._password_entry, password_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(path_box, path_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(self._path_entry, path_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
self.attach_next_to(self._regex_entry, regex_label, Gtk.PositionType.RIGHT, 2, 1)
|
||||
connect_button.set_margin_top(12)
|
||||
self.attach_next_to(connect_button, self._regex_entry, Gtk.PositionType.BOTTOM, 2, 1)
|
||||
|
||||
self._profiles_combo_reload()
|
||||
self._profiles_combo.set_active(self._settings.get_int("active-profile"))
|
||||
|
||||
def _block_entry_changed_handlers(self, *args):
|
||||
for obj, handler in self.entry_changed_handlers:
|
||||
obj.handler_block(handler)
|
||||
@@ -1124,24 +1076,11 @@ class ProfileSettings(Gtk.Grid):
|
||||
obj.handler_unblock(handler)
|
||||
|
||||
def _profiles_combo_reload(self, *args):
|
||||
self._profiles_combo.handler_block(self._profiles_changed)
|
||||
|
||||
self._profiles_combo.handler_block(self._profiles_select)
|
||||
self._profiles_combo.remove_all()
|
||||
for profile in self._settings.get_value("profiles"):
|
||||
self._profiles_combo.append_text(profile)
|
||||
|
||||
self._profiles_combo.handler_unblock(self._profiles_changed)
|
||||
|
||||
def _remove_handlers(self, *args):
|
||||
for handler in self._settings_handlers:
|
||||
self._settings.disconnect(handler)
|
||||
|
||||
def _on_settings_changed(self, *args):
|
||||
if self._gui_modification:
|
||||
self._gui_modification=False
|
||||
else:
|
||||
self._profiles_combo_reload()
|
||||
self._profiles_combo.set_active(0)
|
||||
self._profiles_combo.handler_unblock(self._profiles_select)
|
||||
|
||||
def _on_add_button_clicked(self, *args):
|
||||
model=self._profiles_combo.get_model()
|
||||
@@ -1156,7 +1095,7 @@ class ProfileSettings(Gtk.Grid):
|
||||
self._profiles_combo.set_active(new_pos)
|
||||
|
||||
def _on_delete_button_clicked(self, *args):
|
||||
pos=self._profiles_combo.get_active()
|
||||
pos=self._profiles_combo.get_selected()
|
||||
self._settings.array_delete("as", "profiles", pos)
|
||||
self._settings.array_delete("as", "hosts", pos)
|
||||
self._settings.array_delete("ai", "ports", pos)
|
||||
@@ -1171,55 +1110,45 @@ class ProfileSettings(Gtk.Grid):
|
||||
self._profiles_combo.set_active(new_pos)
|
||||
|
||||
def _on_connect_button_clicked(self, *args):
|
||||
self._settings.set_int("active-profile", self._profiles_combo.get_active())
|
||||
self._client.reconnect()
|
||||
selected=self._profiles_combo.get_selected()
|
||||
if selected == self._settings.get_int("active-profile"):
|
||||
self._client.reconnect()
|
||||
else:
|
||||
self._settings.set_int("active-profile", selected)
|
||||
|
||||
def _on_profile_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
pos=self._profiles_combo.get_active()
|
||||
self._settings.array_modify("as", "profiles", pos, self._profile_entry.get_text())
|
||||
self._profiles_combo_reload()
|
||||
self._profiles_combo.handler_block(self._profiles_changed) # do not reload all settings
|
||||
self._profiles_combo.set_active(pos)
|
||||
self._profiles_combo.handler_unblock(self._profiles_changed)
|
||||
self._settings.array_modify("as", "profiles", self._profiles_combo.get_selected(), self._profiles_combo.get_text())
|
||||
|
||||
def _on_host_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
self._settings.array_modify("as", "hosts", self._profiles_combo.get_active(), self._host_entry.get_text())
|
||||
self._settings.array_modify("as", "hosts", self._profiles_combo.get_selected(), self._host_entry.get_text())
|
||||
|
||||
def _on_port_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
self._settings.array_modify("ai", "ports", self._profiles_combo.get_active(), int(self._port_entry.get_value()))
|
||||
self._settings.array_modify("ai", "ports", self._profiles_combo.get_selected(), int(self._port_entry.get_value()))
|
||||
|
||||
def _on_password_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
self._settings.array_modify("as", "passwords", self._profiles_combo.get_active(), self._password_entry.get_text())
|
||||
self._settings.array_modify("as", "passwords", self._profiles_combo.get_selected(), self._password_entry.get_text())
|
||||
|
||||
def _on_path_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
self._settings.array_modify("as", "paths", self._profiles_combo.get_active(), self._path_entry.get_text())
|
||||
self._settings.array_modify("as", "paths", self._profiles_combo.get_selected(), self._path_entry.get_text())
|
||||
|
||||
def _on_regex_entry_changed(self, *args):
|
||||
self._gui_modification=True
|
||||
self._settings.array_modify("as", "regex", self._profiles_combo.get_active(), self._regex_entry.get_text())
|
||||
self._settings.array_modify("as", "regex", self._profiles_combo.get_selected(), self._regex_entry.get_text())
|
||||
|
||||
def _on_path_select_button_clicked(self, widget, parent):
|
||||
def _on_path_entry_icon_release(self, widget, icon_pos, event, parent):
|
||||
dialog=Gtk.FileChooserNative(title=_("Choose directory"), transient_for=parent, action=Gtk.FileChooserAction.SELECT_FOLDER)
|
||||
folder=self._settings.get_lib_path(self._profiles_combo.get_active())
|
||||
folder=self._settings.get_lib_path(self._profiles_combo.get_selected())
|
||||
if folder is not None:
|
||||
dialog.set_current_folder(folder)
|
||||
response=dialog.run()
|
||||
if response == Gtk.ResponseType.ACCEPT:
|
||||
self._gui_modification=True
|
||||
self._settings.array_modify("as", "paths", self._profiles_combo.get_active(), dialog.get_filename())
|
||||
self._settings.array_modify("as", "paths", self._profiles_combo.get_selected(), dialog.get_filename())
|
||||
self._path_entry.set_text(dialog.get_filename())
|
||||
dialog.destroy()
|
||||
|
||||
def _on_profiles_changed(self, *args):
|
||||
def _on_profiles_select(self, *args):
|
||||
active=self._profiles_combo.get_active()
|
||||
if active >= 0:
|
||||
self._block_entry_changed_handlers()
|
||||
self._profile_entry.set_text(self._settings.get_value("profiles")[active])
|
||||
self._host_entry.set_text(self._settings.get_value("hosts")[active])
|
||||
self._port_entry.set_value(self._settings.get_value("ports")[active])
|
||||
self._password_entry.set_text(self._settings.get_value("passwords")[active])
|
||||
@@ -1282,10 +1211,6 @@ class PlaylistSettings(Gtk.Box):
|
||||
self._up_button.connect("clicked", self._on_up_button_clicked)
|
||||
self._down_button.connect("clicked", self._on_down_button_clicked)
|
||||
self._selection.connect("changed", self._set_button_sensitivity)
|
||||
self._settings_handlers=[]
|
||||
self._settings_handlers.append(self._settings.connect("changed::column-visibilities", self._on_visibilities_changed))
|
||||
self._settings_handlers.append(self._settings.connect("changed::column-permutation", self._on_permutation_changed))
|
||||
self.connect("destroy", self._remove_handlers)
|
||||
|
||||
# packing
|
||||
self.pack_start(label, False, False, 0)
|
||||
@@ -1319,10 +1244,6 @@ class PlaylistSettings(Gtk.Box):
|
||||
self._up_button.set_sensitive(True)
|
||||
self._down_button.set_sensitive(True)
|
||||
|
||||
def _remove_handlers(self, *args):
|
||||
for handler in self._settings_handlers:
|
||||
self._settings.disconnect(handler)
|
||||
|
||||
def _on_cell_toggled(self, widget, path):
|
||||
self._store[path][0]=not self._store[path][0]
|
||||
self._settings.array_modify("ab", "column-visibilities", self._store[path][2], self._store[path][0])
|
||||
@@ -1344,26 +1265,8 @@ class PlaylistSettings(Gtk.Box):
|
||||
self._set_button_sensitivity()
|
||||
self._save_permutation()
|
||||
|
||||
def _on_visibilities_changed(self, *args):
|
||||
visibilities=self._settings.get_value("column-visibilities").unpack()
|
||||
for i, actual_index in enumerate(self._settings.get_value("column-permutation")):
|
||||
self._store[i][0]=visibilities[actual_index]
|
||||
|
||||
def _on_permutation_changed(self, *args):
|
||||
equal=True
|
||||
perm=self._settings.get_value("column-permutation")
|
||||
for i, e in enumerate(self._store):
|
||||
if e[2] != perm[i]:
|
||||
equal=False
|
||||
break
|
||||
if not equal:
|
||||
self._store.handler_block(self._row_deleted)
|
||||
self._store.clear()
|
||||
self._fill()
|
||||
self._store.handler_unblock(self._row_deleted)
|
||||
|
||||
class SettingsDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, client, settings):
|
||||
def __init__(self, parent, client, settings, tab="general"):
|
||||
use_csd=settings.get_boolean("use-csd")
|
||||
if use_csd:
|
||||
super().__init__(title=_("Settings"), transient_for=parent, use_header_bar=True)
|
||||
@@ -1397,6 +1300,10 @@ class SettingsDialog(Gtk.Dialog):
|
||||
vbox.set_property("border-width", 6)
|
||||
vbox.pack_start(tabs, True, True, 0)
|
||||
self.show_all()
|
||||
if use_csd:
|
||||
stack.set_visible_child_name(tab)
|
||||
else:
|
||||
tabs.set_current_page({"general": 0, "profiles": 1, "playlist": 2}[tab])
|
||||
|
||||
#################
|
||||
# other dialogs #
|
||||
@@ -1490,6 +1397,35 @@ class PasswordEntry(Gtk.Entry):
|
||||
self.set_visibility(False)
|
||||
self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "view-conceal-symbolic")
|
||||
|
||||
class ComboBoxEntry(Gtk.ComboBoxText):
|
||||
__gsignals__={"text": (GObject.SignalFlags.RUN_FIRST, None, ()), "select": (GObject.SignalFlags.RUN_FIRST, None, ())}
|
||||
def __init__(self):
|
||||
super().__init__(entry_text_column=0, has_entry=True)
|
||||
self._store=self.get_property("model")
|
||||
self._entry=self.get_child()
|
||||
self._selected=-1
|
||||
|
||||
# connect
|
||||
self.connect("changed", self._on_changed)
|
||||
|
||||
def get_text(self):
|
||||
return self._entry.get_text()
|
||||
|
||||
def get_selected(self):
|
||||
return self._selected
|
||||
|
||||
def _on_changed(self, *args):
|
||||
active=self.get_active()
|
||||
if active >= 0:
|
||||
self._selected=active
|
||||
self.emit("select")
|
||||
else:
|
||||
try:
|
||||
self._store[self._selected][0]=self._entry.get_text()
|
||||
self.emit("text")
|
||||
except:
|
||||
pass
|
||||
|
||||
class FocusFrame(Gtk.Overlay):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -1840,13 +1776,12 @@ class ArtistPopover(Gtk.Popover):
|
||||
|
||||
# buttons
|
||||
vbox=Gtk.ButtonBox(orientation=Gtk.Orientation.VERTICAL, border_width=9)
|
||||
data=((_("Append"), _("Add all titles to playlist"), "list-add-symbolic", "append"),
|
||||
(_("Play"), _("Directly play all titles"), "media-playback-start-symbolic", "play"),
|
||||
(_("Enqueue"), _("Append all titles after the currently playing track and clear the playlist from all other songs"),
|
||||
"insert-object-symbolic", "enqueue")
|
||||
data=((_("Append"), "list-add-symbolic", "append"),
|
||||
(_("Play"), "media-playback-start-symbolic", "play"),
|
||||
(_("Enqueue"), "insert-object-symbolic", "enqueue")
|
||||
)
|
||||
for label, tooltip, icon, mode in data:
|
||||
button=Gtk.ModelButton(label=label, tooltip_text=tooltip, image=Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON))
|
||||
for label, icon, mode in data:
|
||||
button=Gtk.ModelButton(label=label, image=Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON))
|
||||
button.get_child().set_property("xalign", 0)
|
||||
button.connect("clicked", self._on_button_clicked, mode)
|
||||
vbox.pack_start(button, True, True, 0)
|
||||
@@ -1943,6 +1878,8 @@ class SearchWindow(Gtk.Box):
|
||||
|
||||
# connect
|
||||
self._search_entry_changed=self.search_entry.connect("search-changed", self._search)
|
||||
self.search_entry.connect("focus_in_event", self._on_search_entry_focus_event, True)
|
||||
self.search_entry.connect("focus_out_event", self._on_search_entry_focus_event, False)
|
||||
self._tag_combo_box_changed=self._tag_combo_box.connect("changed", self._search)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
@@ -2042,6 +1979,13 @@ class SearchWindow(Gtk.Box):
|
||||
pass
|
||||
return False
|
||||
|
||||
def _on_search_entry_focus_event(self, widget, event, focus):
|
||||
app=self.get_toplevel().get_application()
|
||||
if focus:
|
||||
app.set_accels_for_action("mpd.toggle-play", [])
|
||||
else:
|
||||
app.set_accels_for_action("mpd.toggle-play", ["space"])
|
||||
|
||||
class GenreSelect(Gtk.ComboBoxText):
|
||||
__gsignals__={"genre_changed": (GObject.SignalFlags.RUN_FIRST, None, ())}
|
||||
def __init__(self, client):
|
||||
@@ -2531,7 +2475,6 @@ class AlbumWindow(FocusFrame):
|
||||
GLib.idle_add(callback)
|
||||
|
||||
class Browser(Gtk.Paned):
|
||||
__gsignals__={"search-focus-changed": (GObject.SignalFlags.RUN_FIRST, None, (bool,))}
|
||||
def __init__(self, client, settings):
|
||||
super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
self._client=client
|
||||
@@ -2558,10 +2501,9 @@ class Browser(Gtk.Paned):
|
||||
self._album_window=AlbumWindow(self._client, self._settings, self._artist_window)
|
||||
|
||||
# connect
|
||||
self.back_to_current_album_button.connect("clicked", self._back_to_current_album)
|
||||
self.back_to_current_album_button.connect("clicked", self._on_back_to_current_album_button_clicked)
|
||||
self.back_to_current_album_button.connect("button-press-event", self._on_back_to_current_album_button_press_event)
|
||||
self.search_button.connect("toggled", self._on_search_toggled)
|
||||
self._search_window.search_entry.connect("focus_in_event", lambda *args: self.emit("search-focus-changed", True))
|
||||
self._search_window.search_entry.connect("focus_out_event", lambda *args: self.emit("search-focus-changed", False))
|
||||
self._artist_window.connect("artists_changed", self._on_artists_changed)
|
||||
self._settings.connect("notify::mini-player", self._on_mini_player)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
@@ -2585,7 +2527,7 @@ class Browser(Gtk.Paned):
|
||||
self.pack1(box1, False, False)
|
||||
self.pack2(self._stack, True, False)
|
||||
|
||||
def _back_to_current_album(self, *args):
|
||||
def _back_to_current_album(self, force=False):
|
||||
song=ClientHelper.song_to_first_str_dict(self._client.currentsong())
|
||||
if song != {}:
|
||||
self.search_button.set_active(False)
|
||||
@@ -2594,16 +2536,23 @@ class Browser(Gtk.Paned):
|
||||
if artist is None:
|
||||
artist=song.get("artist", "")
|
||||
# deactivate genre filter to show all artists (if needed)
|
||||
if song.get("genre", "") != self._genre_select.get_selected_genre():
|
||||
if song.get("genre", "") != self._genre_select.get_selected_genre() or force:
|
||||
self._genre_select.deactivate()
|
||||
# select artist
|
||||
if self._artist_window.get_selected_artist() is None: # all artists selected
|
||||
if self._artist_window.get_selected_artist() is None and not force: # all artists selected
|
||||
self.search_button.set_active(False)
|
||||
self._artist_window.highlight_selected()
|
||||
else: # one artist selected
|
||||
self._artist_window.select(artist)
|
||||
self._album_window.scroll_to_current_album()
|
||||
|
||||
def _on_back_to_current_album_button_clicked(self, *args):
|
||||
self._back_to_current_album()
|
||||
|
||||
def _on_back_to_current_album_button_press_event(self, widget, event):
|
||||
if event.button == 1 and event.type == Gdk.EventType._2BUTTON_PRESS:
|
||||
self._back_to_current_album(force=True)
|
||||
|
||||
def _on_search_toggled(self, widget):
|
||||
if widget.get_active():
|
||||
self._stack.set_visible_child_name("search")
|
||||
@@ -2879,18 +2828,19 @@ class PlaylistWindow(Gtk.Box):
|
||||
self._back_to_current_song_button=Gtk.Button(
|
||||
image=AutoSizedIcon("go-previous-symbolic", "icon-size-sec", self._settings),
|
||||
tooltip_text=_("Scroll to current song"),
|
||||
relief=Gtk.ReliefStyle.NONE
|
||||
relief=Gtk.ReliefStyle.NONE,
|
||||
can_focus=False
|
||||
)
|
||||
self._back_to_current_song_button.set_can_focus(False)
|
||||
style_context=self._back_to_current_song_button.get_style_context()
|
||||
style_context.add_provider(provider, 600)
|
||||
self._clear_button=Gtk.Button(
|
||||
clear_button=Gtk.Button(
|
||||
image=AutoSizedIcon("edit-clear-symbolic", "icon-size-sec", self._settings),
|
||||
tooltip_text=_("Clear playlist"),
|
||||
relief=Gtk.ReliefStyle.NONE
|
||||
relief=Gtk.ReliefStyle.NONE,
|
||||
action_name="mpd.clear",
|
||||
can_focus=False
|
||||
)
|
||||
self._clear_button.set_can_focus(False)
|
||||
style_context=self._clear_button.get_style_context()
|
||||
style_context=clear_button.get_style_context()
|
||||
style_context.add_class("destructive-action")
|
||||
style_context.add_provider(provider, 600)
|
||||
|
||||
@@ -2945,7 +2895,7 @@ class PlaylistWindow(Gtk.Box):
|
||||
action_bar.pack_start(self._playlist_info)
|
||||
audio.set_margin_end(3)
|
||||
audio.set_margin_start(12)
|
||||
action_bar.pack_end(self._clear_button)
|
||||
action_bar.pack_end(clear_button)
|
||||
action_bar.pack_end(audio)
|
||||
|
||||
# song popover
|
||||
@@ -2960,7 +2910,6 @@ class PlaylistWindow(Gtk.Box):
|
||||
self._row_deleted=self._store.connect("row-deleted", self._on_row_deleted)
|
||||
self._row_inserted=self._store.connect("row-inserted", self._on_row_inserted)
|
||||
self._back_to_current_song_button.connect("clicked", self._on_back_to_current_song_button_clicked)
|
||||
self._clear_button.connect("clicked", self._on_clear_button_clicked)
|
||||
|
||||
self._client.emitter.connect("playlist_changed", self._on_playlist_changed)
|
||||
self._client.emitter.connect("current_song_changed", self._on_song_changed)
|
||||
@@ -3127,19 +3076,14 @@ class PlaylistWindow(Gtk.Box):
|
||||
break
|
||||
self._scroll_to_selected_title()
|
||||
|
||||
def _on_clear_button_clicked(self, *args):
|
||||
self._client.clear()
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self._treeview.set_sensitive(False)
|
||||
self._back_to_current_song_button.set_sensitive(False)
|
||||
self._clear_button.set_sensitive(False)
|
||||
self._song_popover.popdown()
|
||||
self._clear()
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self._back_to_current_song_button.set_sensitive(True)
|
||||
self._clear_button.set_sensitive(True)
|
||||
self._treeview.set_sensitive(True)
|
||||
|
||||
def _on_show_info(self, *args):
|
||||
@@ -3247,27 +3191,26 @@ class PlaybackControl(Gtk.ButtonBox):
|
||||
self._play_icon=AutoSizedIcon("media-playback-start-symbolic", "icon-size", self._settings)
|
||||
self._pause_icon=AutoSizedIcon("media-playback-pause-symbolic", "icon-size", self._settings)
|
||||
self._play_button=Gtk.Button(image=self._play_icon)
|
||||
self._play_button.set_action_name("mpd.toggle-play")
|
||||
self._play_button.set_can_focus(False)
|
||||
self._stop_button=Gtk.Button(image=AutoSizedIcon("media-playback-stop-symbolic", "icon-size", self._settings))
|
||||
self._stop_button.set_property("no-show-all", not(self._settings.get_boolean("show-stop")))
|
||||
self._stop_button.set_action_name("mpd.stop")
|
||||
self._stop_button.set_can_focus(False)
|
||||
self._prev_button=Gtk.Button(image=AutoSizedIcon("media-skip-backward-symbolic", "icon-size", self._settings))
|
||||
self._prev_button.set_action_name("mpd.prev")
|
||||
self._prev_button.set_can_focus(False)
|
||||
self._next_button=Gtk.Button(image=AutoSizedIcon("media-skip-forward-symbolic", "icon-size", self._settings))
|
||||
self._next_button.set_action_name("mpd.next")
|
||||
self._next_button.set_can_focus(False)
|
||||
|
||||
# connect
|
||||
self._play_button.connect("clicked", self._on_play_clicked)
|
||||
self._stop_button.connect("clicked", self._on_stop_clicked)
|
||||
self._stop_button.set_property("no-show-all", not(self._settings.get_boolean("show-stop")))
|
||||
self._prev_button.connect("clicked", self._on_prev_clicked)
|
||||
self._next_button.connect("clicked", self._on_next_clicked)
|
||||
self._settings.connect("notify::mini-player", self._on_mini_player)
|
||||
self._settings.connect("changed::show-stop", self._on_show_stop_changed)
|
||||
self._client.emitter.connect("state", self._on_state)
|
||||
self._client.emitter.connect("playlist_changed", self._refresh_tooltips)
|
||||
self._client.emitter.connect("current_song_changed", self._refresh_tooltips)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
|
||||
# packing
|
||||
self.pack_start(self._prev_button, True, True, 0)
|
||||
@@ -3289,40 +3232,18 @@ class PlaybackControl(Gtk.ButtonBox):
|
||||
self._prev_button.set_tooltip_text("")
|
||||
self._next_button.set_tooltip_text("")
|
||||
|
||||
def _on_play_clicked(self, widget):
|
||||
self._client.toggle_play()
|
||||
|
||||
def _on_stop_clicked(self, widget):
|
||||
self._client.stop()
|
||||
|
||||
def _on_prev_clicked(self, widget):
|
||||
self._client.previous()
|
||||
|
||||
def _on_next_clicked(self, widget):
|
||||
self._client.next()
|
||||
|
||||
def _on_state(self, emitter, state):
|
||||
if state == "play":
|
||||
self._play_button.set_image(self._pause_icon)
|
||||
self._prev_button.set_sensitive(True)
|
||||
self._next_button.set_sensitive(True)
|
||||
elif state == "pause":
|
||||
self._play_button.set_image(self._play_icon)
|
||||
self._prev_button.set_sensitive(True)
|
||||
self._next_button.set_sensitive(True)
|
||||
else:
|
||||
self._play_button.set_image(self._play_icon)
|
||||
self._prev_button.set_sensitive(False)
|
||||
self._next_button.set_sensitive(False)
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self.set_sensitive(False)
|
||||
self._prev_button.set_tooltip_text("")
|
||||
self._next_button.set_tooltip_text("")
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self.set_sensitive(True)
|
||||
|
||||
def _on_mini_player(self, obj, typestring):
|
||||
self._on_show_stop_changed()
|
||||
|
||||
@@ -3453,77 +3374,112 @@ class OutputPopover(Gtk.Popover):
|
||||
self._client=client
|
||||
|
||||
# widgets
|
||||
box=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6, border_width=6)
|
||||
box=Gtk.Box(orientation=Gtk.Orientation.VERTICAL, border_width=9)
|
||||
for output in self._client.outputs():
|
||||
button=Gtk.CheckButton(label="{} ({})".format(output["outputname"], output["plugin"]))
|
||||
button=Gtk.ModelButton(label="{} ({})".format(output["outputname"], output["plugin"]), role=Gtk.ButtonRole.CHECK)
|
||||
button.get_child().set_property("xalign", 0)
|
||||
if output["outputenabled"] == "1":
|
||||
button.set_active(True)
|
||||
button.connect("toggled", self._on_button_toggled, output["outputid"])
|
||||
button.set_property("active", True)
|
||||
button.connect("clicked", self._on_button_clicked, output["outputid"])
|
||||
box.pack_start(button, False, False, 0)
|
||||
|
||||
#connect
|
||||
self.connect("closed", lambda *args: self.destroy())
|
||||
|
||||
# packing
|
||||
self.add(box)
|
||||
box.show_all()
|
||||
|
||||
def _on_button_toggled(self, button, out_id):
|
||||
if button.get_active():
|
||||
self._client.enableoutput(out_id)
|
||||
else:
|
||||
def _on_button_clicked(self, button, out_id):
|
||||
if button.get_property("active"):
|
||||
self._client.disableoutput(out_id)
|
||||
button.set_property("active", False)
|
||||
else:
|
||||
self._client.enableoutput(out_id)
|
||||
button.set_property("active", True)
|
||||
|
||||
class PlaybackOptions(Gtk.Box):
|
||||
class VolumeButton(Gtk.VolumeButton):
|
||||
def __init__(self, client, settings):
|
||||
super().__init__(spacing=6)
|
||||
super().__init__(use_symbolic=True, size=settings.get_gtk_icon_size("icon-size"), can_focus=False)
|
||||
self._client=client
|
||||
self._settings=settings
|
||||
self._popover=None
|
||||
|
||||
# widgets
|
||||
icons={}
|
||||
for icon_name in ("media-playlist-shuffle-symbolic","media-playlist-repeat-symbolic",
|
||||
"org.mpdevil.mpdevil-single-symbolic","org.mpdevil.mpdevil-consume-symbolic"):
|
||||
icons[icon_name]=AutoSizedIcon(icon_name, "icon-size", self._settings)
|
||||
self._random_button=Gtk.ToggleButton(image=icons["media-playlist-shuffle-symbolic"], tooltip_text=_("Random mode"))
|
||||
self._random_button.set_can_focus(False)
|
||||
self._repeat_button=Gtk.ToggleButton(image=icons["media-playlist-repeat-symbolic"], tooltip_text=_("Repeat mode"))
|
||||
self._repeat_button.set_can_focus(False)
|
||||
self._single_button=Gtk.ToggleButton(image=icons["org.mpdevil.mpdevil-single-symbolic"], tooltip_text=_("Single mode"))
|
||||
self._single_button.set_can_focus(False)
|
||||
self._consume_button=Gtk.ToggleButton(image=icons["org.mpdevil.mpdevil-consume-symbolic"], tooltip_text=_("Consume mode"))
|
||||
self._consume_button.set_can_focus(False)
|
||||
self._volume_button=Gtk.VolumeButton(use_symbolic=True, size=self._settings.get_gtk_icon_size("icon-size"))
|
||||
self._volume_button.set_can_focus(False)
|
||||
self._adj=self._volume_button.get_adjustment()
|
||||
self._adj=self.get_adjustment()
|
||||
self._adj.set_step_increment(0.05)
|
||||
self._adj.set_page_increment(0.1)
|
||||
self._adj.set_upper(0) # do not allow volume change by user when MPD has not yet reported volume (no output enabled/avail)
|
||||
|
||||
# connect
|
||||
self._random_button_toggled=self._random_button.connect("toggled", self._set_option, "random")
|
||||
self._repeat_button_toggled=self._repeat_button.connect("toggled", self._set_option, "repeat")
|
||||
self._single_button_toggled=self._single_button.connect("toggled", self._set_option, "single")
|
||||
self._consume_button_toggled=self._consume_button.connect("toggled", self._set_option, "consume")
|
||||
self._volume_button_changed=self._volume_button.connect("value-changed", self._set_volume)
|
||||
self._repeat_changed=self._client.emitter.connect("repeat", self._repeat_refresh)
|
||||
self._random_changed=self._client.emitter.connect("random", self._random_refresh)
|
||||
self._single_changed=self._client.emitter.connect("single", self._single_refresh)
|
||||
self._consume_changed=self._client.emitter.connect("consume", self._consume_refresh)
|
||||
self._volume_changed=self._client.emitter.connect("volume_changed", self._volume_refresh)
|
||||
self._single_button.connect("button-press-event", self._on_single_button_press_event)
|
||||
self._volume_button.connect("button-press-event", self._on_volume_button_press_event)
|
||||
self._changed=self.connect("value-changed", self._set_volume)
|
||||
self._client.emitter.connect("volume_changed", self._refresh)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
self.connect("button-press-event", self._on_button_press_event)
|
||||
self._settings.connect("changed::icon-size", self._on_icon_size_changed)
|
||||
|
||||
def _set_volume(self, widget, value):
|
||||
self._client.setvol(str(int(value*100)))
|
||||
|
||||
def _refresh(self, emitter, volume):
|
||||
self.handler_block(self._changed)
|
||||
if volume < 0:
|
||||
self.set_value(0)
|
||||
self._adj.set_upper(0)
|
||||
else:
|
||||
self._adj.set_upper(1)
|
||||
self.set_value(volume/100)
|
||||
self.handler_unblock(self._changed)
|
||||
|
||||
def _on_button_press_event(self, widget, event):
|
||||
if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
self._popover=OutputPopover(self._client, self)
|
||||
self._popover.popup()
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self.set_sensitive(True)
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self.set_sensitive(False)
|
||||
self._refresh(None, -1)
|
||||
if self._popover is not None:
|
||||
self._popover.popdown()
|
||||
self._popover=None
|
||||
|
||||
def _on_icon_size_changed(self, *args):
|
||||
self.set_property("size", self._settings.get_gtk_icon_size("icon-size"))
|
||||
|
||||
class PlaybackOptions(Gtk.ButtonBox):
|
||||
def __init__(self, client, settings):
|
||||
super().__init__(layout_style=Gtk.ButtonBoxStyle.EXPAND)
|
||||
self._client=client
|
||||
self._settings=settings
|
||||
|
||||
# buttons
|
||||
self._buttons={}
|
||||
data=(
|
||||
("repeat", "media-playlist-repeat-symbolic", _("Repeat mode")),
|
||||
("random", "media-playlist-shuffle-symbolic", _("Random mode")),
|
||||
("single", "org.mpdevil.mpdevil-single-symbolic", _("Single mode")),
|
||||
("consume", "org.mpdevil.mpdevil-consume-symbolic", _("Consume mode")),
|
||||
)
|
||||
for name, icon, tooltip in data:
|
||||
button=Gtk.ToggleButton(image=AutoSizedIcon(icon, "icon-size", self._settings), tooltip_text=tooltip, can_focus=False)
|
||||
handler=button.connect("toggled", self._set_option, name)
|
||||
self.pack_start(button, True, True, 0)
|
||||
self._buttons[name]=(button, handler)
|
||||
|
||||
# css
|
||||
self._provider=Gtk.CssProvider()
|
||||
self._provider.load_from_data(b"""image {color: @error_color;}""") # red icon
|
||||
|
||||
# connect
|
||||
for name in ("repeat", "random", "consume"):
|
||||
self._client.emitter.connect(name, self._button_refresh, name)
|
||||
self._client.emitter.connect("single", self._single_refresh)
|
||||
self._buttons["single"][0].connect("button-press-event", self._on_single_button_press_event)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
self._settings.connect("notify::mini-player", self._on_mini_player)
|
||||
self._settings.connect("changed::icon-size", self._on_icon_size_changed)
|
||||
|
||||
# packing
|
||||
self._button_box=Gtk.ButtonBox(layout_style=Gtk.ButtonBoxStyle.EXPAND)
|
||||
self._button_box.pack_start(self._repeat_button, True, True, 0)
|
||||
self._button_box.pack_start(self._random_button, True, True, 0)
|
||||
self._button_box.pack_start(self._single_button, True, True, 0)
|
||||
self._button_box.pack_start(self._consume_button, True, True, 0)
|
||||
self.pack_start(self._button_box, True, True, 0)
|
||||
self.pack_start(self._volume_button, True, True, 0)
|
||||
|
||||
def _set_option(self, widget, option):
|
||||
func=getattr(self._client, option)
|
||||
@@ -3532,51 +3488,19 @@ class PlaybackOptions(Gtk.Box):
|
||||
else:
|
||||
func("0")
|
||||
|
||||
def _set_volume(self, widget, value):
|
||||
self._client.setvol(str(int(value*100)))
|
||||
|
||||
def _repeat_refresh(self, emitter, val):
|
||||
self._repeat_button.handler_block(self._repeat_button_toggled)
|
||||
self._repeat_button.set_active(val)
|
||||
self._repeat_button.handler_unblock(self._repeat_button_toggled)
|
||||
|
||||
def _random_refresh(self, emitter, val):
|
||||
self._random_button.handler_block(self._random_button_toggled)
|
||||
self._random_button.set_active(val)
|
||||
self._random_button.handler_unblock(self._random_button_toggled)
|
||||
def _button_refresh(self, emitter, val, name):
|
||||
self._buttons[name][0].handler_block(self._buttons[name][1])
|
||||
self._buttons[name][0].set_active(val)
|
||||
self._buttons[name][0].handler_unblock(self._buttons[name][1])
|
||||
|
||||
def _single_refresh(self, emitter, val):
|
||||
self._single_button.handler_block(self._single_button_toggled)
|
||||
if val == "1":
|
||||
self._single_button.get_style_context().remove_class("destructive-action")
|
||||
self._single_button.set_active(True)
|
||||
elif val == "oneshot":
|
||||
self._single_button.get_style_context().add_class("destructive-action")
|
||||
self._single_button.set_active(False)
|
||||
self._buttons["single"][0].handler_block(self._buttons["single"][1])
|
||||
self._buttons["single"][0].set_active((val in ("1", "oneshot")))
|
||||
if val == "oneshot":
|
||||
self._buttons["single"][0].get_image().get_style_context().add_provider(self._provider, 600)
|
||||
else:
|
||||
self._single_button.get_style_context().remove_class("destructive-action")
|
||||
self._single_button.set_active(False)
|
||||
self._single_button.handler_unblock(self._single_button_toggled)
|
||||
|
||||
def _consume_refresh(self, emitter, val):
|
||||
self._consume_button.handler_block(self._consume_button_toggled)
|
||||
self._consume_button.set_active(val)
|
||||
self._consume_button.handler_unblock(self._consume_button_toggled)
|
||||
|
||||
def _volume_refresh(self, emitter, volume):
|
||||
self._volume_button.handler_block(self._volume_button_changed)
|
||||
if volume < 0:
|
||||
self._volume_button.set_value(0)
|
||||
self._adj.set_upper(0)
|
||||
else:
|
||||
self._adj.set_upper(1)
|
||||
self._volume_button.set_value(volume/100)
|
||||
self._volume_button.handler_unblock(self._volume_button_changed)
|
||||
|
||||
def _on_volume_button_press_event(self, widget, event):
|
||||
if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
self._popover=OutputPopover(self._client, self._volume_button)
|
||||
self._popover.popup()
|
||||
self._buttons["single"][0].get_image().get_style_context().remove_provider(self._provider)
|
||||
self._buttons["single"][0].handler_unblock(self._buttons["single"][1])
|
||||
|
||||
def _on_single_button_press_event(self, widget, event):
|
||||
if event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
@@ -3586,38 +3510,22 @@ class PlaybackOptions(Gtk.Box):
|
||||
else:
|
||||
self._client.single("oneshot")
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self._repeat_button.set_sensitive(True)
|
||||
self._random_button.set_sensitive(True)
|
||||
self._single_button.set_sensitive(True)
|
||||
self._consume_button.set_sensitive(True)
|
||||
self._volume_button.set_sensitive(True)
|
||||
|
||||
def _on_disconnected(self, *args):
|
||||
self._repeat_button.set_sensitive(False)
|
||||
self._random_button.set_sensitive(False)
|
||||
self._single_button.set_sensitive(False)
|
||||
self._consume_button.set_sensitive(False)
|
||||
self._volume_button.set_sensitive(False)
|
||||
self._repeat_refresh(None, False)
|
||||
self._random_refresh(None, False)
|
||||
self.set_sensitive(False)
|
||||
for name in ("repeat", "random", "consume"):
|
||||
self._button_refresh(None, False, name)
|
||||
self._single_refresh(None, "0")
|
||||
self._consume_refresh(None, False)
|
||||
self._volume_refresh(None, -1)
|
||||
if self._popover is not None:
|
||||
self._popover.destroy()
|
||||
self._popover=None
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
self.set_sensitive(True)
|
||||
|
||||
def _on_mini_player(self, obj, typestring):
|
||||
if obj.get_property("mini-player"):
|
||||
self._button_box.set_property("no-show-all", True)
|
||||
self._button_box.set_property("visible", False)
|
||||
self.set_property("no-show-all", True)
|
||||
self.set_property("visible", False)
|
||||
else:
|
||||
self._button_box.set_property("no-show-all", False)
|
||||
self._button_box.show_all()
|
||||
|
||||
def _on_icon_size_changed(self, *args):
|
||||
self._volume_button.set_property("size", self._settings.get_gtk_icon_size("icon-size"))
|
||||
self.set_property("no-show-all", False)
|
||||
self.show_all()
|
||||
|
||||
###################
|
||||
# MPD gio actions #
|
||||
@@ -3760,6 +3668,8 @@ class ConnectionNotify(Gtk.Revealer):
|
||||
close_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("window-close-symbolic", Gtk.IconSize.BUTTON))
|
||||
close_button.set_relief(Gtk.ReliefStyle.NONE)
|
||||
connect_button=Gtk.Button(label=_("Connect"))
|
||||
settings_button=Gtk.Button(label=_("Settings"))
|
||||
settings_button.set_action_name("win.profile-settings")
|
||||
|
||||
# connect
|
||||
close_button.connect("clicked", self._on_close_button_clicked)
|
||||
@@ -3773,6 +3683,7 @@ class ConnectionNotify(Gtk.Revealer):
|
||||
box.pack_start(self._label, False, True, 6)
|
||||
box.pack_end(close_button, False, True, 0)
|
||||
box.pack_end(connect_button, False, True, 0)
|
||||
box.pack_end(settings_button, False, True, 0)
|
||||
self.add(box)
|
||||
|
||||
def _on_connection_error(self, *args):
|
||||
@@ -3813,7 +3724,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
|
||||
# actions
|
||||
simple_actions_data=(
|
||||
"settings","stats","help","menu",
|
||||
"settings","profile-settings","stats","help","menu",
|
||||
"toggle-lyrics","back-to-current-album","toggle-search",
|
||||
"profile-next","profile-prev","show-info","append","play","enqueue"
|
||||
)
|
||||
@@ -3826,8 +3737,6 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self._profiles_action=Gio.SimpleAction.new_stateful("profiles", GLib.VariantType.new("i"), GLib.Variant("i", 0))
|
||||
self._profiles_action.connect("change-state", self._on_profiles)
|
||||
self.add_action(self._profiles_action)
|
||||
self._mpd_action_group=MPDActionGroup(self._client)
|
||||
self.insert_action_group("mpd", self._mpd_action_group)
|
||||
|
||||
# shortcuts
|
||||
shortcuts_window=ShortcutsWindow()
|
||||
@@ -3846,6 +3755,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
playback_control=PlaybackControl(self._client, self._settings)
|
||||
seek_bar=SeekBar(self._client)
|
||||
playback_options=PlaybackOptions(self._client, self._settings)
|
||||
volume_button=VolumeButton(self._client, self._settings)
|
||||
connection_notify=ConnectionNotify(self._client, self._settings)
|
||||
|
||||
# menu
|
||||
@@ -3877,6 +3787,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
action_bar.pack_start(playback_control)
|
||||
action_bar.pack_start(seek_bar)
|
||||
action_bar.pack_start(playback_options)
|
||||
action_bar.pack_start(volume_button)
|
||||
|
||||
# connect
|
||||
self._settings.connect("changed::profiles", self._refresh_profiles_menu)
|
||||
@@ -3887,7 +3798,6 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
self._client.emitter.connect("current_song_changed", self._on_song_changed)
|
||||
self._client.emitter.connect("disconnected", self._on_disconnected)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
self._browser.connect("search-focus-changed", self._on_search_focus_changed)
|
||||
# auto save window state and size
|
||||
self.connect("size-allocate", self._on_size_allocate)
|
||||
self._settings.bind("maximize", self, "is-maximized", Gio.SettingsBindFlags.SET)
|
||||
@@ -3953,6 +3863,11 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
settings.run()
|
||||
settings.destroy()
|
||||
|
||||
def _on_profile_settings(self, action, param):
|
||||
settings=SettingsDialog(self, self._client, self._settings, "profiles")
|
||||
settings.run()
|
||||
settings.destroy()
|
||||
|
||||
def _on_stats(self, action, param):
|
||||
stats=ServerStats(self, self._client, self._settings)
|
||||
stats.destroy()
|
||||
@@ -4026,9 +3941,6 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
for action in ("stats","toggle-lyrics","back-to-current-album","toggle-search"):
|
||||
self.lookup_action(action).set_enabled(False)
|
||||
|
||||
def _on_search_focus_changed(self, obj, focus):
|
||||
self._mpd_action_group.lookup_action("toggle-play").set_enabled(not(focus))
|
||||
|
||||
def _on_size_allocate(self, widget, rect):
|
||||
if not self.is_maximized() and not self._settings.get_property("mini-player"):
|
||||
size=self.get_size()
|
||||
@@ -4089,6 +4001,7 @@ class mpdevil(Gtk.Application):
|
||||
if not self._window: # allow just one instance
|
||||
self._window=MainWindow(self, self._client, self._settings)
|
||||
self._window.connect("delete-event", self._on_delete_event)
|
||||
self._window.insert_action_group("mpd", MPDActionGroup(self._client))
|
||||
# accelerators
|
||||
action_accels=(
|
||||
("app.quit", ["<Control>q"]),("win.mini-player", ["<Control>m"]),("win.help", ["F1"]),("win.menu", ["F10"]),
|
||||
|
@@ -23,7 +23,7 @@
|
||||
</ul>
|
||||
</description>
|
||||
<releases>
|
||||
<release version="1.2.0" date="2021-04-21"/>
|
||||
<release version="1.2.1" date="2021-05-04"/>
|
||||
</releases>
|
||||
<launchable type="desktop-id">org.mpdevil.mpdevil.desktop</launchable>
|
||||
<screenshots>
|
||||
|
2
setup.py
2
setup.py
@@ -4,7 +4,7 @@ import DistUtilsExtra.auto
|
||||
|
||||
DistUtilsExtra.auto.setup(
|
||||
name='mpdevil',
|
||||
version='1.2.0', # sync with bin/mpdevil
|
||||
version='1.2.1', # sync with bin/mpdevil
|
||||
author="Martin Wagner",
|
||||
author_email="martin.wagner.dev@gmail.com",
|
||||
description=('A simple music browser for MPD'),
|
||||
|
Reference in New Issue
Block a user