action: Add an ActionEntry class
This is inspried by the Gio.ActionEntry struct, which I can't figure out how to get working in Python. I add on a few extra helpful features, such as: - Automatically creating a Gio.SimpleAction - Tracking the desired accelerator keys - Binding the "enabled" state to a specificed property at construction Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
c5f9608c49
commit
2b5cdaa197
|
@ -0,0 +1,39 @@
|
|||
# Copyright 2023 (c) Anna Schumaker.
|
||||
"""A custom ActionEntry that works in Python."""
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gio
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class ActionEntry(GObject.GObject):
|
||||
"""Our own AcitionEntry class to make accelerators easier."""
|
||||
|
||||
enabled = GObject.Property(type=bool, default=True)
|
||||
|
||||
def __init__(self, name: str, func: callable, *accels: tuple[str],
|
||||
enabled: tuple[GObject.GObject, str] | None = None):
|
||||
"""Initialize an ActionEntry."""
|
||||
super().__init__()
|
||||
|
||||
for accel in accels:
|
||||
if not Gtk.accelerator_parse(accel)[0]:
|
||||
raise ValueError
|
||||
|
||||
self.accels = list(accels)
|
||||
self.func = func
|
||||
|
||||
if enabled is not None:
|
||||
self.enabled = enabled[0].get_property(enabled[1])
|
||||
enabled[0].bind_property(enabled[1], self, "enabled")
|
||||
|
||||
self.action = Gio.SimpleAction(name=name, enabled=self.enabled)
|
||||
self.action.connect("activate", self.__activate)
|
||||
self.bind_property("enabled", self.action, "enabled")
|
||||
|
||||
def __activate(self, action: Gio.SimpleAction, param) -> None:
|
||||
self.func()
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Get then name of this ActionEntry."""
|
||||
return self.action.get_name()
|
|
@ -0,0 +1,66 @@
|
|||
# Copyright 2023 (c) Anna Schumaker.
|
||||
"""Tests our Python ActionEntry class."""
|
||||
import unittest
|
||||
import emmental.action
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gio
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TestActionEntry(unittest.TestCase):
|
||||
"""Test case for our Python ActionEntry."""
|
||||
|
||||
def test_init(self):
|
||||
"""Test constructing an ActionEntry."""
|
||||
func = unittest.mock.Mock()
|
||||
entry = emmental.action.ActionEntry("test-name", func, "<Control>t")
|
||||
self.assertIsInstance(entry, GObject.GObject)
|
||||
self.assertIsInstance(entry.action, Gio.SimpleAction)
|
||||
self.assertEqual(entry.action.get_name(), "test-name")
|
||||
|
||||
self.assertEqual(entry.name, "test-name")
|
||||
self.assertEqual(entry.func, func)
|
||||
self.assertListEqual(entry.accels, ["<Control>t"])
|
||||
|
||||
def test_multiple_accels(self):
|
||||
"""Test that multiple accelerators can be passed."""
|
||||
func = unittest.mock.Mock()
|
||||
entry = emmental.action.ActionEntry("test-multi", func,
|
||||
"<Control>t", "<Control>u")
|
||||
self.assertListEqual(entry.accels, ["<Control>t", "<Control>u"])
|
||||
|
||||
def test_invalid_accel(self):
|
||||
"""Test that invalid accelerators are caught during construction."""
|
||||
func = unittest.mock.Mock()
|
||||
with self.assertRaises(ValueError):
|
||||
emmental.action.ActionEntry("test-name", func, "<abcde>")
|
||||
|
||||
def test_activate(self):
|
||||
"""Test activating the constructed action."""
|
||||
func = unittest.mock.Mock()
|
||||
entry = emmental.action.ActionEntry("test-name", func, "<Control>t")
|
||||
entry.action.activate()
|
||||
func.assert_called_with()
|
||||
|
||||
def test_enabled(self):
|
||||
"""Test the enabled property."""
|
||||
func = unittest.mock.Mock()
|
||||
entry = emmental.action.ActionEntry("test-name", func, "<Control>t")
|
||||
self.assertTrue(entry.enabled)
|
||||
self.assertTrue(entry.action.get_enabled())
|
||||
|
||||
entry.enabled = False
|
||||
self.assertFalse(entry.action.get_enabled())
|
||||
|
||||
def test_enabled_bind(self):
|
||||
"""Test binding to the enabled property at construction."""
|
||||
func = unittest.mock.Mock()
|
||||
label = Gtk.Label(sensitive=False)
|
||||
entry = emmental.action.ActionEntry("test-name", func, "<Control>t",
|
||||
enabled=(label, "sensitive"))
|
||||
self.assertFalse(entry.enabled)
|
||||
self.assertFalse(entry.action.get_enabled())
|
||||
|
||||
label.set_sensitive(True)
|
||||
self.assertTrue(entry.enabled)
|
||||
self.assertTrue(entry.action.get_enabled())
|
Loading…
Reference in New Issue