py10x-universe 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core_10x/__init__.py +42 -0
- core_10x/backbone/__init__.py +0 -0
- core_10x/backbone/backbone_store.py +59 -0
- core_10x/backbone/backbone_traitable.py +30 -0
- core_10x/backbone/backbone_user.py +66 -0
- core_10x/backbone/bound_data_domain.py +49 -0
- core_10x/backbone/namespace.py +101 -0
- core_10x/backbone/vault.py +38 -0
- core_10x/code_samples/__init__.py +0 -0
- core_10x/code_samples/_package_manifest.py +3 -0
- core_10x/code_samples/directories.py +181 -0
- core_10x/code_samples/person.py +76 -0
- core_10x/concrete_traits.py +356 -0
- core_10x/conftest.py +12 -0
- core_10x/curve.py +321 -0
- core_10x/data_domain.py +48 -0
- core_10x/data_domain_binder.py +45 -0
- core_10x/directory.py +250 -0
- core_10x/entity.py +8 -0
- core_10x/entity_filter.py +5 -0
- core_10x/environment_variables.py +147 -0
- core_10x/exec_control.py +84 -0
- core_10x/experimental/__init__.py +0 -0
- core_10x/experimental/data_protocol_ex.py +34 -0
- core_10x/global_cache.py +121 -0
- core_10x/manual_tests/__init__.py +0 -0
- core_10x/manual_tests/calendar_test.py +35 -0
- core_10x/manual_tests/ctor_update_bug.py +58 -0
- core_10x/manual_tests/debug_graph_on.py +17 -0
- core_10x/manual_tests/debug_graphoff_inside_graph_on.py +28 -0
- core_10x/manual_tests/enum_bits_test.py +17 -0
- core_10x/manual_tests/env_vars_trivial_test.py +12 -0
- core_10x/manual_tests/existing_traitable.py +33 -0
- core_10x/manual_tests/k10x_test1.py +13 -0
- core_10x/manual_tests/named_constant_test.py +121 -0
- core_10x/manual_tests/nucleus_trivial_test.py +42 -0
- core_10x/manual_tests/polars_test.py +14 -0
- core_10x/manual_tests/py_class_test.py +4 -0
- core_10x/manual_tests/rc_test.py +42 -0
- core_10x/manual_tests/rdate_test.py +12 -0
- core_10x/manual_tests/reference_serialization_bug.py +19 -0
- core_10x/manual_tests/resource_trivial_test.py +10 -0
- core_10x/manual_tests/store_uri_test.py +6 -0
- core_10x/manual_tests/trait_definition_test.py +19 -0
- core_10x/manual_tests/trait_filter_test.py +15 -0
- core_10x/manual_tests/trait_flag_modification_test.py +42 -0
- core_10x/manual_tests/trait_modification_bug.py +26 -0
- core_10x/manual_tests/traitable_as_of_test.py +82 -0
- core_10x/manual_tests/traitable_heir_test.py +39 -0
- core_10x/manual_tests/traitable_history_test.py +41 -0
- core_10x/manual_tests/traitable_serialization_test.py +54 -0
- core_10x/manual_tests/traitable_trivial_test.py +71 -0
- core_10x/manual_tests/trivial_graph_test.py +16 -0
- core_10x/manual_tests/ts_class_association_test.py +64 -0
- core_10x/manual_tests/ts_trivial_test.py +35 -0
- core_10x/named_constant.py +425 -0
- core_10x/nucleus.py +81 -0
- core_10x/package_manifest.py +85 -0
- core_10x/package_refactoring.py +153 -0
- core_10x/py_class.py +431 -0
- core_10x/rc.py +155 -0
- core_10x/rdate.py +339 -0
- core_10x/resource.py +189 -0
- core_10x/roman_number.py +67 -0
- core_10x/testlib/__init__.py +0 -0
- core_10x/testlib/test_store.py +240 -0
- core_10x/testlib/traitable_history_tests.py +787 -0
- core_10x/testlib/ts_tests.py +280 -0
- core_10x/trait.py +377 -0
- core_10x/trait_definition.py +176 -0
- core_10x/trait_filter.py +205 -0
- core_10x/trait_method_error.py +36 -0
- core_10x/traitable.py +1082 -0
- core_10x/traitable_cli.py +153 -0
- core_10x/traitable_heir.py +33 -0
- core_10x/traitable_id.py +31 -0
- core_10x/ts_store.py +172 -0
- core_10x/ts_store_type.py +26 -0
- core_10x/ts_union.py +147 -0
- core_10x/ui_hint.py +153 -0
- core_10x/unit_tests/test_concrete_traits.py +156 -0
- core_10x/unit_tests/test_converters.py +51 -0
- core_10x/unit_tests/test_curve.py +157 -0
- core_10x/unit_tests/test_directory.py +54 -0
- core_10x/unit_tests/test_documentation.py +172 -0
- core_10x/unit_tests/test_environment_variables.py +15 -0
- core_10x/unit_tests/test_filters.py +239 -0
- core_10x/unit_tests/test_graph.py +348 -0
- core_10x/unit_tests/test_named_constant.py +98 -0
- core_10x/unit_tests/test_rc.py +11 -0
- core_10x/unit_tests/test_rdate.py +484 -0
- core_10x/unit_tests/test_trait_method_error.py +80 -0
- core_10x/unit_tests/test_trait_modification.py +19 -0
- core_10x/unit_tests/test_traitable.py +959 -0
- core_10x/unit_tests/test_traitable_history.py +1 -0
- core_10x/unit_tests/test_ts_store.py +1 -0
- core_10x/unit_tests/test_ts_union.py +369 -0
- core_10x/unit_tests/test_ui_nodes.py +81 -0
- core_10x/unit_tests/test_xxcalendar.py +471 -0
- core_10x/vault/__init__.py +0 -0
- core_10x/vault/sec_keys.py +133 -0
- core_10x/vault/security_keys_old.py +168 -0
- core_10x/vault/vault.py +56 -0
- core_10x/vault/vault_traitable.py +56 -0
- core_10x/vault/vault_user.py +70 -0
- core_10x/xdate_time.py +136 -0
- core_10x/xnone.py +71 -0
- core_10x/xxcalendar.py +228 -0
- infra_10x/__init__.py +0 -0
- infra_10x/manual_tests/__init__.py +0 -0
- infra_10x/manual_tests/test_misc.py +16 -0
- infra_10x/manual_tests/test_prepare_filter_and_pipeline.py +25 -0
- infra_10x/mongodb_admin.py +111 -0
- infra_10x/mongodb_store.py +346 -0
- infra_10x/mongodb_utils.py +129 -0
- infra_10x/unit_tests/conftest.py +13 -0
- infra_10x/unit_tests/test_mongo_db.py +36 -0
- infra_10x/unit_tests/test_mongo_history.py +1 -0
- py10x_universe-0.1.3.dist-info/METADATA +406 -0
- py10x_universe-0.1.3.dist-info/RECORD +214 -0
- py10x_universe-0.1.3.dist-info/WHEEL +4 -0
- py10x_universe-0.1.3.dist-info/licenses/LICENSE +21 -0
- ui_10x/__init__.py +0 -0
- ui_10x/apps/__init__.py +0 -0
- ui_10x/apps/collection_editor_app.py +100 -0
- ui_10x/choice.py +212 -0
- ui_10x/collection_editor.py +135 -0
- ui_10x/concrete_trait_widgets.py +220 -0
- ui_10x/conftest.py +8 -0
- ui_10x/entity_stocker.py +173 -0
- ui_10x/examples/__init__.py +0 -0
- ui_10x/examples/_guess_word_data.py +14076 -0
- ui_10x/examples/collection_editor.py +17 -0
- ui_10x/examples/date_selector.py +14 -0
- ui_10x/examples/entity_stocker.py +18 -0
- ui_10x/examples/guess_word.py +392 -0
- ui_10x/examples/message_box.py +20 -0
- ui_10x/examples/multi_choice.py +17 -0
- ui_10x/examples/py_data_browser.py +66 -0
- ui_10x/examples/radiobox.py +29 -0
- ui_10x/examples/single_choice.py +31 -0
- ui_10x/examples/style_sheet.py +47 -0
- ui_10x/examples/trivial_entity_editor.py +18 -0
- ui_10x/platform.py +20 -0
- ui_10x/platform_interface.py +517 -0
- ui_10x/py_data_browser.py +249 -0
- ui_10x/qt6/__init__.py +0 -0
- ui_10x/qt6/conftest.py +8 -0
- ui_10x/qt6/manual_tests/__init__.py +0 -0
- ui_10x/qt6/manual_tests/basic_test.py +35 -0
- ui_10x/qt6/platform_implementation.py +275 -0
- ui_10x/qt6/utils.py +665 -0
- ui_10x/rio/__init__.py +0 -0
- ui_10x/rio/apps/examples/examples/__init__.py +22 -0
- ui_10x/rio/apps/examples/examples/components/__init__.py +3 -0
- ui_10x/rio/apps/examples/examples/components/collection_editor.py +15 -0
- ui_10x/rio/apps/examples/examples/pages/collection_editor.py +21 -0
- ui_10x/rio/apps/examples/examples/pages/login_page.py +88 -0
- ui_10x/rio/apps/examples/examples/pages/style_sheet.py +21 -0
- ui_10x/rio/apps/examples/rio.toml +14 -0
- ui_10x/rio/component_builder.py +497 -0
- ui_10x/rio/components/__init__.py +9 -0
- ui_10x/rio/components/group_box.py +31 -0
- ui_10x/rio/components/labeled_checkbox.py +18 -0
- ui_10x/rio/components/line_edit.py +37 -0
- ui_10x/rio/components/radio_button.py +32 -0
- ui_10x/rio/components/separator.py +24 -0
- ui_10x/rio/components/splitter.py +121 -0
- ui_10x/rio/components/tree_view.py +75 -0
- ui_10x/rio/conftest.py +35 -0
- ui_10x/rio/internals/__init__.py +0 -0
- ui_10x/rio/internals/app.py +192 -0
- ui_10x/rio/manual_tests/__init__.py +0 -0
- ui_10x/rio/manual_tests/basic_test.py +24 -0
- ui_10x/rio/manual_tests/splitter.py +27 -0
- ui_10x/rio/platform_implementation.py +91 -0
- ui_10x/rio/style_sheet.py +53 -0
- ui_10x/rio/unit_tests/test_collection_editor.py +68 -0
- ui_10x/rio/unit_tests/test_internals.py +630 -0
- ui_10x/rio/unit_tests/test_style_sheet.py +37 -0
- ui_10x/rio/widgets/__init__.py +46 -0
- ui_10x/rio/widgets/application.py +109 -0
- ui_10x/rio/widgets/button.py +48 -0
- ui_10x/rio/widgets/button_group.py +60 -0
- ui_10x/rio/widgets/calendar.py +23 -0
- ui_10x/rio/widgets/checkbox.py +24 -0
- ui_10x/rio/widgets/dialog.py +137 -0
- ui_10x/rio/widgets/group_box.py +27 -0
- ui_10x/rio/widgets/layout.py +34 -0
- ui_10x/rio/widgets/line_edit.py +37 -0
- ui_10x/rio/widgets/list.py +105 -0
- ui_10x/rio/widgets/message_box.py +70 -0
- ui_10x/rio/widgets/scroll_area.py +31 -0
- ui_10x/rio/widgets/spacer.py +6 -0
- ui_10x/rio/widgets/splitter.py +45 -0
- ui_10x/rio/widgets/text_edit.py +28 -0
- ui_10x/rio/widgets/tree.py +89 -0
- ui_10x/rio/widgets/unit_tests/test_button.py +101 -0
- ui_10x/rio/widgets/unit_tests/test_button_group.py +33 -0
- ui_10x/rio/widgets/unit_tests/test_calendar.py +114 -0
- ui_10x/rio/widgets/unit_tests/test_checkbox.py +109 -0
- ui_10x/rio/widgets/unit_tests/test_group_box.py +158 -0
- ui_10x/rio/widgets/unit_tests/test_label.py +43 -0
- ui_10x/rio/widgets/unit_tests/test_line_edit.py +140 -0
- ui_10x/rio/widgets/unit_tests/test_list.py +146 -0
- ui_10x/table_header_view.py +305 -0
- ui_10x/table_view.py +174 -0
- ui_10x/trait_editor.py +189 -0
- ui_10x/trait_widget.py +131 -0
- ui_10x/traitable_editor.py +200 -0
- ui_10x/traitable_view.py +131 -0
- ui_10x/unit_tests/conftest.py +8 -0
- ui_10x/unit_tests/test_platform.py +9 -0
- ui_10x/utils.py +661 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
import ui_10x.platform_interface as i
|
|
6
|
+
import ui_10x.rio.components as rio_components
|
|
7
|
+
from ui_10x.rio.component_builder import Widget
|
|
8
|
+
|
|
9
|
+
# noinspection PyCompatibility
|
|
10
|
+
from . import (
|
|
11
|
+
Application,
|
|
12
|
+
Dialog,
|
|
13
|
+
HBoxLayout,
|
|
14
|
+
Label,
|
|
15
|
+
PushButton,
|
|
16
|
+
Style,
|
|
17
|
+
VBoxLayout,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Callable
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Separator(Widget, i.Separator):
|
|
25
|
+
s_component_class = rio_components.Separator
|
|
26
|
+
s_forced_kwargs = {}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MessageBox(i.MessageBox):
|
|
30
|
+
@classmethod
|
|
31
|
+
def _dialog(cls, parent: Widget, title: str, message: str, icon: Style.StandardPixmap, on_close: Callable[[Any], None]) -> bool | None:
|
|
32
|
+
style = Application.style()
|
|
33
|
+
if icon == Style.StandardPixmap.SP_MESSAGEBOXQUESTION:
|
|
34
|
+
buttons = [
|
|
35
|
+
PushButton(style.standard_icon(Style.StandardPixmap.SP_DIALOGYESBUTTON.value), 'Yes', on_press=lambda: dlg.on_accept()),
|
|
36
|
+
PushButton(style.standard_icon(Style.StandardPixmap.SP_DIALOGNOBUTTON.value), 'No', on_press=lambda: dlg.on_reject()),
|
|
37
|
+
]
|
|
38
|
+
else:
|
|
39
|
+
buttons = [PushButton(style.standard_icon(Style.StandardPixmap.SP_DIALOGOKBUTTON.value), 'Ok', on_press=lambda: dlg.on_accept())]
|
|
40
|
+
children = (
|
|
41
|
+
Label(title, align_x=0.5, align_y=0, style='heading1'),
|
|
42
|
+
Separator(),
|
|
43
|
+
HBoxLayout(
|
|
44
|
+
PushButton(style.standard_icon(icon.value), '', style='plain-text', is_sensitive=False, align_y=0, align_x=0, grow_x=False),
|
|
45
|
+
Label(message, align_y=0, overflow='wrap', grow_x=True),
|
|
46
|
+
),
|
|
47
|
+
Separator(),
|
|
48
|
+
HBoxLayout(*buttons),
|
|
49
|
+
)
|
|
50
|
+
dlg = Dialog(
|
|
51
|
+
parent=parent, title=title, children=children, on_accept=lambda: on_close(dlg.accepted), on_reject=lambda: on_close(dlg.accepted)
|
|
52
|
+
)
|
|
53
|
+
dlg.set_layout(VBoxLayout())
|
|
54
|
+
return dlg.show() if on_close else dlg.exec()
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def question(cls, parent: Widget, title: str, message: str, on_close: Callable[[Any], None]) -> bool:
|
|
58
|
+
return cls._dialog(parent=parent, title=title, message=message, icon=Style.StandardPixmap.SP_MESSAGEBOXQUESTION, on_close=on_close)
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def warning(cls, parent: Widget, title: str, message: str, on_close: Callable[[Any], None]):
|
|
62
|
+
return cls._dialog(parent=parent, title=title, message=message, icon=Style.StandardPixmap.SP_MESSAGEBOXWARNING, on_close=on_close)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def information(cls, parent: Widget, title: str, message: str, on_close: Callable[[Any], None]):
|
|
66
|
+
return cls._dialog(parent=parent, title=title, message=message, icon=Style.StandardPixmap.SP_MESSAGEBOXINFORMATION, on_close=on_close)
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def is_yes_button(cls, sb) -> bool:
|
|
70
|
+
return sb
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from core_10x.named_constant import Enum
|
|
6
|
+
|
|
7
|
+
import rio
|
|
8
|
+
import ui_10x.platform_interface as i
|
|
9
|
+
from ui_10x.rio.component_builder import Widget
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SCROLL(Enum):
|
|
13
|
+
OFF = 'never'
|
|
14
|
+
ON = 'always'
|
|
15
|
+
AS_NEEDED = 'auto'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ScrollArea(Widget, i.ScrollArea):
|
|
19
|
+
s_component_class = rio.ScrollContainer
|
|
20
|
+
|
|
21
|
+
def set_widget(self, w: Widget):
|
|
22
|
+
self.set_children([w])
|
|
23
|
+
|
|
24
|
+
def set_horizontal_scroll_bar_policy(self, h):
|
|
25
|
+
self._set_scrollbar_policy('scroll_x', h)
|
|
26
|
+
|
|
27
|
+
def set_vertical_scroll_bar_policy(self, h):
|
|
28
|
+
self._set_scrollbar_policy('scroll_y', h)
|
|
29
|
+
|
|
30
|
+
def _set_scrollbar_policy(self, scroll: Literal['scroll_x', 'scroll_y'], policy: SCROLL):
|
|
31
|
+
self[scroll] = policy.label
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from core_10x.named_constant import Enum
|
|
4
|
+
|
|
5
|
+
import ui_10x.platform_interface as i
|
|
6
|
+
import ui_10x.rio.components as rio_components
|
|
7
|
+
from ui_10x.rio.component_builder import Widget
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Direction(Enum):
|
|
11
|
+
VERTICAL = 'vertical'
|
|
12
|
+
HORIZONTAL = 'horizontal'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Horizontal = Direction.HORIZONTAL
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Splitter(Widget, i.Splitter):
|
|
19
|
+
s_component_class = rio_components.Splitter
|
|
20
|
+
s_pass_children_in_kwargs = True
|
|
21
|
+
|
|
22
|
+
def _make_kwargs(self, **kwargs):
|
|
23
|
+
kwargs = super()._make_kwargs(**kwargs)
|
|
24
|
+
if kwargs['direction'] == Horizontal.label:
|
|
25
|
+
del kwargs['align_y']
|
|
26
|
+
kwargs['grow_y'] = True
|
|
27
|
+
kwargs['child_proportions'] = []
|
|
28
|
+
return kwargs
|
|
29
|
+
|
|
30
|
+
def __init__(self, direction: Direction = Horizontal, **kwargs):
|
|
31
|
+
super().__init__(**kwargs | dict(direction=direction.label))
|
|
32
|
+
|
|
33
|
+
def add_widget(self, widget: Widget):
|
|
34
|
+
self.add_children(widget)
|
|
35
|
+
self['child_proportions'].append(1)
|
|
36
|
+
|
|
37
|
+
def set_handle_width(self, width: int):
|
|
38
|
+
self['handle_size'] = width
|
|
39
|
+
|
|
40
|
+
def set_stretch_factor(self, widget_index: int, factor: int):
|
|
41
|
+
self['child_proportions'][widget_index] = factor # TODO: normalize?
|
|
42
|
+
|
|
43
|
+
def replace_widget(self, widget_index: int, widget: Widget):
|
|
44
|
+
self.get_children()[widget_index] = widget
|
|
45
|
+
self.force_update()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import rio
|
|
4
|
+
import ui_10x.platform_interface as i
|
|
5
|
+
from ui_10x.rio.component_builder import Widget
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TextEdit(Widget, i.TextEdit):
|
|
9
|
+
s_component_class = rio.MultiLineTextInput
|
|
10
|
+
|
|
11
|
+
def _make_kwargs(self, **kwargs):
|
|
12
|
+
kw = super()._make_kwargs(**kwargs)
|
|
13
|
+
handler = self.focus_out_event
|
|
14
|
+
if handler.__func__ != TextEdit.focus_out_event: # do not set unless implemented
|
|
15
|
+
kw['on_lose_focus'] = self.callback(handler)
|
|
16
|
+
# TODO: test clipboard interactions
|
|
17
|
+
return kw
|
|
18
|
+
|
|
19
|
+
def to_plain_text(self) -> str:
|
|
20
|
+
return self['text']
|
|
21
|
+
|
|
22
|
+
def set_plain_text(self, text: str):
|
|
23
|
+
self['text'] = text
|
|
24
|
+
|
|
25
|
+
def set_read_only(self, readonly: bool):
|
|
26
|
+
self['is_sensitive'] = not readonly
|
|
27
|
+
|
|
28
|
+
def focus_out_event(self, event): ...
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import partial
|
|
4
|
+
|
|
5
|
+
import ui_10x.platform_interface as i
|
|
6
|
+
import ui_10x.rio.components as rio_components
|
|
7
|
+
from ui_10x.rio.component_builder import Widget
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TreeItem(Widget, i.TreeItem):
|
|
11
|
+
__slots__ = ('handlers',)
|
|
12
|
+
s_component_class = rio_components.RioTreeItem
|
|
13
|
+
s_pass_children_in_kwargs = True
|
|
14
|
+
|
|
15
|
+
def __init__(self, parent: TreeWidget | TreeItem, *args, **kwargs):
|
|
16
|
+
super().__init__(*args, **kwargs)
|
|
17
|
+
parent[self.s_children_attr] = parent[self.s_children_attr] + [self]
|
|
18
|
+
self.handlers = parent.handlers
|
|
19
|
+
for name, callback in self.handlers.items():
|
|
20
|
+
self[name.replace('_item_', '_')] = partial(callback, self)
|
|
21
|
+
|
|
22
|
+
def set_expanded(self, expanded: bool):
|
|
23
|
+
self['is_expanded'] = expanded
|
|
24
|
+
|
|
25
|
+
# noinspection PyMethodOverriding
|
|
26
|
+
def set_text(self, col: int, text: str):
|
|
27
|
+
super().set_text(text)
|
|
28
|
+
|
|
29
|
+
# noinspection PyMethodOverriding
|
|
30
|
+
def set_tool_tip(self, col: int, text: str):
|
|
31
|
+
super().set_tool_tip(text)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TreeWidget(Widget, i.TreeWidget):
|
|
35
|
+
__slots__ = ('handlers',)
|
|
36
|
+
s_component_class = rio_components.RioTreeView
|
|
37
|
+
s_default_kwargs = dict(selection_mode='single')
|
|
38
|
+
|
|
39
|
+
def __init__(self, *args, **kwargs):
|
|
40
|
+
super().__init__(*args, **kwargs)
|
|
41
|
+
self.handlers = {}
|
|
42
|
+
|
|
43
|
+
def set_column_count(self, col_count: int):
|
|
44
|
+
"""Set the number of columns in the tree widget."""
|
|
45
|
+
assert col_count in [1, 2], 'col_count must be 1 or 2'
|
|
46
|
+
self['col_count'] = col_count
|
|
47
|
+
|
|
48
|
+
def set_header_labels(self, labels: list):
|
|
49
|
+
"""Set the header labels for each column."""
|
|
50
|
+
self['header_labels'] = labels
|
|
51
|
+
|
|
52
|
+
def top_level_item_count(self) -> int:
|
|
53
|
+
"""Return the number of top-level items."""
|
|
54
|
+
return len(self.get_children())
|
|
55
|
+
|
|
56
|
+
def top_level_item(self, i: int) -> TreeItem:
|
|
57
|
+
"""Return the top-level item at index i."""
|
|
58
|
+
return self.get_children()[i]
|
|
59
|
+
|
|
60
|
+
def resize_column_to_contents(self, col: int):
|
|
61
|
+
"""Adjust the width of the specified column (placeholder)."""
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def item_expanded_connect(self, bound_method):
|
|
65
|
+
self.handlers['on_item_expand'] = self.callback(bound_method)
|
|
66
|
+
|
|
67
|
+
def item_clicked_connect(self, bound_method):
|
|
68
|
+
# self.handlers['on_item_double_press'] = bound_method
|
|
69
|
+
self.handlers['on_item_press'] = self.callback(bound_method)
|
|
70
|
+
|
|
71
|
+
def item_pressed_connect(self, bound_method):
|
|
72
|
+
self.handlers['on_item_press'] = bound_method
|
|
73
|
+
|
|
74
|
+
def item_changed_connect(self, bound_method):
|
|
75
|
+
raise NotImplementedError
|
|
76
|
+
|
|
77
|
+
def edit_item(self, item: TreeItem, col: int):
|
|
78
|
+
"""Start editing the specified item in the given column (placeholder)."""
|
|
79
|
+
# self.component.start_editing(item, col)
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
|
|
82
|
+
def open_persistent_editor(self, item: TreeItem, col: int):
|
|
83
|
+
"""Open a persistent editor for the specified item and column (placeholder)."""
|
|
84
|
+
# self.component.open_persistent_editor(item, col)
|
|
85
|
+
raise NotImplementedError
|
|
86
|
+
|
|
87
|
+
def add_top_level_item(self, item: TreeItem):
|
|
88
|
+
"""Add a top-level item to the tree (helper method)."""
|
|
89
|
+
self.get_children().append(item)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import rio.testing.browser_client
|
|
4
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
5
|
+
from ui_10x.rio.widgets import PushButton
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def test_button_comprehensive() -> None:
|
|
9
|
+
"""Test PushButton with comprehensive client-widget interaction verification."""
|
|
10
|
+
widget = PushButton('Click Me')
|
|
11
|
+
find_button_text = 'document.querySelector(".rio-button .rio-text").children[0].innerText'
|
|
12
|
+
|
|
13
|
+
clicked_calls = []
|
|
14
|
+
|
|
15
|
+
def clicked_handler():
|
|
16
|
+
clicked_calls.append(True)
|
|
17
|
+
|
|
18
|
+
widget.clicked_connect(clicked_handler)
|
|
19
|
+
|
|
20
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
21
|
+
await asyncio.sleep(0.5)
|
|
22
|
+
|
|
23
|
+
# 1) Verify client shows widget value
|
|
24
|
+
assert widget['content'] == 'Click Me'
|
|
25
|
+
client_text = await test_client.execute_js(find_button_text)
|
|
26
|
+
assert client_text == 'Click Me'
|
|
27
|
+
|
|
28
|
+
# 2) Modify client value (user clicking button)
|
|
29
|
+
await test_client.click(10, 10) # Click on the button
|
|
30
|
+
|
|
31
|
+
# 3) Verify widget reflects client value (click handler called)
|
|
32
|
+
assert len(clicked_calls) == 1
|
|
33
|
+
assert clicked_calls[0] is True
|
|
34
|
+
|
|
35
|
+
# Test another click
|
|
36
|
+
await test_client.click(10, 10)
|
|
37
|
+
assert len(clicked_calls) == 2
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
async def test_button_disabled_interaction() -> None:
|
|
41
|
+
"""Test PushButton disabled state blocks user interaction."""
|
|
42
|
+
widget = PushButton('Test Button')
|
|
43
|
+
|
|
44
|
+
clicked_calls = []
|
|
45
|
+
|
|
46
|
+
def clicked_handler():
|
|
47
|
+
clicked_calls.append(True)
|
|
48
|
+
|
|
49
|
+
widget.clicked_connect(clicked_handler)
|
|
50
|
+
|
|
51
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
52
|
+
await asyncio.sleep(0.5)
|
|
53
|
+
|
|
54
|
+
# Test initial enabled state - clicks should work
|
|
55
|
+
await test_client.click(10, 10)
|
|
56
|
+
assert len(clicked_calls) == 1
|
|
57
|
+
|
|
58
|
+
# Disable widget
|
|
59
|
+
widget.set_enabled(False)
|
|
60
|
+
await test_client.wait_for_refresh()
|
|
61
|
+
assert not widget['is_sensitive']
|
|
62
|
+
|
|
63
|
+
# Test that clicks are blocked when disabled
|
|
64
|
+
await test_client.click(10, 10)
|
|
65
|
+
assert len(clicked_calls) == 1 # No additional calls
|
|
66
|
+
|
|
67
|
+
# Re-enable widget
|
|
68
|
+
widget.set_enabled(True)
|
|
69
|
+
await test_client.wait_for_refresh()
|
|
70
|
+
assert widget['is_sensitive']
|
|
71
|
+
|
|
72
|
+
# Test that clicks work again
|
|
73
|
+
await test_client.click(10, 10)
|
|
74
|
+
assert len(clicked_calls) == 2
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def test_button_basic_functionality() -> None:
|
|
78
|
+
"""Test PushButton basic functionality."""
|
|
79
|
+
widget = PushButton('Test Button')
|
|
80
|
+
|
|
81
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
82
|
+
await asyncio.sleep(0.5)
|
|
83
|
+
|
|
84
|
+
# Test initial state
|
|
85
|
+
assert widget['content'] == 'Test Button'
|
|
86
|
+
assert widget['is_sensitive']
|
|
87
|
+
|
|
88
|
+
# Test enabled/disabled state with timeout protection
|
|
89
|
+
widget.set_enabled(False)
|
|
90
|
+
await test_client.wait_for_refresh()
|
|
91
|
+
assert not widget['is_sensitive']
|
|
92
|
+
|
|
93
|
+
widget.set_enabled(True)
|
|
94
|
+
await test_client.wait_for_refresh()
|
|
95
|
+
assert widget['is_sensitive']
|
|
96
|
+
|
|
97
|
+
# Test flat style changes with timeout protection
|
|
98
|
+
assert not await test_client.execute_js('document.querySelector(".rio-buttonstyle-plain-text")')
|
|
99
|
+
widget.set_flat(True)
|
|
100
|
+
await test_client.wait_for_refresh()
|
|
101
|
+
assert await test_client.execute_js('document.querySelector(".rio-buttonstyle-plain-text")')
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import rio.testing.browser_client
|
|
4
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
5
|
+
from ui_10x.rio.widgets.button_group import ButtonGroup, RadioButton
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def test_button_group() -> None:
|
|
9
|
+
group = ButtonGroup()
|
|
10
|
+
btn1 = RadioButton(label='A', value='A')
|
|
11
|
+
btn2 = RadioButton(label='B', value='B')
|
|
12
|
+
group.add_button(btn1, 0)
|
|
13
|
+
group.add_button(btn2, 1)
|
|
14
|
+
|
|
15
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(group)) as test_client:
|
|
16
|
+
await asyncio.sleep(0.5)
|
|
17
|
+
# Initially, nothing selected
|
|
18
|
+
assert group.checked_id() == -1
|
|
19
|
+
|
|
20
|
+
# Select first button
|
|
21
|
+
btn1.set_checked(True)
|
|
22
|
+
await test_client.wait_for_refresh()
|
|
23
|
+
assert group.checked_id() == 0
|
|
24
|
+
|
|
25
|
+
# Select second button
|
|
26
|
+
btn2.set_checked(True)
|
|
27
|
+
await test_client.wait_for_refresh()
|
|
28
|
+
assert group.checked_id() == 1
|
|
29
|
+
|
|
30
|
+
# Deselect second button
|
|
31
|
+
btn2.set_checked(False)
|
|
32
|
+
await test_client.wait_for_refresh()
|
|
33
|
+
assert group.checked_id() == -1
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from datetime import date
|
|
3
|
+
|
|
4
|
+
import dateutil.parser
|
|
5
|
+
import rio.testing
|
|
6
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
7
|
+
from ui_10x.rio.widgets import CalendarWidget
|
|
8
|
+
|
|
9
|
+
find_selected_date = (
|
|
10
|
+
'document.querySelector(".rio-calendar-selected-day").textContent + " " + document.querySelector(".rio-calendar-year-month-display").textContent'
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def verify_content(widget, test_client):
|
|
15
|
+
selected_date = await test_client.execute_js(find_selected_date)
|
|
16
|
+
|
|
17
|
+
assert dateutil.parser.parse(selected_date).date() == widget.selected_date()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def test_calendar_comprehensive() -> None:
|
|
21
|
+
"""Test CalendarWidget with comprehensive client-widget interaction verification."""
|
|
22
|
+
widget = CalendarWidget()
|
|
23
|
+
test_date = date(2024, 6, 15)
|
|
24
|
+
|
|
25
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
26
|
+
await asyncio.sleep(0.5)
|
|
27
|
+
|
|
28
|
+
# 1) Verify client shows widget value (initial state)
|
|
29
|
+
assert widget.selected_date() == date.today()
|
|
30
|
+
|
|
31
|
+
# Verify client shows the expected date
|
|
32
|
+
await verify_content(widget, test_client)
|
|
33
|
+
|
|
34
|
+
# 2) Modify widget value and verify client reflects it
|
|
35
|
+
widget.set_selected_date(test_date)
|
|
36
|
+
await test_client.wait_for_refresh()
|
|
37
|
+
assert widget.selected_date() == test_date
|
|
38
|
+
|
|
39
|
+
# Verify client shows the expected date
|
|
40
|
+
await verify_content(widget, test_client)
|
|
41
|
+
|
|
42
|
+
# Test another date change
|
|
43
|
+
new_date = date(2024, 8, 20)
|
|
44
|
+
widget.set_selected_date(new_date)
|
|
45
|
+
await test_client.wait_for_refresh()
|
|
46
|
+
assert widget.selected_date() == new_date
|
|
47
|
+
|
|
48
|
+
# Verify client shows the new expected date
|
|
49
|
+
await verify_content(widget, test_client)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def test_calendar_disabled_interaction() -> None:
|
|
53
|
+
"""Test CalendarWidget disabled state."""
|
|
54
|
+
widget = CalendarWidget()
|
|
55
|
+
|
|
56
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
57
|
+
await asyncio.sleep(0.5)
|
|
58
|
+
|
|
59
|
+
# Test initial enabled state
|
|
60
|
+
assert widget['is_sensitive']
|
|
61
|
+
|
|
62
|
+
# Disable widget
|
|
63
|
+
widget.set_enabled(False)
|
|
64
|
+
await test_client.wait_for_refresh()
|
|
65
|
+
assert not widget['is_sensitive']
|
|
66
|
+
await verify_content(widget, test_client)
|
|
67
|
+
|
|
68
|
+
# Test that date changes still work (programmatic changes are allowed)
|
|
69
|
+
widget.set_selected_date(date(2024, 12, 25))
|
|
70
|
+
await test_client.wait_for_refresh()
|
|
71
|
+
assert widget.selected_date() == date(2024, 12, 25)
|
|
72
|
+
|
|
73
|
+
# Verify client shows the expected date even when disabled
|
|
74
|
+
await verify_content(widget, test_client)
|
|
75
|
+
|
|
76
|
+
# Re-enable widget
|
|
77
|
+
widget.set_enabled(True)
|
|
78
|
+
await test_client.wait_for_refresh()
|
|
79
|
+
assert widget['is_sensitive']
|
|
80
|
+
|
|
81
|
+
# Test that date changes continue to work
|
|
82
|
+
widget.set_selected_date(date(2024, 1, 1))
|
|
83
|
+
await test_client.wait_for_refresh()
|
|
84
|
+
assert widget.selected_date() == date(2024, 1, 1)
|
|
85
|
+
|
|
86
|
+
# Verify client shows the final expected date
|
|
87
|
+
await verify_content(widget, test_client)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
async def test_calendar_basic_functionality() -> None:
|
|
91
|
+
"""Test CalendarWidget basic functionality."""
|
|
92
|
+
widget = CalendarWidget()
|
|
93
|
+
|
|
94
|
+
async with rio.testing.DummyClient(lambda: DynamicComponent(widget)) as test_client:
|
|
95
|
+
await asyncio.sleep(0.5)
|
|
96
|
+
|
|
97
|
+
# Test initial state
|
|
98
|
+
assert widget is not None
|
|
99
|
+
assert widget['is_sensitive']
|
|
100
|
+
|
|
101
|
+
# Test date setting
|
|
102
|
+
test_date = date(2024, 3, 10)
|
|
103
|
+
widget.set_selected_date(test_date)
|
|
104
|
+
await test_client.wait_for_refresh()
|
|
105
|
+
assert widget.selected_date() == test_date
|
|
106
|
+
|
|
107
|
+
# Test enabled/disabled state
|
|
108
|
+
widget.set_enabled(False)
|
|
109
|
+
await test_client.wait_for_refresh()
|
|
110
|
+
assert not widget['is_sensitive']
|
|
111
|
+
|
|
112
|
+
widget.set_enabled(True)
|
|
113
|
+
await test_client.wait_for_refresh()
|
|
114
|
+
assert widget['is_sensitive']
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import rio.testing
|
|
4
|
+
from ui_10x.rio.component_builder import DynamicComponent
|
|
5
|
+
from ui_10x.rio.widgets import CheckBox
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def test_checkbox_comprehensive() -> None:
|
|
9
|
+
"""Test CheckBox with comprehensive client-widget interaction verification."""
|
|
10
|
+
widget = CheckBox('Check me')
|
|
11
|
+
find_checkbox = 'document.querySelector("input[type=\'checkbox\']")'
|
|
12
|
+
|
|
13
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
14
|
+
await asyncio.sleep(0.5)
|
|
15
|
+
|
|
16
|
+
# 1) Verify client shows widget value (unchecked initially)
|
|
17
|
+
assert not widget.is_checked()
|
|
18
|
+
client_checked = await test_client.execute_js(find_checkbox + '.checked')
|
|
19
|
+
assert client_checked is False
|
|
20
|
+
|
|
21
|
+
# 2) Modify client value (user clicking checkbox)
|
|
22
|
+
await test_client.execute_js(find_checkbox + '.click();')
|
|
23
|
+
await asyncio.sleep(0.5) # Wait for event processing
|
|
24
|
+
|
|
25
|
+
# 3) Verify widget reflects client value
|
|
26
|
+
assert widget.is_checked()
|
|
27
|
+
client_checked = await test_client.execute_js(find_checkbox + '.checked')
|
|
28
|
+
assert client_checked is True
|
|
29
|
+
|
|
30
|
+
# Test widget changes propagate to client
|
|
31
|
+
widget.set_checked(False)
|
|
32
|
+
await test_client.wait_for_refresh()
|
|
33
|
+
client_checked = await test_client.execute_js(find_checkbox + '.checked')
|
|
34
|
+
assert client_checked is False
|
|
35
|
+
assert not widget.is_checked()
|
|
36
|
+
|
|
37
|
+
# Test another client interaction
|
|
38
|
+
await test_client.execute_js(find_checkbox + '.click();')
|
|
39
|
+
await asyncio.sleep(0.5)
|
|
40
|
+
assert widget.is_checked()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def test_checkbox_disabled_interaction() -> None:
|
|
44
|
+
"""Test CheckBox disabled state blocks user interaction."""
|
|
45
|
+
widget = CheckBox('Test Checkbox')
|
|
46
|
+
find_checkbox = 'document.querySelector("input[type=\'checkbox\']")'
|
|
47
|
+
|
|
48
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
49
|
+
await asyncio.sleep(0.5)
|
|
50
|
+
|
|
51
|
+
# Test initial enabled state - clicks should work
|
|
52
|
+
await test_client.execute_js(find_checkbox + '.click();')
|
|
53
|
+
await asyncio.sleep(0.5)
|
|
54
|
+
assert widget.is_checked()
|
|
55
|
+
|
|
56
|
+
# Disable widget
|
|
57
|
+
widget.set_enabled(False)
|
|
58
|
+
await test_client.wait_for_refresh()
|
|
59
|
+
|
|
60
|
+
# Verify client shows disabled state
|
|
61
|
+
client_disabled = await test_client.execute_js(find_checkbox + '.disabled')
|
|
62
|
+
assert client_disabled is True
|
|
63
|
+
|
|
64
|
+
# Test that clicks are blocked when disabled
|
|
65
|
+
initial_checked = widget.is_checked()
|
|
66
|
+
await test_client.execute_js(find_checkbox + '.click();')
|
|
67
|
+
await asyncio.sleep(0.5)
|
|
68
|
+
assert widget.is_checked() == initial_checked # State should not change
|
|
69
|
+
|
|
70
|
+
# Re-enable widget
|
|
71
|
+
widget.set_enabled(True)
|
|
72
|
+
await test_client.wait_for_refresh()
|
|
73
|
+
|
|
74
|
+
# Verify client shows enabled state
|
|
75
|
+
client_disabled = await test_client.execute_js(find_checkbox + '.disabled')
|
|
76
|
+
assert client_disabled is False
|
|
77
|
+
|
|
78
|
+
# Test that clicks work again
|
|
79
|
+
await test_client.execute_js(find_checkbox + '.click();')
|
|
80
|
+
await asyncio.sleep(0.5)
|
|
81
|
+
assert not widget.is_checked() # Should toggle
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def test_checkbox_basic_functionality() -> None:
|
|
85
|
+
"""Test CheckBox basic functionality without client interaction."""
|
|
86
|
+
widget = CheckBox('Test Checkbox')
|
|
87
|
+
|
|
88
|
+
async with rio.testing.BrowserClient(lambda: DynamicComponent(widget)) as test_client:
|
|
89
|
+
await asyncio.sleep(0.5)
|
|
90
|
+
|
|
91
|
+
# Test initial state
|
|
92
|
+
assert not widget.is_checked()
|
|
93
|
+
|
|
94
|
+
# Test checking
|
|
95
|
+
widget.set_checked(True)
|
|
96
|
+
await test_client.wait_for_refresh()
|
|
97
|
+
assert widget.is_checked()
|
|
98
|
+
|
|
99
|
+
# Test unchecking
|
|
100
|
+
widget.set_checked(False)
|
|
101
|
+
await test_client.wait_for_refresh()
|
|
102
|
+
assert not widget.is_checked()
|
|
103
|
+
|
|
104
|
+
# Test enabled/disabled state
|
|
105
|
+
widget.set_enabled(False)
|
|
106
|
+
await test_client.wait_for_refresh()
|
|
107
|
+
|
|
108
|
+
widget.set_enabled(True)
|
|
109
|
+
await test_client.wait_for_refresh()
|