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

1# keybinds.py 

2 

3from dataclasses import dataclass 

4from typing import Any 

5from typing import Callable 

6from typing import Optional 

7 

8 

9class KeybindError(Exception): 

10 pass 

11 

12 

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. 

18 

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. 

27 

28 Methods: 

29 toggle_hidden(): Toggles the visibility of the keybind in the user interface. 

30 """ 

31 

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 

39 

40 def toggle_hidden(self) -> None: 

41 self.hidden = not self.hidden 

42 

43 

44class KeyManager: 

45 """ 

46 A class for managing keybinds, which are associations between key combinations 

47 and callback functions. 

48 

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 """ 

55 

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] = [] 

61 

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. 

73 

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 ) 

92 

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) 

98 

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. 

104 

105 Returns: 

106 Keybind: The registered keybind. 

107 

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) 

113 

114 if self.keys.get(key.bind): 

115 raise KeybindError(f"{key.bind=} already registered") 

116 

117 self.key_count += 1 

118 self.code_count += 1 

119 self.keys[key.bind] = key 

120 return key 

121 

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 

128 

129 @property 

130 def list_registered(self) -> list[Keybind]: 

131 return list(self.keys.values()) 

132 

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 

138 

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 = []