header: Add tooltips to the Header widgets

This is nice to have so users know what to expect from each button. I do
take some liberties, such as putting version numbers of our dependencies
as the tooltip for the Title widget. I also display the current volume
level in the volume button tooltip.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2023-05-27 16:12:44 -04:00
parent dd9d6268ff
commit 5b0a0f54e4
4 changed files with 31 additions and 6 deletions

View File

@ -1,11 +1,13 @@
# Copyright 2022 (c) Anna Schumaker. # Copyright 2022 (c) Anna Schumaker.
"""A custom Gtk.HeaderBar configured for our application.""" """A custom Gtk.HeaderBar configured for our application."""
import pathlib import pathlib
import typing
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Adw from gi.repository import Adw
from .. import db from .. import db
from .. import buttons from .. import buttons
from .. import gsetup
from . import open from . import open
from . import replaygain from . import replaygain
from . import volume from . import volume
@ -39,7 +41,8 @@ class Header(Gtk.HeaderBar):
"""Initialize the HeaderBar.""" """Initialize the HeaderBar."""
super().__init__(title=title, subtitle=SUBTITLE, sql=sql) super().__init__(title=title, subtitle=SUBTITLE, sql=sql)
self._open = open.Button() self._open = open.Button()
self._title = Adw.WindowTitle(title=self.title, subtitle=self.subtitle) self._title = Adw.WindowTitle(title=self.title, subtitle=self.subtitle,
tooltip_text=gsetup.env_string())
self._volume = volume.Controls() self._volume = volume.Controls()
self._replaygain = replaygain.Selector() self._replaygain = replaygain.Selector()
@ -64,7 +67,8 @@ class Header(Gtk.HeaderBar):
self.pack_start(self._open) self.pack_start(self._open)
if __debug__: if __debug__:
self._window = settings.Window(sql) self._window = settings.Window(sql)
self._settings = Gtk.Button.new_from_icon_name("settings-symbolic") self._settings = Gtk.Button(icon_name="settings-symbolic",
tooltip_text="open settings editor")
self._settings.connect("clicked", self.__run_settings) self._settings.connect("clicked", self.__run_settings)
self.pack_start(self._settings) self.pack_start(self._settings)
@ -72,14 +76,21 @@ class Header(Gtk.HeaderBar):
self.set_title_widget(self._title) self.set_title_widget(self._title)
self._open.connect("track-requested", self.__track_requested) self._open.connect("track-requested", self.__track_requested)
self.connect("notify::volume", self.__notify_volume) self.connect("notify", self.__notify)
def __run_settings(self, button: Gtk.Button) -> None: def __run_settings(self, button: Gtk.Button) -> None:
if __debug__: if __debug__:
self._window.present() self._window.present()
def __notify_volume(self, header, param) -> None: def __notify(self, header: typing.Self, param: GObject.ParamSpec) -> None:
self._button.set_icon_name(_volume_icon(self.volume)) match param.name:
case "volume":
self._button.set_icon_name(_volume_icon(self.volume))
rg_status = f"{self.rg_mode} mode" if self.rg_enabled else "off"
status = (f"volume: {round(self.volume * 100)}%\n"
f"normalizing: {rg_status}")
self._button.set_tooltip_text(status)
def __track_requested(self, button: open.Button, def __track_requested(self, button: open.Button,
path: pathlib.Path) -> None: path: pathlib.Path) -> None:

View File

@ -12,7 +12,8 @@ class Button(Gtk.Button):
def __init__(self): def __init__(self):
"""Initialize our open button.""" """Initialize our open button."""
super().__init__(icon_name="document-open-symbolic") super().__init__(icon_name="document-open-symbolic",
tooltip_text="open a file for playback")
self._filters = Gio.ListStore() self._filters = Gio.ListStore()
self._filter = Gtk.FileFilter(name="Audio Files", self._filter = Gtk.FileFilter(name="Audio Files",
mime_types=["inode/directory", mime_types=["inode/directory",

View File

@ -33,6 +33,9 @@ class TestHeader(tests.util.TestCase):
self.assertEqual(self.header._title.get_subtitle(), self.assertEqual(self.header._title.get_subtitle(),
emmental.header.SUBTITLE) emmental.header.SUBTITLE)
self.assertEqual(self.header._title.get_tooltip_text(),
emmental.gsetup.env_string())
def test_open(self): def test_open(self):
"""Check that the Open button works as expected.""" """Check that the Open button works as expected."""
self.assertIsInstance(self.header._open, emmental.header.open.Button) self.assertIsInstance(self.header._open, emmental.header.open.Button)
@ -51,6 +54,8 @@ class TestHeader(tests.util.TestCase):
self.assertEqual(self.header.sql, self.sql) self.assertEqual(self.header.sql, self.sql)
self.assertEqual(self.header._settings.get_icon_name(), self.assertEqual(self.header._settings.get_icon_name(),
"settings-symbolic") "settings-symbolic")
self.assertEqual(self.header._settings.get_tooltip_text(),
"open settings editor")
with unittest.mock.patch.object(self.header._window, with unittest.mock.patch.object(self.header._window,
"present") as mock_present: "present") as mock_present:
@ -77,6 +82,8 @@ class TestHeader(tests.util.TestCase):
self.assertEqual(self.header._volume.volume, vol) self.assertEqual(self.header._volume.volume, vol)
self.assertEqual(self.header._button.get_icon_name(), self.assertEqual(self.header._button.get_icon_name(),
f"audio-volume-{icon}-symbolic") f"audio-volume-{icon}-symbolic")
self.assertEqual(self.header._button.get_tooltip_text(),
f"volume: {i*10}%\nnormalizing: off")
def test_replaygain(self): def test_replaygain(self):
"""Test that we can configure ReplayGain as expected.""" """Test that we can configure ReplayGain as expected."""
@ -89,11 +96,15 @@ class TestHeader(tests.util.TestCase):
self.header.rg_mode = "track" self.header.rg_mode = "track"
self.assertTrue(self.header._replaygain.enabled) self.assertTrue(self.header._replaygain.enabled)
self.assertEqual(self.header._replaygain.mode, "track") self.assertEqual(self.header._replaygain.mode, "track")
self.assertEqual(self.header._button.get_tooltip_text(),
"volume: 100%\nnormalizing: track mode")
self.header._replaygain.enabled = False self.header._replaygain.enabled = False
self.header._replaygain.mode = "album" self.header._replaygain.mode = "album"
self.assertFalse(self.header.rg_enabled) self.assertFalse(self.header.rg_enabled)
self.assertEqual(self.header.rg_mode, "album") self.assertEqual(self.header.rg_mode, "album")
self.assertEqual(self.header._button.get_tooltip_text(),
"volume: 100%\nnormalizing: off")
def test_popover(self): def test_popover(self):
"""Check that the menu popover was set up correctly.""" """Check that the menu popover was set up correctly."""

View File

@ -18,6 +18,8 @@ class TestButton(unittest.TestCase):
"""Check that the button was set up properly.""" """Check that the button was set up properly."""
self.assertIsInstance(self.button, Gtk.Button) self.assertIsInstance(self.button, Gtk.Button)
self.assertEqual(self.button.get_icon_name(), "document-open-symbolic") self.assertEqual(self.button.get_icon_name(), "document-open-symbolic")
self.assertEqual(self.button.get_tooltip_text(),
"open a file for playback")
def test_filter(self): def test_filter(self):
"""Check that the file filter is set up properly.""" """Check that the file filter is set up properly."""