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