1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-01-01 19:41:18 +01:00
This commit is contained in:
2025-06-04 14:21:05 +02:00
parent 21b9dc086d
commit aefc1d49f4
3 changed files with 33 additions and 14 deletions

View File

@@ -17,7 +17,6 @@ from bec_widgets.utils.forms_from_types.items import (
DynamicFormItem,
DynamicFormItemType,
FormItemSpec,
default_widget_types,
widget_from_type,
)
@@ -93,7 +92,6 @@ class TypedForm(BECWidget, QWidget):
self._layout.addWidget(self._form_grid_container)
self._form_grid_container.setLayout(QVBoxLayout())
self._form_grid.setLayout(self._new_grid_layout())
self._widget_types = default_widget_types
self._widget_from_type = widget_from_type
self._post_init()
@@ -112,7 +110,7 @@ class TypedForm(BECWidget, QWidget):
label.setProperty("_model_field_name", item.name)
label.setToolTip(item.info.description or item.name)
grid.addWidget(label, row, 0)
widget = self._widget_from_type(item.item_type, self._widget_types)(parent=self, spec=item)
widget = self._widget_from_type(item.item_type)(parent=self, spec=item)
widget.valueChanged.connect(self.value_changed)
widget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
grid.addWidget(widget, row, 1)
@@ -144,9 +142,9 @@ class TypedForm(BECWidget, QWidget):
self._form_grid.setLayout(self._new_grid_layout())
self._form_grid_container.layout().addWidget(self._form_grid)
self.resize()
self.update_size()
def resize(self):
def update_size(self):
self._form_grid.adjustSize()
self._form_grid_container.adjustSize()
self.adjustSize()

View File

@@ -1,9 +1,10 @@
from __future__ import annotations
import typing
from abc import abstractmethod
from decimal import Decimal
from types import GenericAlias, UnionType
from typing import Callable, Literal, TypedDict
from typing import Callable, Final, Literal
from bec_lib.logger import bec_logger
from bec_qthemes import material_icon
@@ -125,7 +126,7 @@ class ClearableBoolEntry(QWidget):
self._false.setToolTip(tooltip)
DynamicFormItemType = str | int | float | Decimal | bool | dict
DynamicFormItemType = str | int | float | Decimal | bool | dict | list
class DynamicFormItem(QWidget):
@@ -335,11 +336,28 @@ class DictMetadataField(DynamicFormItem):
self._main_widget.replace_data(value)
class ListMetadataField(DynamicFormItem):
def __init__(self, *, parent: QWidget | None = None, spec: FormItemSpec) -> None:
super().__init__(parent=parent, spec=spec)
if spec.info.annotation is list:
self.item_type = str
elif isinstance(spec.info.annotation, GenericAlias):
args = set(typing.get_args(spec.info.annotation))
if args == set((str,)):
self.item_type = str
if args == set((int,)):
self.item_type = int
if args == set((float,)) or args == set((int, float)):
self.item_type = float
else:
self.item_type = str
WidgetTypeRegistry = dict[
str, tuple[Callable[[type | UnionType | None], bool], type[DynamicFormItem]]
]
default_widget_types: WidgetTypeRegistry = {
DEFAULT_WIDGET_TYPES: Final[WidgetTypeRegistry] = {
"str": (lambda anno: anno in [str, str | None, None], StrMetadataField),
"int": (lambda anno: anno in [int, int | None], IntMetadataField),
"float_decimal": (
@@ -355,14 +373,15 @@ default_widget_types: WidgetTypeRegistry = {
"list": (
lambda anno: anno in [list, list | None]
or (isinstance(anno, GenericAlias) and anno.__origin__ is list),
StrMetadataField,
ListMetadataField,
),
}
def widget_from_type(
annotation: type | UnionType | None, widget_types: WidgetTypeRegistry
annotation: type | UnionType | None, widget_types: WidgetTypeRegistry | None = None
) -> type[DynamicFormItem]:
widget_types = widget_types or DEFAULT_WIDGET_TYPES
for predicate, widget_type in widget_types.values():
if predicate(annotation):
return widget_type
@@ -378,6 +397,8 @@ if __name__ == "__main__": # pragma: no cover
value3: bool = Field(True)
value4: int = Field(123)
value5: int | None = Field()
value6: list[int] = Field()
value7: list = Field()
app = QApplication([])
w = QWidget()

View File

@@ -8,9 +8,9 @@ from bec_widgets.utils.colors import get_theme_name
from bec_widgets.utils.forms_from_types import styles
from bec_widgets.utils.forms_from_types.forms import PydanticModelForm
from bec_widgets.utils.forms_from_types.items import (
DEFAULT_WIDGET_TYPES,
BoolMetadataField,
BoolToggleMetadataField,
default_widget_types,
)
@@ -26,9 +26,9 @@ class DeviceConfigForm(PydanticModelForm):
client=client,
**kwargs,
)
self._widget_types = default_widget_types.copy()
self._widget_types["bool"] = (lambda anno: anno == bool, BoolToggleMetadataField)
self._widget_types["optional_bool"] = (lambda anno: anno == bool | None, BoolMetadataField)
self._widget_types = DEFAULT_WIDGET_TYPES.copy()
self._widget_types["bool"] = (lambda anno: anno is bool, BoolToggleMetadataField)
self._widget_types["optional_bool"] = (lambda anno: anno is bool | None, BoolMetadataField)
self._validity.setVisible(False)
self._connect_to_theme_change()
self.populate()