From bd390d27f00147c1305e244fbd6d0650a6bdcec9 Mon Sep 17 00:00:00 2001 From: Dirk Alders Date: Fri, 25 Jul 2025 19:41:44 +0200 Subject: [PATCH] Initial mytui with widget MultiSelect created --- __init__.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 __init__.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..deabb0d --- /dev/null +++ b/__init__.py @@ -0,0 +1,75 @@ +import re + +import textual.widgets + + +class MultiSelect(textual.widgets.Select): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.__new_options__ = [] + self.__seltion_states__ = {} + self.__default_value__ = True + self.__selection_regex__ = "" + + def __sorted_selection_keys__(self): + rv = list(self.__seltion_states__.keys()) + rv.sort() + return rv + + def SetSelectionRegEx(self, regex: str) -> None: + self.__selection_regex__ = regex + self.set_options(self.__get_select_list__()) + + def AddEntry(self, entry) -> None: + if entry not in self.__new_options__ and entry not in self.__seltion_states__: + self.__seltion_states__[entry] = self.__default_value__ + self.__new_options__.append(entry) + + def __toggle__(self, entry_num): + if entry_num < 0: + if not self.__selection_regex__: + self.__default_value__ = entry_num == -1 + for key in self.__seltion_states__: + if self.__match__(key): + self.__seltion_states__[key] = entry_num == -1 + elif entry_num > len(self.__seltion_states__): + raise ValueError(f"The Entry '{entry} is not in the list") + else: + entry = self.__sorted_selection_keys__()[entry_num] + self.__seltion_states__[entry] = not self.__seltion_states__[entry] + + def __match__(self, key): + try: + match = len(re.findall(self.__selection_regex__, key)) > 0 + except re.error: + match = True # No valid regular expression + return match + + def __get_select_list__(self): + rv = [] + if len(self.__seltion_states__) > 2: + rv.append(('All', -1)) + rv.append(('None', -2)) + for index, key in enumerate(self.__sorted_selection_keys__()): + if self.__match__(key): + prefix = "\\[X] " if self.__seltion_states__[key] else "\\[-] " + rv.append((prefix + key, index)) + return rv + + def IsSelected(self, entry): + return self.__seltion_states__.get(entry, self.__default_value__) + + def _on_blur(self, event): + for entry in self.__new_options__: + self.__seltion_states__[entry] = self.__default_value__ + self.__new_options__ = [] + self.set_options(self.__get_select_list__()) + return super()._on_blur(event) + + def _on_message(self, message): + if type(message) == self.Changed: + if type(message.value) is int: + self.__toggle__(message.value) + self.clear() + self.set_options(self.__get_select_list__()) + return super()._on_message(message)