Repository URL to install this package:
|
Version:
0.10.7 ▾
|
bauh-reloaded
/
opt
/
bauh-reloaded
/
usr
/
lib
/
python3.9
/
site-packages
/
bauh
/
api
/
abstract
/
view.py
|
|---|
from abc import ABC
from enum import Enum
from typing import List, Set, Optional, Dict, TypeVar, Type, Union, Tuple
class MessageType(Enum):
INFO = 0
WARNING = 1
ERROR = 2
class ViewComponentAlignment(Enum):
CENTER = 0
LEFT = 1
RIGHT = 2
BOTTOM = 3
TOP = 4
HORIZONTAL_CENTER = 5
VERTICAL_CENTER = 6
class ViewObserver:
def on_change(self, change):
pass
class ViewComponent(ABC):
"""
Represents a GUI component
"""
def __init__(self, id_: Optional[str], alignment: Optional[ViewComponentAlignment] = None,
observers: Optional[List[ViewObserver]] = None):
self.id = id_
self.alignment = alignment
self.observers = observers if observers else []
def add_observer(self, obs):
self.observers.append(obs)
V = TypeVar('V', bound=ViewComponent)
class ViewContainer(ViewComponent, ABC):
"""
Represents a GUI component composed by other components
"""
def __init__(self, components: Union[List[V], Tuple[V]],
id_: Optional[str] = None,
observers: Optional[List[ViewObserver]] = None):
super(ViewContainer, self).__init__(id_=id_, observers=observers)
self.components = components
self.component_map = {c.id: c for c in components if c.id is not None} if components else None
def get_component(self, id_: str, type_: Type[V] = ViewComponent) -> Optional[V]:
if self.component_map:
instance = self.component_map.get(id_)
if instance:
if isinstance(instance, type_):
return instance
raise Exception(f"The {ViewComponent.__class__.__name__} (id={id_}) is not an "
f"instance of '{type_.__name__}'")
def get_component_by_idx(self, idx: int, type_: Type[V]) -> Optional[V]:
if self.components and idx < len(self.components):
c = self.components[idx]
if isinstance(c, type_):
return c
raise Exception(f"The {ViewComponent.__class__.__name__} at index {idx} is not an "
f"instance of '{type_.__name__}'")
class SpacerComponent(ViewComponent):
def __init__(self):
super(SpacerComponent, self).__init__(id_=None)
class InputViewComponent(ViewComponent):
"""
Represents a component which needs a user interaction to provide its value
"""
class InputOption:
"""
Represents a select component option.
"""
def __init__(self, label: str, value: object, tooltip: Optional[str] = None,
icon_path: Optional[str] = None, read_only: bool = False, id_: Optional[str] = None,
invalid: bool = False, extra_properties: Optional[Dict[str, str]] = None):
"""
:param label: the string that will be shown to the user
:param value: the option value (not shown)
:param tooltip: an optional tooltip
:param icon_path: an optional icon path
:param invalid: if this option is considered invalid
:param extra_properties: extra properties
"""
if not label:
raise Exception("'label' must be a not blank string")
self.id = id_
self.label = label
self.value = value
self.tooltip = tooltip
self.icon_path = icon_path
self.read_only = read_only
self.invalid = invalid
self.extra_properties = extra_properties
def __hash__(self):
return hash(self.label) + hash(self.value)
class SelectViewType(Enum):
RADIO = 0
COMBO = 1
class SingleSelectComponent(InputViewComponent):
def __init__(self, type_: SelectViewType, label: str, options: List[InputOption],
default_option: InputOption = None, max_per_line: int = 1, tooltip: str = None,
max_width: Optional[int] = -1, id_: str = None, capitalize_label: bool = True,
alignment: Optional[ViewComponentAlignment] = None):
super(SingleSelectComponent, self).__init__(id_=id_, alignment=alignment)
self.type = type_
self.label = label
self.options = options
self.value = default_option
self.init_value = default_option
self.max_per_line = max_per_line
self.tooltip = tooltip
self.max_width = max_width
self.capitalize_label = capitalize_label
def get_selected(self):
if self.value:
return self.value.value
def changed(self) -> bool:
return self.init_value != self.value
class MultipleSelectComponent(InputViewComponent):
def __init__(self, label: Optional[str], options: List[InputOption], default_options: Set[InputOption] = None,
max_per_line: int = 1, tooltip: str = None, spaces: bool = True, max_width: int = -1,
max_height: int = -1, id_: str = None, min_width: Optional[int] = None,
opt_max_width: Optional[int] = None):
super(MultipleSelectComponent, self).__init__(id_=id_)
if not options:
raise Exception("'options' cannot be None or empty")
self.options = options
self.spaces = spaces
self.label = label
self.tooltip = tooltip
self.values = default_options if default_options else set()
self.max_per_line = max_per_line
self.min_width = min_width
self.max_width = max_width
self.max_height = max_height
self.opt_max_width = opt_max_width
def get_selected_values(self) -> list:
selected = []
if self.values:
selected.extend([op.value for op in self.values])
return selected
class TextComponent(ViewComponent):
def __init__(self, html: str, min_width: Optional[int] = None, max_width: int = -1,
tooltip: str = None, id_: str = None, size: int = None):
super(TextComponent, self).__init__(id_=id_)
self.value = html
self.min_width = min_width
self.max_width = max_width
self.tooltip = tooltip
self.size = size
class TwoStateButtonComponent(ViewComponent):
def __init__(self, label: str, tooltip: str = None, state: bool = False, id_: str = None):
super(TwoStateButtonComponent, self).__init__(id_=id_)
self.label = label
self.tooltip = tooltip
self.state = state
class TextInputType(Enum):
SINGLE_LINE = 0
MULTIPLE_LINES = 1
class TextInputComponent(ViewComponent):
def __init__(self, label: str, value: str = '', placeholder: Optional[str] = None, tooltip: Optional[str] = None,
read_only: bool = False, id_: Optional[str] = None, only_int: bool = False, max_width: int = -1,
type_: TextInputType = TextInputType.SINGLE_LINE, capitalize_label: bool = True, min_width: int = -1,
min_height: int = -1):
super(TextInputComponent, self).__init__(id_=id_)
self.label = label
self.value = value
self.tooltip = tooltip
self.placeholder = placeholder
self.read_only = read_only
self.only_int = only_int
self.max_width = max_width
self.type = type_
self.capitalize_label = capitalize_label
self.min_width = min_width
self.min_height = min_height
def get_value(self) -> str:
if self.value is not None:
return self.value
else:
return ''
def set_value(self, val: Optional[str], caller: object = None):
if val != self.value:
self.value = val
if self.observers:
for o in self.observers:
if caller != o:
o.on_change(val)
def get_int_value(self) -> Optional[int]:
if self.value is not None:
val = self.value.strip() if isinstance(self.value, str) else self.value
if val is not None:
return int(self.value)
def get_label(self) -> str:
if not self.label:
return ''
else:
return self.label.capitalize() if self.capitalize_label else self.label
class FormComponent(ViewContainer):
def __init__(self, components: List[ViewComponent], label: str = None, spaces: bool = True, id_: str = None,
min_width: Optional[int] = None):
super(FormComponent, self).__init__(id_=id_, components=components)
self.label = label
self.spaces = spaces
self.min_width = min_width
class FileChooserComponent(ViewComponent):
def __init__(self, allowed_extensions: Optional[Set[str]] = None, label: Optional[str] = None, tooltip: Optional[str] = None,
file_path: Optional[str] = None, max_width: int = -1, id_: Optional[str] = None,
search_path: Optional[str] = None, capitalize_label: bool = True, directory: bool = False):
super(FileChooserComponent, self).__init__(id_=id_)
self.label = label
self.allowed_extensions = allowed_extensions
self.file_path = file_path
self.tooltip = tooltip
self.max_width = max_width
self.search_path = search_path
self.capitalize_label = capitalize_label
self.directory = directory
def set_file_path(self, fpath: Optional[str]):
self.file_path = fpath
if self.observers:
for o in self.observers:
o.on_change(self.file_path)
def get_label(self) -> str:
if not self.label:
return ''
else:
return self.label.capitalize() if self.capitalize_label else self.label
class TabComponent(ViewComponent):
def __init__(self, label: str, content: ViewComponent, icon_path: str = None, id_: str = None):
super(TabComponent, self).__init__(id_=id_)
self.label = label
self._content = content
self.icon_path = icon_path
def get_content(self, type_: Type[V] = ViewComponent) -> V:
if isinstance(self._content, type_):
return self._content
raise Exception(f"'content' is not an instance of '{type_.__name__}'")
class TabGroupComponent(ViewContainer):
def __init__(self, tabs: List[TabComponent], id_: str = None):
super(TabGroupComponent, self).__init__(id_=id_, components=tabs)
def get_tab(self, id_: str) -> Optional[TabComponent]:
return self.get_component(id_, TabComponent)
@property
def tabs(self) -> List[TabComponent]:
return self.components
class RangeInputComponent(InputViewComponent):
def __init__(self, id_: str, label: str, tooltip: str, min_value: int, max_value: int,
step_value: int, value: Optional[int] = None, max_width: int = None):
super(RangeInputComponent, self).__init__(id_=id_)
self.label = label
self.tooltip = tooltip
self.min = min_value
self.max = max_value
self.step = step_value
self.value = value
self.max_width = max_width
class PanelComponent(ViewContainer):
def __init__(self, components: List[ViewComponent], id_: str = None):
super(PanelComponent, self).__init__(id_=id_, components=components)