Coverage for src/pyselector/key_manager.py: 100%
54 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-24 11:53 -0300
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-24 11:53 -0300
1# keybinds.py
3from dataclasses import dataclass
4from typing import Any
5from typing import Callable
6from typing import Optional
9class KeybindError(Exception):
10 pass
13@dataclass(kw_only=True)
14class Keybind:
15 """
16 Represents a keybind, which associates a keyboard key or
17 combination of keys with a callback function.
19 Attributes:
20 id (int): The unique identifier of the keybind.
21 bind (str): The key or key combination that triggers the keybind.
22 code (int): The unique code of the keybind.
23 description (str): A brief description of the keybind.
24 action (Optional[str]): An optional action associated with the keybind. Defaults to an empty string.
25 hidden (bool): Whether the keybind is hidden from the user interface. Defaults to True.
26 callback (Optional[Callable[..., Any]]): The function to call when the keybind is triggered. Defaults to None.
28 Methods:
29 toggle_hidden(): Toggles the visibility of the keybind in the user interface.
30 """
32 id: int
33 bind: str
34 code: int
35 description: str
36 action: Optional[str] = ""
37 hidden: bool = True
38 callback: Optional[Callable[..., Any]] = None
40 def toggle_hidden(self) -> None:
41 self.hidden = not self.hidden
44class KeyManager:
45 """
46 A class for managing keybinds, which are associations between key combinations
47 and callback functions.
49 Attributes:
50 keys (dict[str, Keybind]): A dictionary mapping keybinds to their corresponding `Keybind` objects.
51 key_count (int): A counter for assigning unique IDs to newly added keybinds.
52 code_count (int): A counter for assigning unique codes to newly added keybinds.
53 temp_hidden (list[Keybind]): A list of temporarily hidden keybinds.
54 """
56 def __init__(self) -> None:
57 self.keys: dict[str, Keybind] = {}
58 self.key_count = 1
59 self.code_count = 1
60 self.temp_hidden: list[Keybind] = []
62 def add(
63 self,
64 key: str,
65 description: str,
66 callback: Callable[..., Any],
67 hidden: bool = False,
68 exist_ok: bool = False,
69 ) -> Keybind:
70 """
71 Registers a new keybind with the specified bind and description,
72 and associates it with the specified callback function.
74 Args:
75 key (str): The bind of the keybind.
76 description (str): The description of the keybind.
77 callback (Callable[..., Any]): The function to call when the keybind is triggered.
78 hidden (bool): Whether the keybind should be hidden from the user interface. Defaults to False.
79 exist_ok (bool): Whether to overwrite an existing keybind with the same bind. Defaults to False.
80 """
81 return self.register(
82 Keybind(
83 id=self.key_count,
84 bind=key,
85 code=self.code_count,
86 description=description,
87 hidden=hidden,
88 callback=callback,
89 ),
90 exist_ok=exist_ok,
91 )
93 def unregister(self, bind: str) -> None:
94 """Removes the keybind with the specified bind."""
95 if not self.keys.get(bind):
96 raise KeybindError(f"{bind=} not found")
97 self.keys.pop(bind)
99 def register(self, key: Keybind, exist_ok: bool = False) -> Keybind:
100 """
101 Args:
102 key (Keybind): The keybind to register.
103 exist_ok (bool): Whether to overwrite an existing keybind with the same bind. Defaults to False.
105 Returns:
106 Keybind: The registered keybind.
108 Raises:
109 KeybindError: If `exist_ok` is False and a keybind with the same bind is already registered.
110 """
111 if exist_ok and self.keys.get(key.bind):
112 self.unregister(key.bind)
114 if self.keys.get(key.bind):
115 raise KeybindError(f"{key.bind=} already registered")
117 self.key_count += 1
118 self.code_count += 1
119 self.keys[key.bind] = key
120 return key
122 # def patch(self, bind: str) -> Keybind:
123 # # FIX: delete me
124 # key = self.keys.get(bind)
125 # if not key:
126 # raise KeybindError(f"{bind=} not found")
127 # return key
129 @property
130 def list_registered(self) -> list[Keybind]:
131 return list(self.keys.values())
133 def toggle_all(self) -> None:
134 """Toggles the "hidden" property of all non-hidden keybinds."""
135 for key in self.list_registered:
136 if not key.hidden:
137 key.hidden = True
139 def toggle_hidden(self, restore: bool = False) -> None:
140 """
141 Toggles the "hidden" property of all non-hidden keybinds, and
142 temporarily stores the original "hidden" state of each keybind.
143 If `restore` is True, restores the original "hidden" state of each keybind.
144 """
145 for key in self.list_registered:
146 if not key.hidden:
147 key.toggle_hidden()
148 self.temp_hidden.append(key)
149 if restore:
150 for key in self.temp_hidden:
151 key.toggle_hidden()
152 self.temp_hidden = []