# Copyright 2022 (c) Anna Schumaker. """A custom Gtk.HeaderBar configured for our application.""" import pathlib import typing from gi.repository import GObject from gi.repository import Gtk from gi.repository import Adw from ..action import ActionEntry from .. import db from .. import buttons from .. import gsetup from . import open from . import replaygain from . import volume if __debug__: from . import settings SUBTITLE = "The Cheesy Music Player" def _volume_icon(vol: float) -> str: if vol == 0.0: return "audio-volume-muted-symbolic" if vol <= 1/3: return "audio-volume-low-symbolic" if vol <= 2/3: return "audio-volume-medium-symbolic" return "audio-volume-high-symbolic" class Header(Gtk.HeaderBar): """Our custom Gtk.HeaderBar containing window title and volume controls.""" sql = GObject.Property(type=db.Connection) title = GObject.Property(type=str) subtitle = GObject.Property(type=str) show_sidebar = GObject.Property(type=bool, default=False) bg_enabled = GObject.Property(type=bool, default=False) bg_volume = GObject.Property(type=float, default=0.5) rg_enabled = GObject.Property(type=bool, default=False) rg_mode = GObject.Property(type=str, default="auto") volume = GObject.Property(type=float, default=1.0) def __init__(self, sql: db.Connection, title: str): """Initialize the HeaderBar.""" super().__init__(title=title, subtitle=SUBTITLE, sql=sql) self._title = Adw.WindowTitle(title=self.title, subtitle=self.subtitle, tooltip_text=gsetup.env_string()) icon = "sidebar-show-symbolic" self._show_sidebar = Gtk.ToggleButton(icon_name=icon, has_frame=False) self._open = open.OpenRow() self._menu_box = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE) self._menu_box.add_css_class("boxed-list") self._menu_box.append(self._open) if __debug__: self._settings = settings.Row(sql) self._menu_box.append(self._settings) icon = "open-menu-symbolic" self._menu_button = buttons.PopoverButton(popover_child=self._menu_box, icon_name=icon) self._volume = volume.VolumeRow() self._volume_icon = Gtk.Image(icon_name=_volume_icon(self.volume)) self._background = volume.BackgroundRow() self._background_icon = Gtk.Image(icon_name="sound-wave") self._replaygain = replaygain.ReplayGainRow() self._icons = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6) self._icons.append(self._volume_icon) self._icons.append(self._background_icon) self._vol_box = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE) self._vol_box.add_css_class("boxed-list") self._vol_box.append(self._volume) self._vol_box.append(self._background) self._vol_box.append(self._replaygain) self._vol_button = buttons.PopoverButton(popover_child=self._vol_box, child=self._icons, has_frame=False, margin_end=6) self.bind_property("title", self._title, "title") self.bind_property("subtitle", self._title, "subtitle") self.bind_property("show-sidebar", self._show_sidebar, "active", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("bg-enabled", self._background, "enabled", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("bg-volume", self._background, "volume", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("rg-enabled", self._replaygain, "enabled", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("rg-mode", self._replaygain, "mode", GObject.BindingFlags.BIDIRECTIONAL) self.bind_property("volume", self._volume, "volume", GObject.BindingFlags.BIDIRECTIONAL) self.pack_start(self._show_sidebar) self.pack_start(self._menu_button) self.pack_end(self._vol_button) self.set_title_widget(self._title) self._open.connect("track-requested", self.__track_requested) self.connect("notify", self.__notify) def __run_settings(self, button: Gtk.Button) -> None: if __debug__: self._window.present() def __notify(self, header: typing.Self, param: GObject.ParamSpec) -> None: match param.name: case "bg-enabled": icon = "sound-wave-alt" if self.bg_enabled else "sound-wave" self._background_icon.set_from_icon_name(icon) case "volume": self._volume_icon.set_from_icon_name(_volume_icon(self.volume)) bg_status = "off" if self.bg_enabled: bg_status = f"{round(self.bg_volume * 100)}%" rg_status = f"{self.rg_mode} mode" if self.rg_enabled else "off" status = (f"volume: {round(self.volume * 100)}%\n" f"background listening: {bg_status}\n" f"normalizing: {rg_status}") self._vol_button.set_tooltip_text(status) def __track_requested(self, button: open.OpenRow, path: pathlib.Path) -> None: self.emit("track-requested", path) @property def accelerators(self) -> list[ActionEntry]: """Get a list of accelerators for the Header.""" res = [ActionEntry("open-file", self._open.activate, "o"), ActionEntry("decrease-volume", self._volume.decrement, "Down"), ActionEntry("increase-volume", self._volume.increment, "Up"), ActionEntry("toggle-bg-mode", self._background.activate, "b"), ActionEntry("toggle-sidebar", self._show_sidebar.activate, "bracketright")] if __debug__: res.append(ActionEntry("edit-settings", self._settings.activate, "s")) return res @GObject.Signal(arg_types=(GObject.TYPE_PYOBJECT,)) def track_requested(self, path: pathlib.Path) -> None: """Signal that a track has been requested."""