bec-widgets 0.62.0__py3-none-any.whl → 0.63.0__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.
- CHANGELOG.md +25 -21
- PKG-INFO +1 -1
- bec_widgets/cli/client.py +43 -0
- bec_widgets/cli/client_utils.py +34 -62
- bec_widgets/cli/rpc_wigdet_handler.py +2 -0
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +5 -6
- bec_widgets/utils/bec_dispatcher.py +1 -5
- bec_widgets/widgets/text_box/__init__.py +0 -0
- bec_widgets/widgets/text_box/text_box.py +127 -0
- {bec_widgets-0.62.0.dist-info → bec_widgets-0.63.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.62.0.dist-info → bec_widgets-0.63.0.dist-info}/RECORD +18 -14
- docs/user/widgets/text_box.md +33 -0
- docs/user/widgets/widgets.md +1 -0
- pyproject.toml +1 -1
- tests/unit_tests/test_text_box_widget.py +55 -0
- {bec_widgets-0.62.0.dist-info → bec_widgets-0.63.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.62.0.dist-info → bec_widgets-0.63.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.62.0.dist-info → bec_widgets-0.63.0.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## v0.63.0 (2024-06-13)
|
6
|
+
|
7
|
+
### Documentation
|
8
|
+
|
9
|
+
* docs: add documentation ([`bc709c4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bc709c4184c985d4e721f9ea7d1b3dad5e9153a7))
|
10
|
+
|
11
|
+
### Feature
|
12
|
+
|
13
|
+
* feat: add textbox widget ([`d9d4e3c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d9d4e3c9bf73ab2a5629c2867b50fc91e69489ec))
|
14
|
+
|
15
|
+
### Refactor
|
16
|
+
|
17
|
+
* refactor: add pydantic config, add change_theme ([`6b8432f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6b8432f5b20a71175a3537b5f6832b76e3b67d73))
|
18
|
+
|
19
|
+
### Test
|
20
|
+
|
21
|
+
* test: add test for text box ([`b49462a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b49462abeb186e56bac79d2ef0b0add1ef28a1a5))
|
22
|
+
|
23
|
+
### Unknown
|
24
|
+
|
25
|
+
* Revert "feat: implement non-polling, interruptible waiting of gui instruction response with timeout"
|
26
|
+
|
27
|
+
This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fe04dd80e59a0e74f7fdea603e0642707ecc7c2a))
|
28
|
+
|
29
|
+
|
5
30
|
## v0.62.0 (2024-06-12)
|
6
31
|
|
7
32
|
### Feature
|
@@ -142,24 +167,3 @@
|
|
142
167
|
|
143
168
|
|
144
169
|
## v0.57.5 (2024-06-06)
|
145
|
-
|
146
|
-
### Documentation
|
147
|
-
|
148
|
-
* docs(figure): docs adjusted to be compatible with new signature ([`c037b87`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c037b87675af91b26e8c7c60e76622d4ed4cf5d5))
|
149
|
-
|
150
|
-
### Fix
|
151
|
-
|
152
|
-
* fix(waveform): added .plot method with the same signature as BECFigure.plot ([`8479caf`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8479caf53a7325788ca264e5bd9aee01f1d4c5a0))
|
153
|
-
|
154
|
-
* fix(plot_base): .plot removed from plot_base.py, because there is no use case for it ([`82e2c89`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/82e2c898d2e26f786b2d481f85c647472675e75b))
|
155
|
-
|
156
|
-
### Refactor
|
157
|
-
|
158
|
-
* refactor(figure): logic for .add_image and .image consolidated; logic for .add_plot and .plot consolidated ([`52bc322`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/52bc322b2b8d3ef92ff3480e61bddaf32464f976))
|
159
|
-
|
160
|
-
|
161
|
-
## v0.57.4 (2024-06-06)
|
162
|
-
|
163
|
-
### Fix
|
164
|
-
|
165
|
-
* fix(docks): set_title do update dock internal _name now ([`15cbc21`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/15cbc21e5bb3cf85f5822d44a2b3665b5aa2f346))
|
PKG-INFO
CHANGED
bec_widgets/cli/client.py
CHANGED
@@ -17,6 +17,7 @@ class Widgets(str, enum.Enum):
|
|
17
17
|
BECDockArea = "BECDockArea"
|
18
18
|
BECFigure = "BECFigure"
|
19
19
|
SpiralProgressBar = "SpiralProgressBar"
|
20
|
+
TextBox = "TextBox"
|
20
21
|
WebsiteWidget = "WebsiteWidget"
|
21
22
|
|
22
23
|
|
@@ -1897,6 +1898,48 @@ class SpiralProgressBar(RPCBase):
|
|
1897
1898
|
"""
|
1898
1899
|
|
1899
1900
|
|
1901
|
+
class StopButton(RPCBase):
|
1902
|
+
@property
|
1903
|
+
@rpc_call
|
1904
|
+
def config_dict(self) -> "dict":
|
1905
|
+
"""
|
1906
|
+
Get the configuration of the widget.
|
1907
|
+
|
1908
|
+
Returns:
|
1909
|
+
dict: The configuration of the widget.
|
1910
|
+
"""
|
1911
|
+
|
1912
|
+
@rpc_call
|
1913
|
+
def get_all_rpc(self) -> "dict":
|
1914
|
+
"""
|
1915
|
+
Get all registered RPC objects.
|
1916
|
+
"""
|
1917
|
+
|
1918
|
+
|
1919
|
+
class TextBox(RPCBase):
|
1920
|
+
@rpc_call
|
1921
|
+
def set_color(self, background_color: str, font_color: str) -> None:
|
1922
|
+
"""
|
1923
|
+
Set the background color of the Widget.
|
1924
|
+
|
1925
|
+
Args:
|
1926
|
+
background_color (str): The color to set the background in HEX.
|
1927
|
+
font_color (str): The color to set the font in HEX.
|
1928
|
+
"""
|
1929
|
+
|
1930
|
+
@rpc_call
|
1931
|
+
def set_text(self, text: str) -> None:
|
1932
|
+
"""
|
1933
|
+
Set the text of the Widget
|
1934
|
+
"""
|
1935
|
+
|
1936
|
+
@rpc_call
|
1937
|
+
def set_font_size(self, size: int) -> None:
|
1938
|
+
"""
|
1939
|
+
Set the font size of the text in the Widget.
|
1940
|
+
"""
|
1941
|
+
|
1942
|
+
|
1900
1943
|
class WebsiteWidget(RPCBase):
|
1901
1944
|
@rpc_call
|
1902
1945
|
def set_url(self, url: str) -> None:
|
bec_widgets/cli/client_utils.py
CHANGED
@@ -14,7 +14,7 @@ from typing import TYPE_CHECKING
|
|
14
14
|
|
15
15
|
from bec_lib.endpoints import MessageEndpoints
|
16
16
|
from bec_lib.utils.import_utils import isinstance_based_on_class_name, lazy_import, lazy_import_from
|
17
|
-
from qtpy.QtCore import
|
17
|
+
from qtpy.QtCore import QCoreApplication
|
18
18
|
|
19
19
|
import bec_widgets.cli.client as client
|
20
20
|
from bec_widgets.cli.auto_updates import AutoUpdates
|
@@ -24,8 +24,6 @@ if TYPE_CHECKING:
|
|
24
24
|
|
25
25
|
from bec_widgets.cli.client import BECDockArea, BECFigure
|
26
26
|
|
27
|
-
from bec_lib.serialization import MsgpackSerialization
|
28
|
-
|
29
27
|
messages = lazy_import("bec_lib.messages")
|
30
28
|
# from bec_lib.connector import MessageObject
|
31
29
|
MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
|
@@ -207,48 +205,6 @@ class RPCResponseTimeoutError(Exception):
|
|
207
205
|
)
|
208
206
|
|
209
207
|
|
210
|
-
class QtRedisMessageWaiter:
|
211
|
-
def __init__(self, redis_connector, message_to_wait):
|
212
|
-
self.ev_loop = QEventLoop()
|
213
|
-
self.response = None
|
214
|
-
self.connector = redis_connector
|
215
|
-
self.message_to_wait = message_to_wait
|
216
|
-
self.pubsub = redis_connector._redis_conn.pubsub()
|
217
|
-
self.pubsub.subscribe(self.message_to_wait.endpoint)
|
218
|
-
fd = self.pubsub.connection._sock.fileno()
|
219
|
-
self.notifier = QSocketNotifier(fd, QSocketNotifier.Read)
|
220
|
-
self.notifier.activated.connect(self._pubsub_readable)
|
221
|
-
|
222
|
-
def _msg_received(self, msg_obj):
|
223
|
-
self.response = msg_obj.value
|
224
|
-
self.ev_loop.quit()
|
225
|
-
|
226
|
-
def wait(self, timeout=1):
|
227
|
-
timer = QTimer()
|
228
|
-
timer.singleShot(timeout * 1000, self.ev_loop.quit)
|
229
|
-
self.ev_loop.exec_()
|
230
|
-
timer.stop()
|
231
|
-
self.notifier.setEnabled(False)
|
232
|
-
self.pubsub.close()
|
233
|
-
return self.response
|
234
|
-
|
235
|
-
def _pubsub_readable(self, fd):
|
236
|
-
while True:
|
237
|
-
msg = self.pubsub.get_message()
|
238
|
-
if msg:
|
239
|
-
if msg["type"] == "subscribe":
|
240
|
-
# get_message buffers, so we may already have the answer
|
241
|
-
# let's check...
|
242
|
-
continue
|
243
|
-
else:
|
244
|
-
break
|
245
|
-
else:
|
246
|
-
return
|
247
|
-
channel = msg["channel"].decode()
|
248
|
-
msg = MessageObject(topic=channel, value=MsgpackSerialization.loads(msg["data"]))
|
249
|
-
self.connector._execute_callback(self._msg_received, msg, {})
|
250
|
-
|
251
|
-
|
252
208
|
class RPCBase:
|
253
209
|
def __init__(self, gui_id: str = None, config: dict = None, parent=None) -> None:
|
254
210
|
self._client = BECDispatcher().client
|
@@ -275,7 +231,7 @@ class RPCBase:
|
|
275
231
|
parent = parent._parent
|
276
232
|
return parent
|
277
233
|
|
278
|
-
def _run_rpc(self, method, *args, wait_for_rpc_response=True,
|
234
|
+
def _run_rpc(self, method, *args, wait_for_rpc_response=True, **kwargs):
|
279
235
|
"""
|
280
236
|
Run the RPC call.
|
281
237
|
|
@@ -297,24 +253,16 @@ class RPCBase:
|
|
297
253
|
|
298
254
|
# pylint: disable=protected-access
|
299
255
|
receiver = self._root._gui_id
|
300
|
-
if wait_for_rpc_response:
|
301
|
-
redis_msg = QtRedisMessageWaiter(
|
302
|
-
self._client.connector, MessageEndpoints.gui_instruction_response(request_id)
|
303
|
-
)
|
304
|
-
|
305
256
|
self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
|
306
257
|
|
307
|
-
if wait_for_rpc_response:
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
raise ValueError(response.message["error"])
|
316
|
-
msg_result = response.message.get("result")
|
317
|
-
return self._create_widget_from_msg_result(msg_result)
|
258
|
+
if not wait_for_rpc_response:
|
259
|
+
return None
|
260
|
+
response = self._wait_for_response(request_id)
|
261
|
+
# get class name
|
262
|
+
if not response.content["accepted"]:
|
263
|
+
raise ValueError(response.content["message"]["error"])
|
264
|
+
msg_result = response.content["message"].get("result")
|
265
|
+
return self._create_widget_from_msg_result(msg_result)
|
318
266
|
|
319
267
|
def _create_widget_from_msg_result(self, msg_result):
|
320
268
|
if msg_result is None:
|
@@ -337,6 +285,30 @@ class RPCBase:
|
|
337
285
|
return cls(parent=self, **msg_result)
|
338
286
|
return msg_result
|
339
287
|
|
288
|
+
def _wait_for_response(self, request_id: str, timeout: int = 5):
|
289
|
+
"""
|
290
|
+
Wait for the response from the server.
|
291
|
+
|
292
|
+
Args:
|
293
|
+
request_id(str): The request ID.
|
294
|
+
timeout(int): The timeout in seconds.
|
295
|
+
|
296
|
+
Returns:
|
297
|
+
The response from the server.
|
298
|
+
"""
|
299
|
+
start_time = time.time()
|
300
|
+
response = None
|
301
|
+
|
302
|
+
while response is None and self.gui_is_alive() and (time.time() - start_time) < timeout:
|
303
|
+
response = self._client.connector.get(
|
304
|
+
MessageEndpoints.gui_instruction_response(request_id)
|
305
|
+
)
|
306
|
+
QCoreApplication.processEvents() # keep UI responsive (and execute signals/slots)
|
307
|
+
if response is None and (time.time() - start_time) >= timeout:
|
308
|
+
raise RPCResponseTimeoutError(request_id, timeout)
|
309
|
+
|
310
|
+
return response
|
311
|
+
|
340
312
|
def gui_is_alive(self):
|
341
313
|
"""
|
342
314
|
Check if the GUI is alive.
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from bec_widgets.utils import BECConnector
|
2
2
|
from bec_widgets.widgets.figure import BECFigure
|
3
3
|
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
4
|
+
from bec_widgets.widgets.text_box.text_box import TextBox
|
4
5
|
from bec_widgets.widgets.website.website import WebsiteWidget
|
5
6
|
|
6
7
|
|
@@ -11,6 +12,7 @@ class RPCWidgetHandler:
|
|
11
12
|
"BECFigure": BECFigure,
|
12
13
|
"SpiralProgressBar": SpiralProgressBar,
|
13
14
|
"Website": WebsiteWidget,
|
15
|
+
"TextBox": TextBox,
|
14
16
|
}
|
15
17
|
|
16
18
|
@staticmethod
|
@@ -136,18 +136,17 @@ if __name__ == "__main__": # pragma: no cover
|
|
136
136
|
|
137
137
|
module_path = os.path.dirname(bec_widgets.__file__)
|
138
138
|
|
139
|
+
bec_dispatcher = BECDispatcher()
|
140
|
+
client = bec_dispatcher.client
|
141
|
+
client.start()
|
142
|
+
|
139
143
|
app = QApplication(sys.argv)
|
140
144
|
app.setApplicationName("Jupyter Console")
|
141
145
|
app.setApplicationDisplayName("Jupyter Console")
|
142
|
-
qdarktheme.setup_theme("auto")
|
146
|
+
# qdarktheme.setup_theme("auto")
|
143
147
|
icon = QIcon()
|
144
148
|
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
|
145
149
|
app.setWindowIcon(icon)
|
146
|
-
|
147
|
-
bec_dispatcher = BECDispatcher()
|
148
|
-
client = bec_dispatcher.client
|
149
|
-
client.start()
|
150
|
-
|
151
150
|
win = JupyterConsoleWindow()
|
152
151
|
win.show()
|
153
152
|
|
@@ -9,7 +9,7 @@ import redis
|
|
9
9
|
from bec_lib.client import BECClient
|
10
10
|
from bec_lib.redis_connector import MessageObject, RedisConnector
|
11
11
|
from bec_lib.service_config import ServiceConfig
|
12
|
-
from qtpy.QtCore import
|
12
|
+
from qtpy.QtCore import QObject
|
13
13
|
from qtpy.QtCore import Signal as pyqtSignal
|
14
14
|
|
15
15
|
if TYPE_CHECKING:
|
@@ -71,7 +71,6 @@ class BECDispatcher:
|
|
71
71
|
|
72
72
|
_instance = None
|
73
73
|
_initialized = False
|
74
|
-
qapp = None
|
75
74
|
|
76
75
|
def __new__(cls, client=None, config: str = None, *args, **kwargs):
|
77
76
|
if cls._instance is None:
|
@@ -83,9 +82,6 @@ class BECDispatcher:
|
|
83
82
|
if self._initialized:
|
84
83
|
return
|
85
84
|
|
86
|
-
if not QCoreApplication.instance():
|
87
|
-
BECDispatcher.qapp = QCoreApplication([])
|
88
|
-
|
89
85
|
self._slots = collections.defaultdict(set)
|
90
86
|
self.client = client
|
91
87
|
|
File without changes
|
@@ -0,0 +1,127 @@
|
|
1
|
+
import re
|
2
|
+
|
3
|
+
from pydantic import Field, field_validator
|
4
|
+
from qtpy.QtWidgets import QTextEdit
|
5
|
+
|
6
|
+
from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
|
7
|
+
from bec_widgets.utils.colors import Colors
|
8
|
+
|
9
|
+
|
10
|
+
class TextBoxConfig(ConnectionConfig):
|
11
|
+
|
12
|
+
theme: str = Field("dark", description="The theme of the figure widget.")
|
13
|
+
font_color: str = Field("#FFF", description="The font color of the text")
|
14
|
+
background_color: str = Field("#000", description="The background color of the widget.")
|
15
|
+
font_size: int = Field(16, description="The font size of the text in the widget.")
|
16
|
+
text: str = Field("", description="The text to display in the widget.")
|
17
|
+
|
18
|
+
@classmethod
|
19
|
+
@field_validator("theme")
|
20
|
+
def validate_theme(cls, v):
|
21
|
+
"""Validate the theme of the figure widget."""
|
22
|
+
if v not in ["dark", "light"]:
|
23
|
+
raise ValueError("Theme must be either 'dark' or 'light'")
|
24
|
+
return v
|
25
|
+
|
26
|
+
_validate_font_color = field_validator("font_color")(Colors.validate_color)
|
27
|
+
_validate_background_color = field_validator("background_color")(Colors.validate_color)
|
28
|
+
|
29
|
+
|
30
|
+
class TextBox(BECConnector, QTextEdit):
|
31
|
+
|
32
|
+
USER_ACCESS = ["set_color", "set_text", "set_font_size"]
|
33
|
+
|
34
|
+
def __init__(self, text: str = "", parent=None, client=None, config=None, gui_id=None):
|
35
|
+
if config is None:
|
36
|
+
config = TextBoxConfig(widget_class=self.__class__.__name__)
|
37
|
+
else:
|
38
|
+
if isinstance(config, dict):
|
39
|
+
config = TextBoxConfig(**config)
|
40
|
+
self.config = config
|
41
|
+
super().__init__(client=client, config=config, gui_id=gui_id)
|
42
|
+
QTextEdit.__init__(self, parent=parent)
|
43
|
+
|
44
|
+
self.config = config
|
45
|
+
self.setReadOnly(True)
|
46
|
+
self.setGeometry(self.rect())
|
47
|
+
self.set_color(self.config.background_color, self.config.font_color)
|
48
|
+
if not text:
|
49
|
+
text = "<h1>Welcome to the BEC Widget TextBox</h1><p>A widget that allows user to display text in plain and HTML format.</p><p>This is an example of displaying HTML text.</p>"
|
50
|
+
self.set_text(text)
|
51
|
+
|
52
|
+
def change_theme(self) -> None:
|
53
|
+
"""
|
54
|
+
Change the theme of the figure widget.
|
55
|
+
"""
|
56
|
+
if self.config.theme == "dark":
|
57
|
+
theme = "light"
|
58
|
+
font_color = "#000"
|
59
|
+
background_color = "#FFF"
|
60
|
+
else:
|
61
|
+
theme = "dark"
|
62
|
+
font_color = "#FFF"
|
63
|
+
background_color = "#000"
|
64
|
+
self.config.theme = theme
|
65
|
+
self.set_color(background_color, font_color)
|
66
|
+
|
67
|
+
def set_color(self, background_color: str, font_color: str) -> None:
|
68
|
+
"""Set the background color of the widget.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
background_color (str): The color to set the background in HEX.
|
72
|
+
font_color (str): The color to set the font in HEX.
|
73
|
+
|
74
|
+
"""
|
75
|
+
self.config.background_color = background_color
|
76
|
+
self.config.font_color = font_color
|
77
|
+
self._update_stylesheet()
|
78
|
+
|
79
|
+
def set_font_size(self, size: int) -> None:
|
80
|
+
"""Set the font size of the text in the widget.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
size (int): The font size to set.
|
84
|
+
"""
|
85
|
+
self.config.font_size = size
|
86
|
+
self._update_stylesheet()
|
87
|
+
|
88
|
+
def _update_stylesheet(self):
|
89
|
+
"""Update the stylesheet of the widget."""
|
90
|
+
self.setStyleSheet(
|
91
|
+
f"background-color: {self.config.background_color}; color: {self.config.font_color}; font-size: {self.config.font_size}px"
|
92
|
+
)
|
93
|
+
|
94
|
+
def set_text(self, text: str) -> None:
|
95
|
+
"""Set the text of the widget.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
text (str): The text to set.
|
99
|
+
"""
|
100
|
+
if self.is_html(text):
|
101
|
+
self.setHtml(text)
|
102
|
+
else:
|
103
|
+
self.setPlainText(text)
|
104
|
+
self.config.text = text
|
105
|
+
|
106
|
+
def is_html(self, text: str) -> bool:
|
107
|
+
"""Check if the text contains HTML tags.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
text (str): The text to check.
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
bool: True if the text contains HTML tags, False otherwise.
|
114
|
+
"""
|
115
|
+
return bool(re.search(r"<[a-zA-Z/][^>]*>", text))
|
116
|
+
|
117
|
+
|
118
|
+
if __name__ == "__main__":
|
119
|
+
import sys
|
120
|
+
|
121
|
+
from qtpy.QtWidgets import QApplication
|
122
|
+
|
123
|
+
app = QApplication(sys.argv)
|
124
|
+
|
125
|
+
widget = TextBox()
|
126
|
+
widget.show()
|
127
|
+
sys.exit(app.exec())
|
@@ -2,11 +2,11 @@
|
|
2
2
|
.gitlab-ci.yml,sha256=3PU2LONUl10zIOD4UCPQgA6vVBtniabww1MQkTMce7I,7995
|
3
3
|
.pylintrc,sha256=OstrgmEyP0smNFBKoIN5_26-UmNZgMHnbjvAWX0UrLs,18535
|
4
4
|
.readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
|
5
|
-
CHANGELOG.md,sha256=
|
5
|
+
CHANGELOG.md,sha256=SSIvLIsLoMqELDdBJGpxD-i6mL6yHf9zOfv5Sslx0ZA,6807
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=7zmXAhyzvbGnDsRQ9BIOv4jDaDOHgaiY6X2dXspqEM4,1302
|
8
8
|
README.md,sha256=y4jB6wvArS7N8_iTbKWnSM_oRAqLA2GqgzUR-FMh5sU,2645
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=sZcekDO1IZEFkY_FiioZBTW4i6p__x-iQpMLbVq_rqk,2115
|
10
10
|
.git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
|
11
11
|
.gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
|
12
12
|
.gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
|
@@ -17,22 +17,22 @@ bec_widgets/assets/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqgdX7a00nM3i
|
|
17
17
|
bec_widgets/assets/terminal_icon.png,sha256=bJl7Tft4Fi2uxvuXI8o14uMHnI9eAWKSU2uftXCH9ws,3889
|
18
18
|
bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
|
19
19
|
bec_widgets/cli/auto_updates.py,sha256=DyBV3HnjMSH-cvVkYNcDiYKVf0Xut4Qy2qGQqkW47Bw,4833
|
20
|
-
bec_widgets/cli/client.py,sha256=
|
21
|
-
bec_widgets/cli/client_utils.py,sha256=
|
20
|
+
bec_widgets/cli/client.py,sha256=PkKPeR4KJjJP-DOPTq3yYJIuWlwXLHjTyZunCYSsU1I,55332
|
21
|
+
bec_widgets/cli/client_utils.py,sha256=7u8P9EYgLPJuAcHxnFiZi-gCZohO3vAn0W7dqsSrs4M,10660
|
22
22
|
bec_widgets/cli/generate_cli.py,sha256=DIaGz7nhwef3ebIaP4LtiUC3q7MoM1swJ_e0SgAO2jo,6901
|
23
23
|
bec_widgets/cli/rpc_register.py,sha256=QxXUZu5XNg00Yf5O3UHWOXg3-f_pzKjjoZYMOa-MOJc,2216
|
24
|
-
bec_widgets/cli/rpc_wigdet_handler.py,sha256=
|
24
|
+
bec_widgets/cli/rpc_wigdet_handler.py,sha256=1oE2TSbwQdfLEaZiscyDX2eExHsenp2BF5Lwy8PE6LA,1118
|
25
25
|
bec_widgets/cli/server.py,sha256=rsj31Vsx6ayThNe4PQelQFahGjYXFZjfrNyB2fnm6Ro,5737
|
26
26
|
bec_widgets/examples/__init__.py,sha256=WWQ0cu7m8sA4Ehy-DWdTIqSISjaHsbxhsNmNrMnhDZU,202
|
27
27
|
bec_widgets/examples/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
|
-
bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=
|
28
|
+
bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=lViKNC3TOh6_-SztcKaRnYkf-V_EQ9T1cuyORskVX6c,5339
|
29
29
|
bec_widgets/examples/jupyter_console/jupyter_console_window.ui,sha256=2A2mNTUMZBYygz8K4qWzrcjnNqZBMVyeHm26iLZVRWI,1473
|
30
30
|
bec_widgets/examples/motor_movement/__init__.py,sha256=LzPJkxLAxOsZCbXR-fRCPmeYobp7Yqds6tDxW4W1gSw,214
|
31
31
|
bec_widgets/examples/motor_movement/motor_control_compilations.py,sha256=8rpA7a2xVZTDMrx7YQIj3IJew78J1gcVMkHvloS0U_Q,9055
|
32
32
|
bec_widgets/examples/motor_movement/motor_controller.ui,sha256=83XX6NGILwntoUIghvzWnMuGf80O8khK3SduVKTAEFM,29105
|
33
33
|
bec_widgets/utils/__init__.py,sha256=B7OZ2ArjyFaGNh4XYIbk49agnYCz704ltuFSalLCjSA,481
|
34
34
|
bec_widgets/utils/bec_connector.py,sha256=RxHJNF7JjtY5pRbTMu2eQTiRXvoyJ53QuTYxHjZba38,5357
|
35
|
-
bec_widgets/utils/bec_dispatcher.py,sha256=
|
35
|
+
bec_widgets/utils/bec_dispatcher.py,sha256=nLdcj2u4dy8-ZR03XioCzr7hBg9Wq4Kw58OU6sDorT4,5593
|
36
36
|
bec_widgets/utils/bec_table.py,sha256=nA2b8ukSeUfquFMAxGrUVOqdrzMoDYD6O_4EYbOG2zk,717
|
37
37
|
bec_widgets/utils/colors.py,sha256=GYSDe0ZxsJSwxvuy-yG2BH17qlf_Sjq8dhDcyp9IhBI,8532
|
38
38
|
bec_widgets/utils/container_utils.py,sha256=m3VUyAYmSWkEwApP9tBvKxPYVtc2kHw4toxIpMryJy4,1495
|
@@ -87,6 +87,8 @@ bec_widgets/widgets/scan_control/scan_control.py,sha256=B5n2U2iVtTCY3Tx93JyBqzGC
|
|
87
87
|
bec_widgets/widgets/spiral_progress_bar/__init__.py,sha256=4efbtcqCToMIw5bkQrTzy2TzuBCXvlhuUPh1bYC_Yzg,51
|
88
88
|
bec_widgets/widgets/spiral_progress_bar/ring.py,sha256=7i5oKpW8eUQGvLyKce2-2rlaGDVLec__DoWp6hfJlRw,10524
|
89
89
|
bec_widgets/widgets/spiral_progress_bar/spiral_progress_bar.py,sha256=cMi4g7zNTLrkkzZ9ChiIBTaqigDCYwzrgA2iRmq9dUI,24050
|
90
|
+
bec_widgets/widgets/text_box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
91
|
+
bec_widgets/widgets/text_box/text_box.py,sha256=kykQ_Zcxh8IGcPEP5-oGGQwoZEpY9vhxRIM8TY8kTYg,4240
|
90
92
|
bec_widgets/widgets/toolbar/__init__.py,sha256=d-TP4_cr_VbpwreMM4ePnfZ5YXsEPQ45ibEf75nuGoE,36
|
91
93
|
bec_widgets/widgets/toolbar/toolbar.py,sha256=e0zCD_0q7K4NVhrzD8001Qvfxt-VhqHTgofchS9NgCM,5125
|
92
94
|
bec_widgets/widgets/website/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -127,9 +129,10 @@ docs/user/widgets/motor.gif,sha256=FtaWdRHx4UZaGJPpq8LNhMMgX4PFcAB6IZ93JCMEh_w,2
|
|
127
129
|
docs/user/widgets/progress_bar.gif,sha256=5jh0Zw2BBGPuNxszV1DBLJCb4_6glIRX-U2ABjnsK2k,5263592
|
128
130
|
docs/user/widgets/scatter_2D.gif,sha256=yHpsuAUseMafJjI_J5BcOhmE3nu9VFn_Xm9XHzJaH5I,13188862
|
129
131
|
docs/user/widgets/spiral_progress_bar.md,sha256=QTgUDIl6XPuK_HwSfB6sNijZ4bss26biDg6B_mJ8Pxk,2208
|
132
|
+
docs/user/widgets/text_box.md,sha256=i40AxKJP0PxrYW0x0up1VIovPFvemsaZoosGjOn4iZE,931
|
130
133
|
docs/user/widgets/w1D.gif,sha256=tuHbleJpl6bJFNNC2OdndF5LF7IyfvlkFCMGZajrQPs,622773
|
131
134
|
docs/user/widgets/website.md,sha256=wfudAupdtHX-Sfritg0xMWXZLLczJ4XwMLNWvu6ww-w,705
|
132
|
-
docs/user/widgets/widgets.md,sha256=
|
135
|
+
docs/user/widgets/widgets.md,sha256=NzRfrgd4LWmZHa2Cs_1G59LeY5uAlFdy5aP00AtGAjk,380
|
133
136
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
134
137
|
tests/end-2-end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
135
138
|
tests/end-2-end/conftest.py,sha256=taLqiYVzOhJjMre5ypgQjB7wzSXP4soKANW3XfAjems,1773
|
@@ -154,6 +157,7 @@ tests/unit_tests/test_rpc_register.py,sha256=hECjZEimd440mwRrO0rg7L3PKN7__3DgjmE
|
|
154
157
|
tests/unit_tests/test_scan_control.py,sha256=7dtGpE0g4FqUhhQeCkyJl-9o7NH3DFZJgEaqDmBYbBc,7551
|
155
158
|
tests/unit_tests/test_spiral_progress_bar.py,sha256=yak3N9-TmEM3lQZPSROL4cAx9mior__se1XADlMScks,12418
|
156
159
|
tests/unit_tests/test_stop_button.py,sha256=hOoWO0emkvd5bR_EExxCnKsiZgXKqf_uIGTwzWLxhDw,704
|
160
|
+
tests/unit_tests/test_text_box_widget.py,sha256=cT0uEHt_6d-FwST0A_wE9sFW9E3F_nJbKhuBAeU4yHg,1862
|
157
161
|
tests/unit_tests/test_waveform1d.py,sha256=j9-CCE0BkFVI3Gnv8pjV1gc9HwA5PYG0_ox1oZ60F6w,15272
|
158
162
|
tests/unit_tests/test_website_widget.py,sha256=fBADIJJBAHU4Ro7u95kdemFVNv196UOcuO9oLHuHt8A,761
|
159
163
|
tests/unit_tests/test_widget_io.py,sha256=FeL3ZYSBQnRt6jxj8VGYw1cmcicRQyHKleahw7XIyR0,3475
|
@@ -163,8 +167,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
|
|
163
167
|
tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
|
164
168
|
tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
165
169
|
tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
|
166
|
-
bec_widgets-0.
|
167
|
-
bec_widgets-0.
|
168
|
-
bec_widgets-0.
|
169
|
-
bec_widgets-0.
|
170
|
-
bec_widgets-0.
|
170
|
+
bec_widgets-0.63.0.dist-info/METADATA,sha256=7zmXAhyzvbGnDsRQ9BIOv4jDaDOHgaiY6X2dXspqEM4,1302
|
171
|
+
bec_widgets-0.63.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
172
|
+
bec_widgets-0.63.0.dist-info/entry_points.txt,sha256=80s2YKCNziN2ROUYbpDRyEmiejMf_dshmiYCdN7qNsU,70
|
173
|
+
bec_widgets-0.63.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
174
|
+
bec_widgets-0.63.0.dist-info/RECORD,,
|
@@ -0,0 +1,33 @@
|
|
1
|
+
(user.widgets.text_box)=
|
2
|
+
# [Text Box Widget](/api_reference/_autosummary/bec_widgets.cli.client.TextBoxWidget)
|
3
|
+
**Purpose:**
|
4
|
+
|
5
|
+
The Text Box Widget is a widget that allows you to display text within the BEC GUI. The widget can be used to display plain text or HTML text.
|
6
|
+
|
7
|
+
**Key Features:**
|
8
|
+
|
9
|
+
- set the text to display.
|
10
|
+
- automatically detects if the text is plain text or HTML text.
|
11
|
+
- set background color and font color.
|
12
|
+
|
13
|
+
**Code example:**
|
14
|
+
|
15
|
+
The following code snipped demonstrates how to create a `TextBox` widget using BEC Widgets within BEC.
|
16
|
+
```python
|
17
|
+
text_box = gui.add_dock().add_widget("TextBox")
|
18
|
+
# set the text to display
|
19
|
+
text_box.set_text("Hello, World!")
|
20
|
+
# set the background color and font color
|
21
|
+
text_box.set_color(backgroud_color="#FFF", font_color="#000")
|
22
|
+
# set the text to display as HTML
|
23
|
+
text_box.set_text("<h1>Welcome to BEC Widgets</h1><p>This is an example of displaying <strong>HTML</strong> text.</p>")
|
24
|
+
```
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
docs/user/widgets/widgets.md
CHANGED
pyproject.toml
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
import re
|
2
|
+
from unittest import mock
|
3
|
+
|
4
|
+
import pytest
|
5
|
+
|
6
|
+
from bec_widgets.widgets.text_box.text_box import TextBox
|
7
|
+
|
8
|
+
from .client_mocks import mocked_client
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.fixture
|
12
|
+
def text_box_widget(qtbot, mocked_client):
|
13
|
+
widget = TextBox(client=mocked_client)
|
14
|
+
qtbot.addWidget(widget)
|
15
|
+
qtbot.waitExposed(widget)
|
16
|
+
yield widget
|
17
|
+
widget.close()
|
18
|
+
|
19
|
+
|
20
|
+
def test_textbox_widget(text_box_widget):
|
21
|
+
"""Test the TextBox widget."""
|
22
|
+
text = "Hello World!"
|
23
|
+
text_box_widget.set_text(text)
|
24
|
+
assert text_box_widget.toPlainText() == text
|
25
|
+
|
26
|
+
text_box_widget.set_color("#FFDDC1", "#123456")
|
27
|
+
text_box_widget.set_font_size(20)
|
28
|
+
assert (
|
29
|
+
text_box_widget.styleSheet() == "background-color: #FFDDC1; color: #123456; font-size: 20px"
|
30
|
+
)
|
31
|
+
text_box_widget.set_color("white", "blue")
|
32
|
+
text_box_widget.set_font_size(14)
|
33
|
+
assert text_box_widget.styleSheet() == "background-color: white; color: blue; font-size: 14px"
|
34
|
+
text = "<h1>Welcome to PyQt6</h1><p>This is an example of displaying <strong>HTML</strong> text.</p>"
|
35
|
+
with mock.patch.object(text_box_widget, "setHtml") as mocked_set_html:
|
36
|
+
text_box_widget.set_text(text)
|
37
|
+
assert mocked_set_html.call_count == 1
|
38
|
+
assert mocked_set_html.call_args == mock.call(text)
|
39
|
+
|
40
|
+
|
41
|
+
def test_textbox_change_theme(text_box_widget):
|
42
|
+
"""Test change theme functionaility"""
|
43
|
+
# Default is dark theme
|
44
|
+
text_box_widget.change_theme()
|
45
|
+
assert text_box_widget.config.theme == "light"
|
46
|
+
assert (
|
47
|
+
text_box_widget.styleSheet()
|
48
|
+
== f"background-color: #FFF; color: #000; font-size: {text_box_widget.config.font_size}px"
|
49
|
+
)
|
50
|
+
text_box_widget.change_theme()
|
51
|
+
assert text_box_widget.config.theme == "dark"
|
52
|
+
assert (
|
53
|
+
text_box_widget.styleSheet()
|
54
|
+
== f"background-color: #000; color: #FFF; font-size: {text_box_widget.config.font_size}px"
|
55
|
+
)
|
File without changes
|
File without changes
|
File without changes
|