1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-04-16 21:45:35 +02:00

Compare commits

...

9 Commits

Author SHA1 Message Date
065edf1e2d feat(widgets): added status indicator widget 2024-06-15 20:04:01 +02:00
9e16f2faf9 docs: fix links in developer section 2024-06-14 14:34:26 +02:00
2a36d9364f docs: refactor developer section, add widget tutorial 2024-06-14 14:24:38 +02:00
27426ce7a5 ci: add job optional dependency check 2024-06-14 11:47:42 +02:00
semantic-release
69adadd6d7 0.63.2
Automatically generated by python-semantic-release
2024-06-14 08:14:22 +00:00
6f96498de6 fix: do not import "server" in client, prevents from having trouble with QApplication creation order
Like with QtWebEngine
2024-06-13 15:14:30 +02:00
836b6e64f6 Reapply "feat: implement non-polling, interruptible waiting of gui instruction response with timeout"
This reverts commit fe04dd80e5.
2024-06-13 15:14:30 +02:00
semantic-release
fab7dd7eec 0.63.1
Automatically generated by python-semantic-release
2024-06-13 13:12:54 +00:00
9263f8ef5c fix: just terminate the remote process in close() instead of communicating
The proper finalization sequence will be executed by the remote process
on SIGTERM
2024-06-13 14:56:21 +02:00
17 changed files with 374 additions and 121 deletions

View File

@@ -22,6 +22,13 @@ workflow:
include:
- template: Security/Secret-Detection.gitlab-ci.yml
- project: "bec/awi_utils"
file: "/templates/check-packages-job.yml"
inputs:
stage: test
path: "."
pytest_args: "-v --random-order tests/"
exclude_packages: ""
# different stages in the pipeline
stages:
@@ -32,21 +39,21 @@ stages:
- Deploy
.install-qt-webengine-deps: &install-qt-webengine-deps
- apt-get -y install libnss3 libxdamage1 libasound2 libatomic1 libxcursor1
- export QTWEBENGINE_DISABLE_SANDBOX=1
- apt-get -y install libnss3 libxdamage1 libasound2 libatomic1 libxcursor1
- export QTWEBENGINE_DISABLE_SANDBOX=1
.clone-repos: &clone-repos
- git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
- git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
- export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
- git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
- git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
- export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
.install-os-packages: &install-os-packages
- apt-get update
- apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3
- *install-qt-webengine-deps
- apt-get update
- apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3
- *install-qt-webengine-deps
before_script:
- if [[ "$CI_PROJECT_PATH" != "bec/bec_widgets" ]]; then
- if [[ "$CI_PROJECT_PATH" != "bec/bec_widgets" ]]; then
echo -e "\033[35;1m Using branch $CHILD_PIPELINE_BRANCH of BEC Widgets \033[0;m";
test -d bec_widgets || git clone --branch $CHILD_PIPELINE_BRANCH https://gitlab.psi.ch/bec/bec_widgets.git; cd bec_widgets;
fi
@@ -92,10 +99,10 @@ pylint-check:
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
# Identify changed Python files
- if [ "$CI_PIPELINE_SOURCE" == "merge_request_event" ]; then
TARGET_BRANCH_COMMIT_SHA=$(git rev-parse origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
CHANGED_FILES=$(git diff --name-only $TARGET_BRANCH_COMMIT_SHA HEAD | grep '\.py$' || true);
TARGET_BRANCH_COMMIT_SHA=$(git rev-parse origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
CHANGED_FILES=$(git diff --name-only $TARGET_BRANCH_COMMIT_SHA HEAD | grep '\.py$' || true);
else
CHANGED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' || true);
CHANGED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' || true);
fi
- if [ -z "$CHANGED_FILES" ]; then echo "No Python files changed."; exit 0; fi
@@ -120,7 +127,7 @@ tests:
stage: test
needs: []
variables:
QT_QPA_PLATFORM: "offscreen"
QT_QPA_PLATFORM: "offscreen"
script:
- *clone-repos
- *install-os-packages
@@ -141,21 +148,21 @@ tests:
test-matrix:
parallel:
matrix:
- PYTHON_VERSION:
- "3.10"
- "3.11"
- "3.12"
QT_PCKG:
- "pyside6"
- "pyqt5"
- "pyqt6"
- PYTHON_VERSION:
- "3.10"
- "3.11"
- "3.12"
QT_PCKG:
- "pyside6"
- "pyqt5"
- "pyqt6"
stage: AdditionalTests
needs: []
variables:
QT_QPA_PLATFORM: "offscreen"
PYTHON_VERSION: ""
QT_PCKG: ""
QT_QPA_PLATFORM: "offscreen"
PYTHON_VERSION: ""
QT_PCKG: ""
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:$PYTHON_VERSION
script:
- *clone-repos
@@ -226,7 +233,7 @@ semver:
- pip install python-semantic-release==9.* wheel build twine
- export GL_TOKEN=$CI_UPDATES
- semantic-release -vv version
# check if any artifacts were created
- if [ ! -d dist ]; then echo No release will be made; exit 0; fi
- twine upload dist/* -u __token__ -p $CI_PYPI_TOKEN --skip-existing
@@ -242,7 +249,7 @@ pages:
variables:
TARGET_BRANCH: $CI_COMMIT_REF_NAME
rules:
- if: '$CI_COMMIT_TAG != null'
- if: "$CI_COMMIT_TAG != null"
variables:
TARGET_BRANCH: $CI_COMMIT_TAG
- if: '$CI_COMMIT_REF_NAME == "main" && $CI_PROJECT_PATH == "bec/bec_widgets"'

View File

@@ -2,6 +2,31 @@
## v0.63.2 (2024-06-14)
### Fix
* fix: do not import "server" in client, prevents from having trouble with QApplication creation order
Like with QtWebEngine ([`6f96498`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6f96498de66358b89f3a2035627eed2e02dde5a1))
### Unknown
* Reapply "feat: implement non-polling, interruptible waiting of gui instruction response with timeout"
This reverts commit fe04dd80e59a0e74f7fdea603e0642707ecc7c2a. ([`836b6e6`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/836b6e64f694916d6b6f909dedf11a4a6d2c86a4))
## v0.63.1 (2024-06-13)
### Fix
* fix: just terminate the remote process in close() instead of communicating
The proper finalization sequence will be executed by the remote process
on SIGTERM ([`9263f8e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9263f8ef5c17ae7a007a1a564baf787b39061756))
## v0.63.0 (2024-06-13)
### Documentation
@@ -149,21 +174,3 @@ This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https:
## v0.57.7 (2024-06-07)
### Documentation
* docs: added schema of BECDockArea and BECFigure ([`828067f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/828067f486a905eb4678538df58e2bdd6c770de1))
### Fix
* fix: add model_config to pydantic models to allow runtime checks after creation ([`ca5e8d2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ca5e8d2fbbffbf221cc5472710fef81a33ee29d6))
## v0.57.6 (2024-06-06)
### Fix
* fix(bar): docstrings extended ([`edb1775`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/edb1775967c3ff0723d0edad2b764f1ffc832b7c))
## v0.57.5 (2024-06-06)

View File

@@ -16,6 +16,7 @@ class Widgets(str, enum.Enum):
BECDock = "BECDock"
BECDockArea = "BECDockArea"
BECFigure = "BECFigure"
RoundStatusIndicator = "RoundStatusIndicator"
SpiralProgressBar = "SpiralProgressBar"
TextBox = "TextBox"
WebsiteWidget = "WebsiteWidget"
@@ -1719,6 +1720,17 @@ class Ring(RPCBase):
"""
class RoundStatusIndicator(RPCBase):
@rpc_call
def set_state(self, state: Literal["success", "failure", "warning"]) -> None:
"""
Set the state of the indicator.
Args:
state (str): The state of the indicator. Can be "success", "failure", or "warning"
"""
class SpiralProgressBar(RPCBase):
@rpc_call
def get_all_rpc(self) -> "dict":
@@ -1920,7 +1932,7 @@ class TextBox(RPCBase):
@rpc_call
def set_color(self, background_color: str, font_color: str) -> None:
"""
Set the background color of the Widget.
Set the background color of the widget.
Args:
background_color (str): The color to set the background in HEX.
@@ -1930,13 +1942,19 @@ class TextBox(RPCBase):
@rpc_call
def set_text(self, text: str) -> None:
"""
Set the text of the Widget
Set the text of the widget.
Args:
text (str): The text to set.
"""
@rpc_call
def set_font_size(self, size: int) -> None:
"""
Set the font size of the text in the Widget.
Set the font size of the text in the widget.
Args:
size (int): The font size to set.
"""

View File

@@ -14,7 +14,7 @@ from typing import TYPE_CHECKING
from bec_lib.endpoints import MessageEndpoints
from bec_lib.utils.import_utils import isinstance_based_on_class_name, lazy_import, lazy_import_from
from qtpy.QtCore import QCoreApplication
from qtpy.QtCore import QEventLoop, QSocketNotifier, QTimer
import bec_widgets.cli.client as client
from bec_widgets.cli.auto_updates import AutoUpdates
@@ -24,6 +24,8 @@ if TYPE_CHECKING:
from bec_widgets.cli.client import BECDockArea, BECFigure
from bec_lib.serialization import MsgpackSerialization
messages = lazy_import("bec_lib.messages")
# from bec_lib.connector import MessageObject
MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
@@ -84,13 +86,8 @@ def _start_plot_process(gui_id, gui_class, config) -> None:
Start the plot in a new process.
"""
# pylint: disable=subprocess-run-check
monitor_module = importlib.import_module("bec_widgets.cli.server")
monitor_path = monitor_module.__file__
command = [
sys.executable,
"-u",
monitor_path,
"bec-gui-server",
"--id",
gui_id,
"--config",
@@ -98,7 +95,11 @@ def _start_plot_process(gui_id, gui_class, config) -> None:
"--gui_class",
gui_class.__name__,
]
process = subprocess.Popen(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
env_dict = os.environ.copy()
env_dict["PYTHONUNBUFFERED"] = "1"
process = subprocess.Popen(
command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env_dict
)
process_output_processing_thread = threading.Thread(target=_get_output, args=(process,))
process_output_processing_thread.start()
return process, process_output_processing_thread
@@ -174,16 +175,11 @@ class BECGuiClientMixin:
"""
Close the figure.
"""
if self._process is None:
return
if self.gui_is_alive():
self._run_rpc("close", (), wait_for_rpc_response=True)
else:
self._run_rpc("close", (), wait_for_rpc_response=False)
self._process.terminate()
self._process_output_processing_thread.join()
self._process = None
self._client.shutdown()
if self._process:
self._process.terminate()
self._process_output_processing_thread.join()
self._process = None
def print_log(self) -> None:
"""
@@ -205,6 +201,48 @@ class RPCResponseTimeoutError(Exception):
)
class QtRedisMessageWaiter:
def __init__(self, redis_connector, message_to_wait):
self.ev_loop = QEventLoop()
self.response = None
self.connector = redis_connector
self.message_to_wait = message_to_wait
self.pubsub = redis_connector._redis_conn.pubsub()
self.pubsub.subscribe(self.message_to_wait.endpoint)
fd = self.pubsub.connection._sock.fileno()
self.notifier = QSocketNotifier(fd, QSocketNotifier.Read)
self.notifier.activated.connect(self._pubsub_readable)
def _msg_received(self, msg_obj):
self.response = msg_obj.value
self.ev_loop.quit()
def wait(self, timeout=1):
timer = QTimer()
timer.singleShot(timeout * 1000, self.ev_loop.quit)
self.ev_loop.exec_()
timer.stop()
self.notifier.setEnabled(False)
self.pubsub.close()
return self.response
def _pubsub_readable(self, fd):
while True:
msg = self.pubsub.get_message()
if msg:
if msg["type"] == "subscribe":
# get_message buffers, so we may already have the answer
# let's check...
continue
else:
break
else:
return
channel = msg["channel"].decode()
msg = MessageObject(topic=channel, value=MsgpackSerialization.loads(msg["data"]))
self.connector._execute_callback(self._msg_received, msg, {})
class RPCBase:
def __init__(self, gui_id: str = None, config: dict = None, parent=None) -> None:
self._client = BECDispatcher().client
@@ -231,7 +269,7 @@ class RPCBase:
parent = parent._parent
return parent
def _run_rpc(self, method, *args, wait_for_rpc_response=True, **kwargs):
def _run_rpc(self, method, *args, wait_for_rpc_response=True, timeout=3, **kwargs):
"""
Run the RPC call.
@@ -253,16 +291,24 @@ class RPCBase:
# pylint: disable=protected-access
receiver = self._root._gui_id
if wait_for_rpc_response:
redis_msg = QtRedisMessageWaiter(
self._client.connector, MessageEndpoints.gui_instruction_response(request_id)
)
self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
if not wait_for_rpc_response:
return None
response = self._wait_for_response(request_id)
# get class name
if not response.content["accepted"]:
raise ValueError(response.content["message"]["error"])
msg_result = response.content["message"].get("result")
return self._create_widget_from_msg_result(msg_result)
if wait_for_rpc_response:
response = redis_msg.wait(timeout)
if response is None:
raise RPCResponseTimeoutError(request_id, timeout)
# get class name
if not response.accepted:
raise ValueError(response.message["error"])
msg_result = response.message.get("result")
return self._create_widget_from_msg_result(msg_result)
def _create_widget_from_msg_result(self, msg_result):
if msg_result is None:
@@ -285,30 +331,6 @@ class RPCBase:
return cls(parent=self, **msg_result)
return msg_result
def _wait_for_response(self, request_id: str, timeout: int = 5):
"""
Wait for the response from the server.
Args:
request_id(str): The request ID.
timeout(int): The timeout in seconds.
Returns:
The response from the server.
"""
start_time = time.time()
response = None
while response is None and self.gui_is_alive() and (time.time() - start_time) < timeout:
response = self._client.connector.get(
MessageEndpoints.gui_instruction_response(request_id)
)
QCoreApplication.processEvents() # keep UI responsive (and execute signals/slots)
if response is None and (time.time() - start_time) >= timeout:
raise RPCResponseTimeoutError(request_id, timeout)
return response
def gui_is_alive(self):
"""
Check if the GUI is alive.

View File

@@ -1,5 +1,6 @@
from bec_widgets.utils import BECConnector
from bec_widgets.widgets.figure import BECFigure
from bec_widgets.widgets.round_status_indicator.round_status_indicator import RoundStatusIndicator
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
from bec_widgets.widgets.text_box.text_box import TextBox
from bec_widgets.widgets.website.website import WebsiteWidget
@@ -13,6 +14,7 @@ class RPCWidgetHandler:
"SpiralProgressBar": SpiralProgressBar,
"Website": WebsiteWidget,
"TextBox": TextBox,
"RoundStatusIndicator": RoundStatusIndicator,
}
@staticmethod

View File

@@ -114,7 +114,7 @@ class BECWidgetsCLIServer:
self.client.shutdown()
if __name__ == "__main__": # pragma: no cover
def main():
import argparse
import os
import sys
@@ -166,3 +166,7 @@ if __name__ == "__main__": # pragma: no cover
app.aboutToQuit.connect(server.shutdown)
sys.exit(app.exec())
if __name__ == "__main__": # pragma: no cover
main()

View File

@@ -136,17 +136,18 @@ if __name__ == "__main__": # pragma: no cover
module_path = os.path.dirname(bec_widgets.__file__)
app = QApplication(sys.argv)
app.setApplicationName("Jupyter Console")
app.setApplicationDisplayName("Jupyter Console")
qdarktheme.setup_theme("auto")
icon = QIcon()
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
app.setWindowIcon(icon)
bec_dispatcher = BECDispatcher()
client = bec_dispatcher.client
client.start()
app = QApplication(sys.argv)
app.setApplicationName("Jupyter Console")
app.setApplicationDisplayName("Jupyter Console")
# qdarktheme.setup_theme("auto")
icon = QIcon()
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
app.setWindowIcon(icon)
win = JupyterConsoleWindow()
win.show()

View File

@@ -9,7 +9,7 @@ import redis
from bec_lib.client import BECClient
from bec_lib.redis_connector import MessageObject, RedisConnector
from bec_lib.service_config import ServiceConfig
from qtpy.QtCore import QObject
from qtpy.QtCore import QCoreApplication, QObject
from qtpy.QtCore import Signal as pyqtSignal
if TYPE_CHECKING:
@@ -71,6 +71,7 @@ class BECDispatcher:
_instance = None
_initialized = False
qapp = None
def __new__(cls, client=None, config: str = None, *args, **kwargs):
if cls._instance is None:
@@ -82,6 +83,9 @@ class BECDispatcher:
if self._initialized:
return
if not QCoreApplication.instance():
BECDispatcher.qapp = QCoreApplication([])
self._slots = collections.defaultdict(set)
self.client = client

View File

@@ -0,0 +1,108 @@
from enum import Enum
from typing import Literal
from PyQt6.QtGui import QPaintEvent
from qtpy import QtGui
from qtpy.QtCore import QRect, Qt
from qtpy.QtWidgets import QApplication, QMainWindow, QWidget
from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
class RoundStatusIndicatorConfig(ConnectionConfig):
"""
Configuration for the RoundStatusIndicator
"""
state: Literal["success", "failure", "warning"] = "success"
class RoundStatusIndicator(BECConnector, QWidget):
indicator_config = {
"success": {"color": "#24a148", "text": "", "offset": 0.25},
"failure": {"color": "#da1e28", "text": "", "offset": 0.28},
"warning": {"color": "#ffcc00", "text": "!", "offset": 0.28},
}
USER_ACCESS = ["set_state"]
def __init__(
self,
client=None,
config: RoundStatusIndicatorConfig | dict | None = None,
gui_id=None,
parent=None,
):
super().__init__(client=client, config=config, gui_id=gui_id)
QWidget.__init__(self, parent=parent)
self.config = config or RoundStatusIndicatorConfig(widget_class=self.__class__.__name__)
self.active_state_config = self.indicator_config[self.config.state]
def paintEvent(self, _event: QPaintEvent) -> None:
"""
Paint the widget.
Args:
_event (QPaintEvent): The paint event
"""
color = QtGui.QColor(self.active_state_config["color"]) # Red color as default
text_color = QtGui.QColor("#ffffff") # White color for text
text = self.active_state_config["text"]
offset = self.active_state_config["offset"]
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing)
# Determine the size of the widget
size = min(self.width(), self.height())
rect = QRect(0, 0, size, size)
# Set the color and draw the disk
painter.setBrush(color)
painter.setPen(Qt.PenStyle.NoPen)
painter.drawEllipse(rect)
# Draw the exclamation mark "!"
painter.setPen(text_color)
font = painter.font()
font.setPixelSize(int(size * 0.9)) # Adjust font size based on widget size
painter.setFont(font)
# text_rect = painter.boundingRect(rect, Qt.AlignmentFlag.AlignCenter, text)
font_metrics = QtGui.QFontMetrics(font)
text_width = font_metrics.horizontalAdvance(text)
text_height = font_metrics.height()
text_x = int(rect.center().x() - text_width / 2)
text_y = int(rect.center().y() + text_height * offset)
painter.drawText(text_x, text_y, text)
def set_state(self, state: Literal["success", "failure", "warning"]) -> None:
"""
Set the state of the indicator.
Args:
state (str): The state of the indicator. Can be "success", "failure", or "warning"
"""
self.config.state = state
self.active_state_config = self.indicator_config[state]
self.update()
if __name__ == "__main__":
app = QApplication([])
window = QMainWindow()
status_indicator = RoundStatusIndicator()
window.setCentralWidget(status_indicator)
window.resize(200, 200)
window.show()
# Example of changing the color
status_indicator.set_state("warning") # Change to a different color
app.exec()

View File

@@ -1,18 +1,46 @@
(developer)=
# Development
# Developer
To contribute to the development of BEC Widgets, start by setting up the development environment:
Welcome to the BEC Widgets developer guide! This section is intended for developers who want to contribute to the development of BEC Widgets.
1. **Clone the Repository**:
```bash
git clone https://gitlab.psi.ch/bec/bec_widgets
cd bec_widgets
```
2. **Install in Editable Mode**:
```{toctree}
---
maxdepth: 2
hidden: true
---
Installing the package in editable mode allows you to make changes to the code and test them in real-time.
```bash
pip install -e .[dev,pyqt6]
getting_started/getting_started.md
widgets/widgets.md
api_reference/api_reference.md
```
***
````{grid} 2
:gutter: 5
```{grid-item-card}
:link: developer.getting_started
:link-type: ref
:img-top: /assets/rocket_launch_48dp.svg
:text-align: center
## Getting Started
Learn how to install BEC Widgets and get started with the framework.
```
```{grid-item-card}
:link: developer.widgets
:link-type: ref
:img-top: /assets/apps_48dp.svg
:text-align: center
## Widgets
Learn about the building blocks of larger applications: widgets.
```
````

View File

@@ -0,0 +1,27 @@
(developer.development)=
# Development
If you like to contribute to the development of BEC Widgets, you can follow the steps below to set up your development environment.
BEC Widgets works in conjunction with [BEC](https://bec.readthedocs.io/en/latest/).
Therefore, we recommend that you install BEC first following the [developer instructions](https://bec.readthedocs.io/en/latest/developer/getting_started/install_developer_env.html) and include BEC Widgets.
If you already have a BEC environment set up, you can install BEC Widgets in editable mode into your BEC Python environment.
**Prerequisites**
1. **Python Version:** BEC Widgets requires Python version 3.10 or higher. Verify your Python version to ensure compatibility.
2. **BEC Installation:** BEC Widgets works in conjunction with BEC. While BEC is a dependency and will be installed automatically, you can find more information about BEC and its installation process in the [BEC documentation](https://beamline-experiment-control.readthedocs.io/en/latest/).
**Clone the Repository**:
```bash
git clone https://gitlab.psi.ch/bec/bec_widgets
cd bec_widgets
```
**Install in Editable Mode**:
Please install the package in editable mode into your BEC Python environemnt.
```bash
pip install -e '.[dev,pyqt6]'
```
This installs the package together with [PyQT6](https://www.riverbankcomputing.com/static/Docs/PyQt6/introduction.html).

View File

@@ -0,0 +1,12 @@
(developer.getting_started)=
# Getting Started
This section provides valuable information for developers who want to contribute to the development of BEC Widgets. The guide will help you set up the development environment, understand the modular development concept of BEC Widgets, and contribute to the project.
```{toctree}
---
maxdepth: 2
hidden: false
---
development/
```

View File

@@ -0,0 +1,12 @@
(developer.widgets)=
# Widgets
This section provides an introduction to the building blocks of BEC Widgets: widgets. Widgets are the basic components of the graphical user interface (GUI) and are used to create larger applications. We will cover key topics such as how to develop new widgets or how to customise existing widgets. For details on the already available widgets and their usage, please refer to user section about [widgets](#user.widgets)
```{toctree}
---
maxdepth: 2
hidden: false
---
how_to_develop_a_widget/
```

View File

@@ -9,7 +9,7 @@ Before installing BEC Widgets, please ensure the following requirements are met:
**Standard Installation**
To install BEC Widgets using the pip package manager, execute the following command in your terminal for getting the default PyQT6 version in your python environment:
To install BEC Widgets using the pip package manager, execute the following command in your terminal for getting the default PyQT6 version into your python environment for BEC:
```bash

View File

@@ -1,5 +1,5 @@
(user.widgets.text_box)=
# [Text Box Widget](/api_reference/_autosummary/bec_widgets.cli.client.TextBoxWidget)
# [Text Box Widget](/api_reference/_autosummary/bec_widgets.cli.client.TextBox)
**Purpose:**
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.

View File

@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "bec_widgets"
version = "0.63.0"
version = "0.63.2"
description = "BEC Widgets"
requires-python = ">=3.10"
classifiers = [
@@ -48,6 +48,7 @@ Homepage = "https://gitlab.psi.ch/bec/bec_widgets"
[project.scripts]
bw-generate-cli = "bec_widgets.cli.generate_cli:main"
bec-gui-server = "bec_widgets.cli.server:main"
[tool.hatch.build.targets.wheel]
include = ["*"]