# Copyright 2021 (c) Anna Schumaker. from gi.repository import GObject from gi.repository import Gtk class UpDownBox(Gtk.Box): def __init__(self): Gtk.Box.__init__(self) self.append(Gtk.Button.new_from_icon_name("go-up-symbolic")) self.append(Gtk.Button.new_from_icon_name("go-down-symbolic")) self.add_css_class("linked") self.get_first_child().connect("clicked", self.clicked, "move-up") self.get_last_child().connect("clicked", self.clicked, "move-down") self.get_first_child().set_sensitive(False) self.get_last_child().set_sensitive(False) def set_active(self, active, first, last): self.get_first_child().set_sensitive(active and not first) self.get_last_child().set_sensitive(active and not last) def clicked(self, button, signal): self.emit(signal) @GObject.Signal def move_up(self): pass @GObject.Signal def move_down(self): pass class DirectionButton(Gtk.Button): def __init__(self): Gtk.Button.__init__(self, sensitive=False) self.set_icon_name("view-sort-ascending") def set_direction(self, direction, active): sort = "ascending" if direction == "ASC" else "descending" self.set_icon_name(f"view-sort-{sort}") self.set_sensitive(active) class FieldLabel(Gtk.Label): def __init__(self): Gtk.Label.__init__(self, sensitive=False, hexpand=True) def set_field(self, field, active): self.set_sensitive(active) self.set_text({ "tracks.number" : "Track Number", "tracks.title" : "Track Title", "tracks.length" : "Track Length", "artists.sort" : "Artist Name", "albums.sort" : "Album Name", "discs.subtitle" : "Disc Subtitle", "albums.release" : "Release Date", "tracks.playcount" : "Play Count", "tracks.lastplayed" : "Last Played", "playlist_map.rowid" : "Order Added"}.get(field, field)) def get_field(self): text = self.get_text() return { "Track Number" : "tracks.number", "Track Title" : "tracks.title", "Track Length" : "tracks.length", "Artist Name" : "artists.sort", "Album Name" : "albums.sort", "Disc Subtitle" : "discs.subtitle", "Release Date" : "albums.release", "Play Count" : "tracks.playcount", "Last Played" : "tracks.lastplayed", "Order Added" : "playlist_map.rowid"}.get(text, text) class SortRow(Gtk.Box): def __init__(self): Gtk.Box.__init__(self, spacing=5) self.switch = Gtk.Switch(valign=Gtk.Align.CENTER) self.label = FieldLabel() self.direction = DirectionButton() self.updown = UpDownBox() self.append(self.switch) self.append(self.label) self.append(self.direction) self.append(self.updown) self.switch.connect("notify::active", self.switch_active) self.direction.connect("clicked", self.reverse) self.updown.connect("move-up", self.moved_up) self.updown.connect("move-down", self.moved_down) def set_item(self, text, index, n_active): (field, direction) = text.split() self.switch.set_active(index < n_active) self.switch.set_sensitive("rowid" not in field) self.label.set_field(field, index < n_active) self.direction.set_direction(direction, index < n_active) self.updown.set_active(index < n_active, index == 0, index == n_active - 1) def switch_active(self, switch, param): self.emit("switched", switch.get_active()) def reverse(self, button): self.emit("reversed") def moved_up(self, button): self.emit("move-up") def moved_down(self, button): self.emit("move-down") @GObject.Signal(arg_types=(bool,)) def switched(self, switch): pass @GObject.Signal def reversed(self): pass @GObject.Signal def move_up(self): pass @GObject.Signal def move_down(self): pass class Factory(Gtk.SignalListItemFactory): def __init__(self, model): self.model = model Gtk.SignalListItemFactory.__init__(self) self.connect("setup", self.setup) self.connect("bind", self.bind) self.connect("unbind", self.unbind) self.connect("teardown", self.teardown) def setup(self, factory, listitem): listitem.set_child(SortRow()) def bind(self, factory, listitem): child = listitem.get_child() child.set_item(listitem.get_item().get_string(), listitem.get_position(), self.model.get_n_enabled()) child.connect("switched", self.row_switched) child.connect("reversed", self.row_reversed) child.connect("move-up", self.move_row_up) child.connect("move-down", self.move_row_down) def unbind(self, factory, listitem): child = listitem.get_child() child.disconnect_by_func(self.row_switched) child.disconnect_by_func(self.row_reversed) child.disconnect_by_func(self.move_row_up) child.disconnect_by_func(self.move_row_down) def teardown(self, factory, listitem): listitem.set_child(None) def row_switched(self, row, enabled): field = row.label.get_field() if enabled: self.model.enable(field) index = self.model.get_enabled_model().get_index(field) else: index = self.model.get_enabled_model().get_index(field) self.model.disable(field) if index > 0: self.model.emit("items-changed", index - 1, 1, 1) def row_reversed(self, row): self.model.get_enabled_model().reverse(row.label.get_field()) def move_row_up(self, row): self.model.get_enabled_model().move_up(row.label.get_field()) def move_row_down(self, row): self.model.get_enabled_model().move_down(row.label.get_field())