fix: remove deprecated docs

This commit is contained in:
2026-07-07 14:03:12 +02:00
committed by Jan Wyzula
parent 5984ca5617
commit 09dc178826
131 changed files with 0 additions and 4975 deletions
-27
View File
@@ -1,27 +0,0 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# If using Sphinx, optionally build your docs in additional formats such as PDF
# formats:
# - pdf
# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .[dev]
-20
View File
@@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-170
View File
File diff suppressed because one or more lines are too long
-34
View File
@@ -1,34 +0,0 @@
{{ fullname | escape | underline}}
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
:members:
:show-inheritance:
:inherited-members:
:special-members: __call__, __add__, __mul__
{% block methods %}
{% if methods %}
.. rubric:: {{ _('Methods') }}
.. autosummary::
:nosignatures:
{% for item in methods %}
{%- if not item.startswith('_') %}
~{{ name }}.{{ item }}
{%- endif -%}
{%- endfor %}
{% endif %}
{% endblock %}
{% block attributes %}
{% if attributes %}
.. rubric:: {{ _('Attributes') }}
.. autosummary::
{% for item in attributes %}
~{{ name }}.{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
-66
View File
@@ -1,66 +0,0 @@
{{ fullname | escape | underline}}
.. automodule:: {{ fullname }}
{% block attributes %}
{% if attributes %}
.. rubric:: Module attributes
.. autosummary::
:toctree:
{% for item in attributes %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block functions %}
{% if functions %}
.. rubric:: {{ _('Functions') }}
.. autosummary::
:toctree:
:nosignatures:
{% for item in functions %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block classes %}
{% if classes %}
.. rubric:: {{ _('Classes') }}
.. autosummary::
:toctree:
:template: custom-class-template.rst
:nosignatures:
{% for item in classes %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block exceptions %}
{% if exceptions %}
.. rubric:: {{ _('Exceptions') }}
.. autosummary::
:toctree:
{% for item in exceptions %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
{% block modules %}
{% if modules %}
.. autosummary::
:toctree:
:template: custom-module-template.rst
:recursive:
{% for item in modules %}
{{ item }}
{%- endfor %}
{% endif %}
{% endblock %}
-11
View File
@@ -1,11 +0,0 @@
(api_reference)=
# API Reference
This page contains the auto-generated API documentation for all modules, classes, and functions in the BEC Widgets package.
```{toctree}
:maxdepth: 2
:caption: API Documentation
../autoapi/bec_widgets/index
```
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"/></svg>

Before

Width:  |  Height:  |  Size: 292 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 20 20" height="48px" viewBox="0 0 20 20" width="48px" fill="#000000"><g><rect fill="none" height="20" width="20" x="0"/></g><g><g><path d="M16.5,3h-13C2.67,3,2,3.67,2,4.5v9C2,14.33,2.67,15,3.5,15H7v2h6v-2h3.5c0.83,0,1.5-0.67,1.5-1.5v-9 C18,3.67,17.33,3,16.5,3z M16.5,13.5h-13v-9h13V13.5z"/><rect height="1" width="7" x="5" y="7"/><polygon points="14,8 15,8 15,7 14,7 14,6 13,6 13,9 14,9"/><rect height="1" width="7" x="8" y="10"/><polygon points="6,12 7,12 7,9 6,9 6,10 5,10 5,11 6,11"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 568 B

-97
View File
@@ -1,97 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="99.058548mm"
height="89.967583mm"
viewBox="0 0 99.058554 89.967582"
version="1.1"
id="svg1040"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"
sodipodi:docname="index_api.svg">
<defs
id="defs1034" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="533.74914"
inkscape:cy="10.90433"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="930"
inkscape:window-height="472"
inkscape:window-x="2349"
inkscape:window-y="267"
inkscape:window-maximized="0" />
<metadata
id="metadata1037">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(195.19933,-1.0492759)">
<g
id="g1008"
transform="matrix(1.094977,0,0,1.094977,-521.5523,-198.34055)">
<path
inkscape:connector-curvature="0"
id="path899"
d="M 324.96812,187.09499 H 303.0455 v 72.1639 h 22.67969"
style="fill:none;stroke:#5a5a5a;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path899-3"
d="m 361.58921,187.09499 h 21.92262 v 72.1639 h -22.67969"
style="fill:none;stroke:#5a5a5a;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<g
transform="translate(415.87139,46.162126)"
id="g944">
<circle
style="fill:#5a5a5a;fill-opacity:1;stroke:#5a5a5a;stroke-width:4.53704548;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path918"
cx="-84.40152"
cy="189.84375"
r="2.2293637" />
<circle
style="fill:#5a5a5a;fill-opacity:1;stroke:#5a5a5a;stroke-width:4.53704548;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path918-5"
cx="-72.949402"
cy="189.84375"
r="2.2293637" />
<circle
style="fill:#5a5a5a;fill-opacity:1;stroke:#5a5a5a;stroke-width:4.53704548;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path918-6"
cx="-61.497284"
cy="189.84375"
r="2.2293637" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

-76
View File
@@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="89.624855mm"
height="89.96759mm"
viewBox="0 0 89.62486 89.96759"
version="1.1"
id="svg1040"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"
sodipodi:docname="index_contribute.svg">
<defs
id="defs1034" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="683.11893"
inkscape:cy="-59.078181"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="930"
inkscape:window-height="472"
inkscape:window-x="2349"
inkscape:window-y="267"
inkscape:window-maximized="0" />
<metadata
id="metadata1037">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(234.72009,17.466935)">
<g
id="g875"
transform="matrix(0.99300176,0,0,0.99300176,-133.24106,-172.58804)">
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path869"
d="m -97.139881,161.26069 47.247024,40.25446 -47.247024,40.25446"
style="fill:none;stroke:#5a5a5a;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path871"
d="m -49.514879,241.81547 h 32.505951"
style="fill:none;stroke:#5a5a5a;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

-66
View File
@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="101.09389mm"
height="89.96759mm"
viewBox="0 0 101.09389 89.96759"
version="1.1"
id="svg1040"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"
sodipodi:docname="index_getting_started.svg">
<defs
id="defs1034" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="-93.242129"
inkscape:cy="-189.9825"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1875"
inkscape:window-height="1056"
inkscape:window-x="1965"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata1037">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(2.9219487,-8.5995374)">
<path
style="fill:#5a5a5a;fill-opacity:1;stroke-width:0.20233451"
d="M 37.270955,98.335591 C 33.358064,97.07991 31.237736,92.52319 32.964256,89.08022 c 0.18139,-0.361738 4.757999,-5.096629 10.17021,-10.521968 l 9.84041,-9.864254 -4.03738,-4.041175 -4.037391,-4.041172 -4.96415,4.916665 c -3.61569,3.581096 -5.238959,5.04997 -5.975818,5.407377 l -1.011682,0.490718 H 17.267525 1.5866055 L 0.65034544,70.96512 C -2.2506745,69.535833 -3.5952145,66.18561 -2.5925745,62.884631 c 0.53525,-1.762217 1.61699004,-3.050074 3.22528014,-3.839847 l 1.15623996,-0.56778 13.2591094,-0.05613 13.259111,-0.05613 11.5262,-11.527539 11.526199,-11.527528 H 40.622647 c -12.145542,0 -12.189222,-0.0046 -13.752801,-1.445851 -2.229871,-2.055423 -2.162799,-5.970551 0.135998,-7.938238 1.475193,-1.262712 1.111351,-1.238469 18.588522,-1.238469 12.899229,0 16.035311,0.05193 16.692589,0.276494 0.641832,0.219264 2.590731,2.051402 9.416301,8.852134 l 8.606941,8.575638 h 6.848168 c 4.837422,0 7.092281,0.07311 7.679571,0.249094 0.48064,0.144008 1.22985,0.634863 1.77578,1.163429 2.383085,2.307333 1.968685,6.539886 -0.804989,8.221882 -0.571871,0.346781 -1.38284,0.687226 -1.80217,0.756523 -0.41933,0.06928 -4.2741,0.127016 -8.56615,0.128238 -6.56998,0.0016 -7.977492,-0.04901 -8.902732,-0.321921 -0.975569,-0.287742 -1.400468,-0.622236 -3.783999,-2.978832 l -2.685021,-2.654679 -5.05411,5.051071 -5.0541,5.051081 3.926292,3.947202 c 2.365399,2.378001 4.114289,4.309171 4.399158,4.857713 0.39266,0.75606 0.47311,1.219412 0.474321,2.731516 0.003,3.083647 0.620779,2.331942 -13.598011,16.531349 -10.273768,10.259761 -12.679778,12.563171 -13.500979,12.92519 -1.267042,0.55857 -3.156169,0.681342 -4.390271,0.285321 z m 40.130741,-65.45839 c -2.212909,-0.579748 -3.782711,-1.498393 -5.51275,-3.226063 -2.522111,-2.518633 -3.633121,-5.181304 -3.633121,-8.707194 0,-3.530699 1.11238,-6.197124 3.631161,-8.704043 4.866751,-4.8438383 12.324781,-4.8550953 17.211791,-0.026 3.908758,3.862461 4.818578,9.377999 2.372188,14.380771 -0.846209,1.730481 -3.39493,4.326384 -5.143839,5.239072 -2.69708,1.407492 -6.042829,1.798628 -8.92543,1.043434 z"
id="path1000"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

-67
View File
@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="123.72241mm"
height="89.96759mm"
viewBox="0 0 123.72242 89.96759"
version="1.1"
id="svg1040"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"
sodipodi:docname="index_userguide.svg">
<defs
id="defs1034" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="332.26618"
inkscape:cy="83.744004"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="930"
inkscape:window-height="472"
inkscape:window-x="2349"
inkscape:window-y="267"
inkscape:window-maximized="0" />
<metadata
id="metadata1037">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(141.8903,-20.32143)">
<path
style="fill:#5a5a5a;fill-opacity:1;stroke-width:0.20483544"
d="m -139.53374,110.1657 c -0.80428,-0.24884 -1.71513,-1.11296 -2.07107,-1.96486 -0.23905,-0.57214 -0.28453,-6.28104 -0.28453,-35.720988 0,-38.274546 -0.079,-35.840728 1.19849,-36.91568 0.58869,-0.495345 4.63766,-2.187548 8.47998,-3.544073 l 1.58749,-0.560453 v -3.309822 c 0,-3.025538 0.0396,-3.388179 0.46086,-4.222122 0.68808,-1.362003 1.38671,-1.714455 4.60319,-2.322195 4.12797,-0.779966 5.13304,-0.912766 8.81544,-1.16476 11.80964,-0.808168 22.80911,2.509277 30.965439,9.3392 1.750401,1.465747 3.840861,3.5635 5.0903,5.108065 l 0.659122,0.814805 0.659109,-0.814805 c 1.249431,-1.544565 3.33988,-3.642318 5.09029,-5.108065 8.156331,-6.829923 19.155791,-10.147368 30.965441,-9.3392 3.682389,0.251994 4.68748,0.384794 8.81544,1.16476 3.21647,0.60774 3.91511,0.960192 4.60318,2.322195 0.4213,0.833943 0.46087,1.196584 0.46087,4.222122 v 3.309822 l 1.58748,0.560453 c 4.10165,1.448077 7.98852,3.072753 8.5259,3.563743 1.22643,1.120567 1.15258,-1.245868 1.15258,36.927177 0,34.567591 -0.005,35.083151 -0.40663,35.903991 -0.22365,0.45804 -0.73729,1.05665 -1.14143,1.33024 -1.22281,0.82783 -2.17721,0.70485 -5.86813,-0.7561 -9.19595,-3.63998 -18.956011,-6.38443 -26.791332,-7.53353 -3.02827,-0.44412 -9.26189,-0.61543 -11.77821,-0.3237 -5.19357,0.60212 -8.736108,2.05527 -11.700039,4.79936 -0.684501,0.63371 -1.466141,1.23646 -1.736979,1.33942 -0.63859,0.2428 -4.236521,0.2428 -4.875112,0 -0.27083,-0.10296 -1.05247,-0.70571 -1.73696,-1.33942 -2.96395,-2.74409 -6.50648,-4.19724 -11.700058,-4.79936 -2.516312,-0.29173 -8.749941,-0.12042 -11.778201,0.3237 -7.78194,1.14127 -17.39965,3.83907 -26.73341,7.49883 -3.38325,1.32658 -4.15525,1.50926 -5.11851,1.21125 z m 4.2107,-5.34052 c 5.86759,-2.29858 14.40398,-4.922695 20.2018,-6.210065 6.31584,-1.402418 8.5236,-1.646248 14.91592,-1.647338 4.68699,-7.94e-4 6.013661,0.0632 7.257809,0.3497 0.837332,0.19286 1.561052,0.312028 1.60828,0.264819 0.147111,-0.147119 -1.803289,-1.307431 -4.154879,-2.471801 -8.12511,-4.023029 -18.27311,-4.986568 -29.0861,-2.761718 -1.09536,0.22538 -2.32708,0.40827 -2.73715,0.406418 -1.12787,-0.005 -2.3054,-0.76382 -2.84516,-1.8332 l -0.46086,-0.913098 V 62.99179 35.97471 l -0.56331,0.138329 c -0.30981,0.07608 -1.89985,0.665075 -3.5334,1.308881 -2.27551,0.896801 -2.96414,1.252878 -2.94452,1.522563 0.014,0.193604 0.0372,15.284513 0.0512,33.535345 0.014,18.250839 0.0538,33.183322 0.0884,33.183322 0.0346,0 1.02543,-0.3771 2.20198,-0.83801 z m 113.006991,-32.697216 -0.0518,-33.535203 -3.17495,-1.272156 c -1.74623,-0.699685 -3.33627,-1.278755 -3.53341,-1.286819 -0.33966,-0.01389 -0.35847,1.401778 -0.35847,26.980216 v 26.994863 l -0.46087,0.913112 c -0.53976,1.06939 -1.71729,1.828088 -2.84515,1.833189 -0.41008,0.0021 -1.6418,-0.181031 -2.73716,-0.406421 -11.888201,-2.446089 -22.84337,-1.046438 -31.491022,4.02332 -1.68175,0.985941 -2.216748,1.467501 -1.36534,1.228942 1.575181,-0.441362 4.990592,-0.73864 8.524862,-0.742011 5.954408,-0.005 11.43046,0.791951 19.10874,2.78333 3.9516,1.024874 12.1555,3.687454 15.6699,5.085704 1.23926,0.49306 2.36869,0.90517 2.50985,0.9158 0.20489,0.0155 0.2462,-6.745894 0.20483,-33.515866 z m -59.76135,-2.233777 V 40.065438 l -0.95972,-1.357442 c -1.380522,-1.952627 -5.376262,-5.847994 -7.64336,-7.45136 -3.778692,-2.672401 -9.063392,-4.943324 -13.672511,-5.875304 -3.19731,-0.646503 -5.23069,-0.833103 -9.05886,-0.831312 -4.37716,0.0021 -7.70223,0.349169 -11.83461,1.235469 l -1.07538,0.230645 v 31.242342 c 0,26.565778 0.0426,31.226011 0.28429,31.133261 0.15637,-0.06 1.42379,-0.297169 2.81648,-0.527026 12.37657,-2.042634 23.21658,-0.346861 32.521639,5.087596 2.10018,1.226558 5.20202,3.618878 6.880942,5.30692 0.788609,0.792909 1.502978,1.446609 1.587468,1.452679 0.0845,0.006 0.153622,-13.411893 0.153622,-29.817719 z m 5.80221,28.3766 c 6.21476,-6.141601 15.08488,-10.061509 25.025529,-11.05933 4.262419,-0.427849 11.579921,-0.0054 16.017661,0.924912 0.75932,0.15916 1.45259,0.244888 1.54058,0.190498 0.088,-0.05434 0.16003,-14.060382 0.16003,-31.124436 V 26.176883 l -0.52136,-0.198219 c -0.66893,-0.254325 -4.77649,-0.95482 -7.159981,-1.221048 -2.41372,-0.269605 -8.559851,-0.266589 -10.759229,0.0052 -6.458111,0.798299 -12.584091,3.083792 -17.405651,6.49374 -2.267091,1.603366 -6.262831,5.498733 -7.64336,7.45136 l -0.959721,1.357438 v 29.828747 c 0,16.405812 0.0532,29.828746 0.11802,29.828746 0.065,0 0.77928,-0.65347 1.587482,-1.452149 z"
id="path845"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscccscsssscsssssscscsccsccsccscsscccccccscccccccccsccscscscccscccsccssccsscccscccccsccccsccscsccsscc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 20 20" height="48px" viewBox="0 0 20 20" width="48px" fill="#000000"><g><rect fill="none" height="20" width="20" x="0"/></g><g><g><path d="M14.45,10.86l0.26,2.1c0.06,0.46-0.1,0.92-0.43,1.25l-3.55,3.55l-1.41-4.24l-2.83-2.83L2.25,9.27l3.55-3.55 c0.33-0.33,0.79-0.49,1.25-0.43l2.1,0.26C13.92,0.78,17.8,2.2,17.8,2.2C17.8,2.2,19.22,6.08,14.45,10.86z M10.2,6.62 C9.18,7.64,8.37,9.06,7.9,9.97l2.12,2.12c0.91-0.46,2.34-1.27,3.36-2.3C16.18,7,16.54,4.67,16.5,3.5C15.33,3.46,13,3.82,10.2,6.62 z M14,7.5C14,6.68,13.32,6,12.5,6C11.67,6,11,6.68,11,7.5S11.67,9,12.5,9C13.32,9,14,8.33,14,7.5z M7.99,6.92L6.86,6.78L5.02,8.61 l1.62,0.54C6.97,8.52,7.43,7.71,7.99,6.92z M10.85,13.36l0.54,1.62l1.83-1.83l-0.14-1.14C12.29,12.57,11.48,13.03,10.85,13.36z M5.25,12.5c-0.62,0-1.18,0.25-1.59,0.66C2.44,14.38,2,18,2,18s3.62-0.44,4.84-1.66c0.41-0.41,0.66-0.97,0.66-1.59 C7.5,13.51,6.49,12.5,5.25,12.5z M5.78,15.28c-0.44,0.44-1.87,0.81-1.87,0.81s0.37-1.43,0.81-1.87c0.29-0.29,0.77-0.29,1.06,0 S6.07,14.99,5.78,15.28z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

-116
View File
@@ -1,116 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
import datetime
import pathlib
import tomli
project = "BEC Widgets"
copyright = f"{datetime.datetime.today().year}, Paul Scherrer Institute"
author = "Paul Scherrer Institute"
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
current_path = pathlib.Path(__file__).parent.parent.resolve()
version_path = f"{current_path}/pyproject.toml"
def get_version():
"""load the version from the version file"""
with open(version_path, "r", encoding="utf-8") as file:
res = tomli.loads(file.read())
return res["project"]["version"]
release = get_version()
extensions = [
# "sphinx.ext.coverage",
"sphinx.ext.napoleon",
"sphinx_toolbox.collapse",
"sphinx_copybutton",
"myst_parser",
"sphinx_design",
"sphinx_inline_tabs",
"autoapi.extension",
"sphinx.ext.viewcode",
]
myst_enable_extensions = [
"amsmath",
"attrs_inline",
"colon_fence",
"deflist",
"dollarmath",
"fieldlist",
"html_admonition",
"html_image",
"replacements",
"smartquotes",
"strikethrough",
"substitution",
"tasklist",
]
# AutoAPI configuration
autoapi_dirs = ["../bec_widgets"]
autoapi_type = "python"
autoapi_generate_api_docs = True
autoapi_add_toctree_entry = False # We'll control the toctree manually
autoapi_keep_files = False
autoapi_python_class_content = "both" # Include both class docstring and __init__
autoapi_member_order = "groupwise"
add_module_names = False # Remove namespaces from class/method signatures
autodoc_inherit_docstrings = True # If no docstring, inherit from base class
set_type_checking_flag = True # Enable 'expensive' imports for sphinx_autodoc_typehints
autoclass_content = "both" # Include both class docstring and __init__
autodoc_mock_imports = ["pyqtgraph", "qtpy", "PySide6"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
language = "Python"
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = "pydata_sphinx_theme"
html_static_path = ["_static"]
html_css_files = ["custom.css"]
html_logo = "../bec_widgets/assets/app_icons/bec_widgets_icon.png"
def skip_submodules(app, what, name, obj, skip, options):
if what == "module":
if not name.startswith("bec_widgets"):
skip = True
# print(f"Checking module: {name}")
if "bec_widgets.widgets" in name:
widget = name.split(".")[-2]
submodule = name.split(".")[-1]
if submodule in [f"register_{widget}", f"{widget}_plugin"]:
# print(f"Skipping submodule: {name}")
skip = True
elif what in ["data", "attribute"]:
obj_name = name.split(".")[-1]
if obj_name.startswith("_") or obj_name in ["__all__", "logger", "bec_logger", "app"]:
skip = True
elif what == "class":
class_name = name.split(".")[-1]
if class_name.startswith("Demo"):
skip = True
return skip
def setup(app):
app.connect("autoapi-skip-member", skip_submodules)
-52
View File
@@ -1,52 +0,0 @@
(developer)=
# Developer
Welcome to the BEC Widgets developer guide! BEC Widgets is a framework for building graphical user interfaces (GUIs) for [BEC](https://bec.readthedocs.io/en/latest/), a Python package for beamline experiment control.
This guide targets readers who want to develop new widgets or extend existing ones. If your goal is to use BEC Widgets to build GUIs for your experiments, please refer to the [user guide](#user).
```{toctree}
---
maxdepth: 2
hidden: true
---
introduction/introduction.md
widget_development/widget_development.md
api_reference/api_reference.md
```
***
````{grid} 2
:gutter: 5
```{grid-item-card}
:link: developer.introduction
:link-type: ref
:img-top: /assets/rocket_launch_48dp.svg
:text-align: center
:class-item: index-card
## Introduction
An introduction into the single-responsibility principle and the modular design of BEC Widgets.
```
```{grid-item-card}
:link: developer.widget_development
:link-type: ref
:img-top: /assets/apps_48dp.svg
:text-align: center
:class-item: index-card
## Widget Development
Learn how to develop a new modular widget for BEC Widgets.
```
````{grid} 2
-14
View File
@@ -1,14 +0,0 @@
(developer.concepts)=
# Concepts
This section provides an overview of the core concepts of BEC Widgets, which are based on the single-responsibility principle and modular design.
## Moduler Design
We develop widgets with the single-responsibility principle in mind, meaning each widget is designed for a specific task. Our goal is to keep widgets simple, using them primarily for visualization or to initiate actions within BEC. Following these ideas, widgets should be designed to be reusable in various applications, making them versatile building blocks for larger GUIs.
We offer up to three different options for composing larger GUIs from these modular widgets: BEC Designer, DockArea widget, or scripting from the command line interface. More information about these options can be found in the user sections on [applications](user.applications).
## Client-Server Architecture
BEC Widgets is built on top of the [BEC](https://bec.readthedocs.io/en/latest/) package, which provides the backend for beamline experiment control. BEC Widgets is a client of BEC, meaning it can interact with the backend through a client-server architecture. To make full usage of the available features of BEC, we recommend to check the documentation about [data access](https://bec.readthedocs.io/en/latest/developer/data_access/data_access.html) in which the messaging and event system of BEC is described.
In the context of BEC Widgets, the {py:class}`~bec_widgets.utils.bec_dispatcher.BECDispatcher` connects to this messaging and event system, allowing you to link your Qt [`Slots`](https://www.pythonguis.com/tutorials/pyside6-signals-slots-events/) to messages and event received from BEC.
@@ -1,28 +0,0 @@
(developer.contributing)=
# Contributing
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.11 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/).
3. **Qt Distributions:** BEC Widgets supports [PySide6](https://doc.qt.io/qtforpython-6/quickstart.html) and [PyQt6](https://www.riverbankcomputing.com/static/Docs/PyQt6/introduction.html). We use [qtpy](https://pypi.org/project/QtPy/) to abstract the underlying QT distribution.
**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 environment.
```bash
pip install -e '.[dev,pyside6]'
```
This installs the package together with [PySide6](https://doc.qt.io/qtforpython-6/quickstart.html).
@@ -1,16 +0,0 @@
(developer.introduction)=
# Introduction
BEC Widgets is a framework providing modular components that can be integrated into various larger GUI applications. Each widget serves a specific purpose adhering to the single-responsibility principle as detailed in our [concepts section](developer.concepts), and offers a straightforward, user-friendly interface.
These widgets provide data visualisation tools and experimental control interfaces by triggering actions within BEC.
If you're interested in contributing to BEC Widgets, please refer to our [contributing guide](developer.contributing), which provides instructions for setting up your development environment and creating your own widgets.
```{toctree}
---
maxdepth: 2
hidden: false
---
concepts/
contributing/
useful_links/
```
@@ -1,23 +0,0 @@
(developer.useful_links)=
# Useful Links
If you're new to the Qt framework, here are some helpful resources to get you started. In BEC Widgets, we use Qt
distributions based on Qt6, specifically PyQt6 and PySide6. However, all code should be written using
the [`qtpy`](https://pypi.org/project/QtPy/) abstraction layer, which allows compatibility with both. While both PyQt6
and PySide6 are supported, we prefer PySide6 as it is the official Python binding from the Qt Company. It offers
advantages like bundling all necessary libraries in a single package with pip installation and staying more up-to-date
compared to PyQt6.
Below is a list of useful links to help you start developing with Qt and Qt Designer:
- [Python GUIs](https://www.pythonguis.com): A great resource with tutorials and examples for creating GUIs in Python
using various frameworks.
- [PySide6 Quick Start Guide](https://doc.qt.io/qtforpython-6/index.html): The official documentation for PySide6,
including quick start guides and tutorials.
- [Qt Designer Official Documentation](https://doc.qt.io/qt-6/qtdesigner-manual.html): Comprehensive documentation for
Qt Designer, the underlying tool for BEC Designer.
- [Simple PyQt Tutorial from RealPython](https://realpython.com/python-pyqt-gui-calculator/): A beginner-friendly
tutorial on creating your first GUI application with PyQt.
- [PyQtGraph Documentation](https://pyqtgraph.readthedocs.io/en/latest/): BEC Widgets relies on PyQtGraph for plotting;
this is the official documentation.
@@ -1,139 +0,0 @@
(developer.widget_development.bec_dispatcher)=
# BECDispatcher
## Overview
The [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
is a powerful tool that simplifies the process of connecting [Qt slots](https://doc.qt.io/qt-6/signalsandslots.html) to message updates from the BEC server. It enables real-time communication between your widget and the BEC server by listening to specific message channels and triggering callbacks when new data is received.
This tool is especially useful for creating widgets that need to respond to dynamic data, such as device readbacks or
scan updates. By
using [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher),
you
can create callback functions that react to incoming messages and update your widget's state or perform other tasks
based on the data received.
## How It Works
When you create a widget that needs to respond to updates from the BEC server, you can use
the [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
to
connect specific Qt slots (callback functions) to message endpoints. These endpoints are defined within the BEC system
and represent specific channels of information (
e.g., [`device readback`](https://beamline-experiment-control.readthedocs.io/en/latest/api_reference/_autosummary/bec_lib.endpoints.MessageEndpoints.html#bec_lib.endpoints.MessageEndpoints.device_readback),
[`scan_segment`](https://beamline-experiment-control.readthedocs.io/en/latest/api_reference/_autosummary/bec_lib.endpoints.MessageEndpoints.html#bec_lib.endpoints.MessageEndpoints.scan_segment),
etc.).
### Step-by-Step Guide
1. **Create a Callback Function**: Define a function within your widget that will handle the data received from the BEC
server. This function must accept two parameters: `msg_content` (the message content) and `metadata` (
additional
information about the message).
```python
# Example for a callback function that updates a widget display based on motor readback data
from qtpy.QtCore import Slot
@Slot(dict, dict)
def on_device_readback(self, msg_content:dict, metadata:dict):
# Process the incoming data
new_value = msg_content["signals"]['motor_x']["value"]
# Update the widget's display or perform another action
self.update_display(new_value)
```
2. **Connect the Slot to an Endpoint**: Use
the [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
to connect your callback function to a specific
endpoint. The endpoint represents the type of data or message you're interested in.
```python
from bec_lib.endpoints import MessageEndpoints
self.bec_dispatcher.connect_slot(self.on_device_readback, MessageEndpoints.device_readback("motor_x"))
```
3. **Handle Incoming Data**: Your callback function will be triggered automatically whenever a new message is received
on the connected endpoint. Use the data in `msg_content` to update your widget or perform other actions.
4. **Clean Up Connections**: If your widget is being destroyed or you no longer need to listen for updates, make sure to
disconnect your slots from
the [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
to avoid memory or thread leaks.
```python
self.bec_dispatcher.disconnect_slot(self.on_device_readback, MessageEndpoints.device_readback("motor_x"))
```
### Example: Motor Map Widget
The [`BECMotorMap`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.widgets.figure.plots.motor_map.motor_map.BECMotorMap.html#bec-widgets-widgets-figure-plots-motor-map-motor-map-becmotormap)
widget is a great example of
how [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
can be used to handle real-time data updates. This
widget listens for updates on specific motor positions and dynamically updates the motor map display.
Here's a breakdown of
how [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
is used in
the [`BECMotorMap`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.widgets.figure.plots.motor_map.motor_map.BECMotorMap.html#bec-widgets-widgets-figure-plots-motor-map-motor-map-becmotormap)
widget:
1. **Connecting to Motor Readbacks**:
The widget connects to
the [`device readback`](https://beamline-experiment-control.readthedocs.io/en/latest/api_reference/_autosummary/bec_lib.endpoints.MessageEndpoints.html#bec_lib.endpoints.MessageEndpoints.device_readback)
endpoints using
the [`connect_slot`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher.connect_slot)
method
of [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher).
This allows
the widget to receive real-time updates about the motor positions.
```{literalinclude} ../../../bec_widgets/widgets/figure/plots/motor_map/motor_map.py
:language: python
:pyobject: BECMotorMap._connect_motor_to_slots
:dedent: 4
```
2. **Handling Readback Data**:
The `on_device_readback` slot is called whenever new data is received from the motor readback. This slot processes
the data and updates the motor map plot accordingly.
```{literalinclude} ../../../bec_widgets/widgets/figure/plots/motor_map/motor_map.py
:language: python
:pyobject: BECMotorMap.on_device_readback
:dedent: 4
```
3. **Updating the Plot**:
The motor map plot is updated in response to the new data, providing a real-time visualization of the motor's
position.
```{literalinclude} ../../../bec_widgets/widgets/figure/plots/motor_map/motor_map.py
:language: python
:pyobject: BECMotorMap._update_plot
:dedent: 4
```
4. **Disconnecting When No Longer Needed**:
The widget ensures that connections are properly cleaned up when no longer needed.
```{literalinclude} ../../../bec_widgets/widgets/figure/plots/motor_map/motor_map.py
:language: python
:pyobject: BECMotorMap._update_plot
:dedent: 4
```
## Conclusion
The [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher)
is a key tool for developing interactive and responsive widgets within the BEC framework. By leveraging this tool, you can create widgets that automatically respond to real-time data updates from the BEC server,
enhancing the interactivity and functionality of your user interface.
In next tutorials we will cover how to create a custom widget using the BECDispatcher and BECWidget base class.
```{note}
For more details on specific messages and endpoints, please refer to the [Message Endpoints Documentation](https://beamline-experiment-control.readthedocs.io/en/latest/api_reference/_autosummary/bec_lib.endpoints.MessageEndpoints.html#bec-lib-endpoints-messageendpoints).
```
@@ -1,81 +0,0 @@
(developer.widget_development.tutorial_tests)=
# Testing BEC Widgets
## Importance of Writing Tests for Widgets
Writing tests for widgets, even for simple ones, is crucial in maintaining the reliability and stability of a software
project. Tests help ensure that new contributions don't unintentionally break existing functionality, and they provide a
safety net for developers making changes in the future. In the context of the BEC Widgets, testing is particularly
important due to the complexity of interactions with external systems like the BEC server.
## Testing with Pytest and QtBot
For testing Qt-based applications, we use [`pytest`](https://docs.pytest.org/en/stable/) along with
the [`pytest-qt`](https://pytest-qt.readthedocs.io/en/latest/) plugin, which provides the `qtbot` fixture. `qtbot` is
specifically designed to simplify interactions with Qt applications during testing. It handles the creation, management,
and cleanup of widgets, ensuring that your tests are robust and do not leave behind any lingering resources or open
windows.
## Fixtures for Testing BEC Widgets
Let's break down the key fixtures used in testing BEC Widgets:
1. **`qapplication` Fixture**: This fixture ensures that all Qt applications and widgets are properly closed after each
test. It uses `qtbot` to wait until all top-level widgets are closed, raising an error if any remain open.
2. **`rpc_register` Fixture**: This fixture manages the `RPCRegister` singleton, ensuring that it is reset after each
test. This prevents state from leaking between tests, which could cause unexpected behavior.
3. **`bec_dispatcher` Fixture**: This fixture initializes the `BECDispatcher` and ensures that all connections are
properly disconnected and the BEC client is shut down after each test. Like `rpc_register`, it resets the singleton
after each test.
4. **`clean_singleton` Fixture**: This fixture cleans up any singleton instances used in error popups, preventing
interference between tests.
5. **`create_widget` Helper Function**: This function is a helper that should be used in all tests requiring widget
creation. It ensures that widgets are properly added to `qtbot`, which manages their lifecycle during tests. We
highly recommend using this function to create widgets in your tests to ensure proper cleanup and compatibility with
other `autouse` fixtures.
```{note}
These fixtures are automatically applied to all tests within the `tests/unit_tests` directory, ensuring consistency and proper cleanup between tests. You can find all unit test fixtures in the `conftest.py` file located in the `tests/unit_tests` directory of the BEC Widgets repository.
```
````{dropdown} View code: Conftest with Fixtures
:icon: code-square
:animate: fade-in-slide-down
```{literalinclude} ../../../tests/unit_tests/conftest.py
:language: python
```
````
## Example Test for `PositionerBox`
Below is an example of how to write a simple test for the [`PositionerBox`](user.widgets.positioner_box) widget,
utilizing the fixtures mentioned above:
````{dropdown} View code: PositionerBox Widget Unit Tests
:icon: code-square
:animate: fade-in-slide-down
```{literalinclude} ../../../tests/unit_tests/test_positioner_box.py
:language: python
```
````
## Key Points in the Test:
- **Fixture Use**: The `positioner_box` fixture handles widget creation and mocking of external dependencies. This
ensures the test runs in isolation and doesn't rely on actual hardware or network connections.
- **Assertion Checks**: The test includes several assertions to verify that the widget initializes correctly, including
checking the setpoint, precision, and step size.
## Conclusion
By writing tests like the one shown above, you help ensure that your widget behaves as expected. Tests also provide a
way to automatically verify that new changes do not introduce regressions. This is particularly important in a
collaborative environment where multiple developers are contributing to the same codebase. Your tests not only safeguard
your code but also provide confidence to others that their contributions won't break existing functionality.
@@ -1,192 +0,0 @@
(developer.widget_development.widget_base_class)=
# BECWidget Base Class
When developing new widgets, it is crucial to ensure seamless integration with the BEC system. This is achieved by using
the [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class, which provides essential functionalities and shortcuts to interact with various BEC services. In this
tutorial, we will explore the importance of this base class, the role of
the [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
mixin, and how these components work together to facilitate the development of powerful and responsive widgets.
## Understanding the `BECWidget` Base Class
The [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class is designed to serve as the foundation for all BEC-connected widgets. It ensures that your widget is properly
integrated with the BEC system by providing:
1. **Connection to BEC Services**:
[`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget) includes the [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
mixin, which handles all the necessary connections to BEC services such as the BEC server, device manager, scan
control, and more.
2. **Qt Integration**:
The [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class also ensures that your widget is correctly integrated with Qt by requiring that it inherits from
both [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
and [`QWidget`](https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QWidget.html). This combination allows your widget
to leverage the full power of Qt for creating rich user interfaces while staying connected to the BEC ecosystem.
3. **Configuration Management**: The base class provides a `ConnectionConfig` model (based on Pydantic) that helps
manage and validate the configuration of your widget. This configuration can be easily serialized to and from Python
dictionaries, JSON, or YAML formats, allowing for persistent storage and retrieval of widget states.
4. **RPC Registration**: Widgets derived
from [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
are automatically registered with
the [`RPCRegister`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.cli.rpc_register.RPCRegister.html#bec_widgets.cli.rpc_register.RPCRegister),
enabling them to handle remote procedure calls (RPCs) efficiently. This allows the widget to be controlled remotely
from the `BECIPythonClient` via CLI, providing powerful control and automation capabilities. For example, you can
remotely adjust widget settings, start/stop operations, or query the widgets status directly from the command line.
5. **Reacting to Theme Changes**: The base class provides a dedicated input flag to subscribe to theme changes, allowing
your widget to adapt its appearance based on the current theme (e.g., light or dark mode) and can even synchronize with the user's OS settings. The widget-specific logic can then
be implemented in the `apply_theme` method, which is called whenever the theme changes. This ensures a consistent user experience across different themes and environments.
Heres a basic example of a widget inheriting
from [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget):
```python
from bec_widgets.utils.bec_widget import BECWidget
from qtpy.QtWidgets import QWidget, QVBoxLayout
class MyWidget(BECWidget, QWidget):
def __init__(self, parent=None, *args, **kwargs):
super().__init__(*args, **kwargs) # disable theme updates
QWidget.__init__(self, parent=parent)
self.get_bec_shortcuts() # Initialize BEC shortcuts
self.init_ui()
def init_ui(self):
layout = QVBoxLayout(self)
# Add more UI components here
self.setLayout(layout)
# To enable theme updates, set theme_update=True, e.g.:
class MyDynamicWidget(BECWidget, QWidget):
def __init__(self, parent=None, *args, **kwargs):
super().__init__(*args, theme_update=True, **kwargs) # enable theme updates
QWidget.__init__(self, parent=parent)
self.get_bec_shortcuts() # Initialize BEC shortcuts
self.init_ui()
def init_ui(self):
layout = QVBoxLayout(self)
# Add more UI components here
self.setLayout(layout)
def apply_theme(self, theme):
# Implement theme-specific logic here
pass
```
### The Role of `BECConnector`
At the heart
of [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
is
the [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
mixin, which plays a crucial role in managing the connection between your widget and the BEC system.
The [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
provides several key functionalities:
1. **Client Initialization**: It initializes a `BECClient` instance if one isn't provided, ensuring your widget is
connected to the BEC server. This client is central to all interactions with the BEC system.
2. **Task Management**:
The [`submit_task`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector.submit_task)
method allows for running tasks in separate threads, preventing long-running operations from blocking the main UI
thread.
3. **Configuration Handling
**: [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
uses the `ConnectionConfig` model to manage the widgets configuration, ensuring all parameters are validated and
properly set up.
4. **RPC Registration**: Widgets are registered with
the [`RPCRegister`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.cli.rpc_register.RPCRegister.html#bec-widgets-cli-rpc-register-rpcregister),
allowing them to handle remote procedure calls effectively.
5. **Error Handling**: It includes utilities for handling errors gracefully within the Qt environment, ensuring that
issues are reported to the user without crashing the application.
### Utilizing `get_bec_shortcuts`
One of the most powerful features of
the [`BECConnector`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_connector.BECConnector.html#bec_widgets.utils.bec_connector.BECConnector)
is the `get_bec_shortcuts` method. This method provides your widget with direct access to essential components of the
BEC system through convenient shortcuts:
1. **Device Manager (`self.dev`)**:
- Access all devices registered with the BEC system. You can interact with devices, retrieve their status, and send
commands directly through this shortcut.
```python
# Moves 'motor1' to position 10
self.dev["motor1"].move(10)
```
2. **Scan Control (`self.scans`)**:
- Control scans, initiate new ones, monitor progress, and manage their execution.
```python
# Starts Line Scan from -10 to 10 in samx and -5 to 5 in samy
self.scans.line_scan(self.dev.samx,-10,10,self.dev.samy,-5,5, steps=100, exp_time=0.001,relative=False)
```
3. **Queue Management (`self.queue`)**:
- Manage the BEC scan queue, such as adding scans, checking status, or removing scans.
```python
# Request abortion of the current scan queue
self.queue.request_scan_abortion()
```
4. **Scan Storage (`self.scan_storage`)**:
- Access stored scan data for retrieval and analysis.
```python
# Retrieve scan item for a specific scan ID
self.scan_item = self.queue.scan_storage.find_scan_by_ID(self.scan_id)
```
5. **Full BECClient Access (`self.client`)**:
- Direct access to the BECClient instance, allowing for additional functionalities not covered by the shortcuts.
```python
# Shutdown the BECClient
self.client.shutdown()
```
### Example: [`PositionerBox`](user.widgets.positioner_box) Widget
Lets look at an example of a widget that leverages
the [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class and `get_bec_shortcuts`:
````{dropdown} View code: PositionerBox Widget
:icon: code-square
:animate: fade-in-slide-down
```{literalinclude} ../../../bec_widgets/widgets/positioner_box/positioner_box.py
:language: python
:pyobject: PositionerBox
```
````
In this widget:
- **Device Interaction**: The widget uses `self.dev` to interact with a positioner device, reading its state and
updating the UI accordingly.
- **Scan and Queue Control**: Although not shown in this example, the widget could easily use `self.scans`
and `self.queue` to manage scans related to the positioner or queue up new operations.
### Conclusion
The `BECWidget` base class and the `BECConnector` mixin are foundational components for creating widgets that seamlessly
integrate with the BEC system. By inheriting from `BECWidget`, you gain access to powerful connection management, task
handling, and configuration capabilities, as well as shortcuts that make interacting with BEC services straightforward
and efficient.
By leveraging these tools, you can focus on building the core functionality of your widget, confident that the
complexities of BEC integration are handled robustly and efficiently. In the next tutorial we will demonstrate
step-by-step how to create a custom widget using the `BECWidget` base class and explore advanced features for creating
responsive and interactive user interfaces.
@@ -1,56 +0,0 @@
(developer.widget_development)=
# Widget Development
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).
To facilitate the development of new widgets, integrated into the BEC framework, we provide two main base classes: `BECWidget` and its parent class `BECDispatcher`. The `BECDispatcher` class is responsible for managing the communication between widgets and the BEC framework. The `BECWidget` class is the base class for all widgets and provides the basic functionality for creating and managing widgets. Leveraging these classes, you can rapidly develop new widgets that are responsive and interactive.
A very simple "Hello World" example of a widget can be seen below:
````{dropdown} View code: Hello World Widget
:icon: code-square
:animate: fade-in-slide-down
```python
from qtpy.QtWidgets import QLabel, QWidget
from bec_widgets.utils.bec_widget import BECWidget
class HelloWorldWidget(BECWidget, QWidget):
def __init__(
self, parent: QWidget | None = None, client=None, gui_id: str | None = None, **kwargs
) -> None:
# Initialize base classes
super().__init__(parent=parent, client=client, gui_id=gui_id, **kwargs)
self.label = QLabel(self)
self.label.setText("Hello World")
# Run the widget as a standalone application
if __name__ == "__main__":
import sys
from qtpy.QtWidgets import QApplication
app = QApplication(sys.argv)
w = HelloWorldWidget()
w.show()
sys.exit(app.exec_())
```
````
The following sections will provide more details on how to develop new widgets and how to leverage the `BECDispatcher` and `BECWidget` classes to create interactive and responsive widgets.
```{toctree}
---
maxdepth: 2
hidden: false
---
bec_dispatcher
widget_base_class
widget_tutorial
tutorial_tests
```
@@ -1,243 +0,0 @@
(developer.widget_development.widget_tutorial)=
# Tutorial: Creating a New BEC-Connected Widget
In this tutorial, we'll create a BEC-connected widget that allows you to control a motor by setting its position. The
widget will demonstrate how to retrieve data from BEC, prompt an action in BEC (like moving a motor), and expose an RPC
interface for remote control. By the end of this tutorial, you'll have a functional widget that can interact with the
BEC system both through a graphical interface and via command-line control.
We'll break the tutorial into the following steps:
1. **Creating the Basic Widget Layout**: Well design a simple UI with a `QLabel`, `QDoubleSpinBox`, and
a `QPushButton`.
2. **Connecting to BEC**: Well integrate our widget with the BEC system using
the [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class
and [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher).
3. **Implementing RPC for Remote Control**: Well set up an RPC interface to allow remote control of the widget via CLI.
4. **Running the Widget**: Well create a small script to run the widget in a `QApplication`.
## Step 1: Creating the Basic Widget Layout
First, let's start by creating the basic layout of our widget. Well add a `QLabel` to display the current coordinates
of the motor, a `QDoubleSpinBox` to input the desired coordinates, and a `QPushButton` to initiate the motor movement.
```python
from qtpy.QtWidgets import QWidget, QLabel, QDoubleSpinBox, QPushButton, QVBoxLayout
class MotorControlWidget(QWidget):
def __init__(self, parent=None, motor_name: str = ""):
super().__init__(parent)
self.motor_name = motor_name
# Initialize UI elements
self.label_top = QLabel("Current Position:", self)
self.label = QLabel(f"{self.motor_name} - N/A", self)
self.spin_box = QDoubleSpinBox(self)
self.spin_box.setRange(-10000, 10000)
self.spin_box.setDecimals(3)
self.spin_box.setSingleStep(0.1)
self.move_button = QPushButton("Move Motor", self)
# Set up the layout
layout = QVBoxLayout(self)
layout.addWidget(self.label_top)
layout.addWidget(self.label)
layout.addWidget(self.spin_box)
layout.addWidget(self.move_button)
self.setLayout(layout)
# Connect button click to move motor
self.move_button.clicked.connect(self.move_motor)
def move_motor(self):
# Placeholder method for motor movement
print(f"Moving motor {self.motor_name} to {self.spin_box.value()}")
```
## Step 2: Connecting to BEC
Now that we have the basic layout, let's connect our widget to the BEC system using
the [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class
and [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher).
Well modify the widget to inherit
from [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget),
pass the motor name to the widget, and use `get_bec_shortcuts` to access BEC services.
```python
from bec_lib.endpoints import MessageEndpoints
from qtpy.QtWidgets import QDoubleSpinBox, QLabel, QPushButton, QVBoxLayout, QWidget
from bec_widgets.utils.bec_widget import BECWidget
from bec_widgets.utils.error_popups import SafeSlot
class MotorControlWidget(BECWidget, QWidget):
def __init__(self, parent=None, motor_name: str = "", **kwargs):
super().__init__(parent=parent, **kwargs)
self.motor_name = motor_name
# Initialize BEC shortcuts
self.get_bec_shortcuts()
# Initialize UI elements
self.label_top = QLabel(f"Current Position:", self)
self.label = QLabel(f"{self.motor_name} - N/A", self)
self.spin_box = QDoubleSpinBox(self)
self.spin_box.setRange(-10000, 10000)
self.spin_box.setDecimals(3)
self.spin_box.setSingleStep(0.1)
self.move_button = QPushButton("Move Motor", self)
# Set up the layout
layout = QVBoxLayout(self)
layout.addWidget(self.label_top)
layout.addWidget(self.label)
layout.addWidget(self.spin_box)
layout.addWidget(self.move_button)
self.setLayout(layout)
# Connect button click to move motor
self.move_button.clicked.connect(self.move_motor)
# Register BECDispatcher to listen for motor position updates
self.bec_dispatcher.connect_slot(
self.on_motor_update, MessageEndpoints.device_readback(self.motor_name)
)
@SafeSlot()
def move_motor(self):
target_position = self.spin_box.value()
self.dev[self.motor_name].move(target_position)
print(f"Commanding motor {self.motor_name} to move to {target_position}")
@SafeSlot(dict, dict)
def on_motor_update(self, msg_content, metadata):
position = msg_content.get("signals", {}).get(self.motor_name, {}).get("value", "N/A")
self.label.setText(f"{self.motor_name} : {round(position, 2)}")
```
## Step 3: Implementing RPC for Remote Control
Next, well set up an RPC interface to allow remote control of the widget from the command line via
the `BECIPythonClient`. Well expose a method that allows changing the motor name through CLI commands.
```python
from bec_lib.endpoints import MessageEndpoints
from qtpy.QtWidgets import QDoubleSpinBox, QLabel, QPushButton, QVBoxLayout, QWidget
from bec_widgets.utils.bec_widget import BECWidget
from bec_widgets.utils.error_popups import SafeSlot
class MotorControlWidget(BECWidget, QWidget):
USER_ACCESS = ["change_motor"]
def __init__(self, parent=None, motor_name: str = "", **kwargs):
super().__init__(parent=parent, **kwargs)
self.motor_name = motor_name
# Initialize BEC shortcuts
self.get_bec_shortcuts()
# Initialize UI elements
self.label_top = QLabel(f"Current Position:", self)
self.label = QLabel(f"{self.motor_name} - N/A", self)
self.spin_box = QDoubleSpinBox(self)
self.spin_box.setRange(-10000, 10000)
self.spin_box.setDecimals(3)
self.spin_box.setSingleStep(0.1)
self.move_button = QPushButton("Move Motor", self)
# Set up the layout
layout = QVBoxLayout(self)
layout.addWidget(self.label_top)
layout.addWidget(self.label)
layout.addWidget(self.spin_box)
layout.addWidget(self.move_button)
self.setLayout(layout)
# Connect button click to move motor
self.move_button.clicked.connect(self.move_motor)
# Register BECDispatcher to listen for motor position updates
self.bec_dispatcher.connect_slot(
self.on_motor_update, MessageEndpoints.device_readback(self.motor_name)
)
@SafeSlot()
def move_motor(self):
target_position = self.spin_box.value()
self.dev[self.motor_name].move(target_position)
print(f"Commanding motor {self.motor_name} to move to {target_position}")
@SafeSlot(dict, dict)
def on_motor_update(self, msg_content, metadata):
position = msg_content.get("signals", {}).get(self.motor_name, {}).get("value", "N/A")
self.label.setText(f"{self.motor_name} : {round(position, 2)}")
def change_motor(self, motor_name):
"""RPC method to change the motor being controlled."""
# Disconnect from previous motor
self.bec_dispatcher.disconnect_slot(
self.on_motor_update, MessageEndpoints.device_readback(self.motor_name)
)
# Update motor name and reconnect to new motor
self.motor_name = motor_name
self.label.setText(f"{self.motor_name} - N/A")
self.bec_dispatcher.connect_slot(
self.on_motor_update, MessageEndpoints.device_readback(self.motor_name)
)
```
```{warning}
After implementing an RPC method, you must run the `bw-generate-cli --target <your plugin repo name>` script to update the CLI commands for `BECIPythonClient`, e.g. `bw-generate-cli --target csaxs_bec`. This script generates the necessary command-line interface bindings, ensuring that your RPC method can be accessed and controlled remotely.
```
```{note}
In this tutorial, we used the @SafeSlot decorator from BEC Widgets to mark methods as slots for signals. This decorator ensures that the connected methods are treated as slots by the Qt framework, which can be connected to signals. Its a best practice to use the @SafeSlot decorator to clearly indicate which methods are intended to handle signal events with correct argument signatures. @SafeSlot also provides error handling and logging capabilities, making it more robust and easier to debug.
```
## Step 4: Running the Widget
Finally, lets create a script to run our widget within a `QApplication`. This script can be used to test the widget
independently. You can pass different motor names to control different motors using the same widget class.
```python
import sys
from qtpy.QtWidgets import QApplication
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = MotorControlWidget(motor_name='samx')
widget.show()
sys.exit(app.exec_())
```
## Conclusion
In this tutorial, we've created a BEC-connected widget that allows you to control a motor. We started by designing the
UI, then connected it to the BEC system using
the [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class
and [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher).
We also implemented an RPC interface, allowing remote control of the widget through the CLI. Finally, we tested our
widget by running it in a `QApplication`.
This widget demonstrates a simplified version of the [`PositionerBox`](user.widgets.positioner_box), showcasing the
power and flexibility of
the [`BECWidget`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_widget.BECWidget.html#bec_widgets.utils.bec_widget.BECWidget)
base class
and [`BECDispatcher`](https://bec.readthedocs.io/projects/bec-widgets/en/latest/api_reference/_autosummary/bec_widgets.utils.bec_dispatcher.BECDispatcher.html#bec_widgets.utils.bec_dispatcher.BECDispatcher),
making it easy to integrate with the BEC system and enabling robust, interactive control of devices directly from the
GUI or the command line.
-74
View File
@@ -1,74 +0,0 @@
:html_theme.sidebar_secondary.remove:
# BEC Widgets documentation
A flexible and extensible framework for building graphical user interfaces in Python, optimized for use in the BEC environment.
<br><br>
````{grid} 2
:gutter: 5
```{grid-item-card}
:link: introduction
:link-type: ref
:img-top: /assets/index_getting_started.svg
:text-align: center
:class-item: index-card
## Introduction
General information about BEC Widgets.
```
```{grid-item-card}
:link: user
:link-type: ref
:img-top: /assets/index_user_guide.svg
:text-align: center
:class-item: index-card
## User guide
Information for users of BEC Widgets.
```
```{grid-item-card}
:link: developer
:link-type: ref
:img-top: /assets/index_contribute.svg
:text-align: center
:class-item: index-card
## Developer guide
Information for developers of BEC Widgets.
```
```{grid-item-card}
:link: api_reference
:link-type: ref
:img-top: /assets/index_api.svg
:text-align: center
:class-item: index-card
## API reference
Comprehensive reference of all BEC Widget classes, functions, and methods.
```
````
```{toctree}
---
numbered: true
maxdepth: 2
hidden: true
---
introduction/introduction
user/user
developer/developer
api_reference/api_reference
```
-18
View File
@@ -1,18 +0,0 @@
(introduction)=
# Introduction
## Overview
BEC Widgets is a GUI framework developed with beamline scientists in mind, aiming to provide a modern and modular environment for interacting with experiments. This package offers a suite of widgets specifically designed to enhance the workflow of beamline experiments, including features for running scans and data visualization.
Targeting the unique needs of beamline scientists, BEC Widgets stands out with its modular approach to widget design and high customizability. This flexibility allows for tailored solutions that meet the specific requirements of each beamline.
**Key Features**:
- **Integration:** Seamlessly integrates with [BEC (Beamline Experiment Control)](https://gitlab.psi.ch/bec/bec), ensuring a cohesive and efficient experiment control experience.
- **Support for Pyside6 and PyQt6:** Provides compatibility with both Pyside6 and PyQt6, offering versatility in your development environment.
- **Widget Modularity:** Features modular widgets that can be easily combined to create customized applications, perfectly aligning with the diverse needs of beamline experiments.
## Getting Started
For detailed usage instructions and examples showcasing the practical applications of BEC Widgets, please refer to the [User](#user) section. Developers interested in contributing or customizing BEC Widgets can find more information in the [Developer](#developer) section.
-35
View File
@@ -1,35 +0,0 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
-11
View File
@@ -1,11 +0,0 @@
sphinx
sphinx_copybutton
recommonmark
sphinx-toolbox
pydata-sphinx-theme
sphinx-copybutton
sphinx-inline-tabs
myst-parser
sphinx-design
sphinx-autoapi
tomli
-10
View File
@@ -1,10 +0,0 @@
(user.api_reference)=
# User API Reference
This section contains the API documentation for the main user-facing modules and classes.
```{toctree}
:maxdepth: 2
../../autoapi/bec_widgets/cli/index
```
-10
View File
@@ -1,10 +0,0 @@
(user.applications)=
# Applications
**Coming soon**
```{toctree}
---
maxdepth: 1
hidden: true
---
-123
View File
@@ -1,123 +0,0 @@
(user.customisation)=
# Customisation
## Leveraging BEC Widgets in custom GUI applications
BEC Widgets can be used to compose a complete Qt graphical application, along with
other QWidgets. The only requirement is to connect to BEC servers in order to get
data, or to interact with BEC components. This role is devoted to the BECDispatcher,
a singleton object which has to be instantiated **after the QApplication is created**.
A typical BEC Widgets custom application "main" entry point should follow the template
below:
```
import argparse
import sys
from bec_widgets.utils.bec_dispatcher import BECDispatcher
from qtpy.QtWidgets import QApplication
# optional command line arguments processing
parser = argparse.ArgumentParser(description="...")
parser.add_argument( ...)
...
args = parser.parse_args()
# creation of the Qt application
app = QApplication([])
# creation of BEC Dispatcher
# /!\ important: after the QApplication has been instantiated
bec_dispatcher = BECDispatcher()
client = bec_dispatcher.client
client.start()
# (optional) processing of command line args,
# creation of a main window depending on the command line arguments (or not)
if args.xxx == "...":
window = ...
# display of the main window and start of Qt event loop
window.show()
sys.exit(app.exec())
```
The main "window" object presents the layout of widgets to the user and allows
users to interact. BEC Widgets must be placed in the window:
```
from qtpy.QWidgets import QMainWindow
from bec_widgets.widgets.figure import BECFigure
window = QMainWindow()
bec_figure = BECFigure(gui_id="my_gui_app_id")
window.setCentralWidget(bec_figure)
# prepare to plot samx motor vs bpm4i value
bec_figure.plot(device_x="samx", device_y="bpm4i")
```
In the example just above, the resulting application will show a plot of samx
positions on the horizontal axis, and beam intensity on the vertical axis
(when the next scan will be started).
It is important to ensure proper cleanup of the resources is done when application
quits:
```
def final_cleanup():
bec_figure.clear_all()
bec_figure.client.shutdown()
window.aboutToQuit.connect(final_cleanup)
```
Final example:
```
import sys
from qtpy.QtWidgets import QMainWindow, QApplication
from bec_widgets.widgets.figure import BECFigure
from bec_widgets.utils.bec_dispatcher import BECDispatcher
# creation of the Qt application
app = QApplication([])
# creation of BEC Dispatcher
bec_dispatcher = BECDispatcher()
client = bec_dispatcher.client
client.start()
# creation of main window
window = QMainWindow()
# inserting BEC Widgets
bec_figure = BECFigure(parent=window, gui_id="my_gui_app_id")
window.setCentralWidget(bec_figure)
bec_figure.plot(device_x="samx", device_y="bpm4i")
# ensuring proper cleanup
def final_cleanup():
bec_figure.clear_all()
bec_figure.client.shutdown()
app.aboutToQuit.connect(final_cleanup)
# execution
window.show()
sys.exit(app.exec())
```
## Writing applications using BEC Designer
BEC Widgets are designed to be used with BEC Designer to quickly design GUI.
## Example of promoting widgets in BEC Designer
_Work in progress_
## Implementation of plugins into BEC Designer
_Work in progress_
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

-129
View File
@@ -1,129 +0,0 @@
(user.auto_updates)=
# Auto updates
BEC Widgets provides a simple way to update the entire GUI configuration based on events. These events can be of different types, such as a new scan being started or completed, a button being pressed, a device reporting an error or the existence of a specific metadata key. This allows the users to streamline the experience of the GUI and to focus on the data and the analysis, rather than on the GUI itself.
The auto update widget can be launched through the BEC launcher:
![BEC launcher](launcher.png)
The auto update's launch tile also provides a combo box to select the specific auto update to be launched. These options are automatically populated with all available auto updates from a plugin repository and the default auto update.
Once the proper auto update is selected and launched, the CLI will automatically add a new entry to the `gui` object.
The default auto update only provides a simple handler that switches between `line_scan`, `grid_scan` and `best_effort`. More details can be found in the following snippet.
````{dropdown} Auto Updates Handler
:icon: code-square
:animate: fade-in-slide-down
:open:
```{literalinclude} ../../../bec_widgets/widgets/containers/auto_update/auto_updates.py
:pyobject: AutoUpdates.on_scan_open
```
````
As shown, the default auto updates switches between different visualizations whenever a new scan is started. If the scan is a `line_scan`, the `simple_line_scan` update method is executed.
````{dropdown} Auto Updates Simple Line Scan
:icon: code-square
:animate: fade-in-slide-down
:open:
```{literalinclude} ../../../bec_widgets/widgets/containers/auto_update/auto_updates.py
:pyobject: AutoUpdates.simple_line_scan
```
````
As can be seen from the above snippet, the update method changes the dock to a specific widget, in this case to a waveform widget. After selecting the device for the x axis, the y axis is retrieved from the list of monitored devices or from a user-specified `selected_device`.
The y axis can also be set by the user using the `selected_device` attribute:
```python
gui.AutoUpdates.selected_device = 'bpm4i'
```
````{dropdown} Auto Updates Code
:icon: code-square
:animate: fade-in-slide-down
```{literalinclude} ../../../bec_widgets/widgets/containers/auto_update/auto_updates.py
```
````
## Custom Auto Updates
The beamline can customize their default behaviour through customized auto update classes. This can be achieved by adding an auto update class to the plugin repository: `<beamline_plugin>/bec_widgets/auto_updates/auto_updates.py`. The class must inherit from the `AutoUpdates` class.
An example of a custom auto update class `PXIIIUpdate` is shown below.
```{note}
The code below is simply a copy of the default auto update class's 'GUI Callbacks' section. The user can modify any of the methods to suit their needs but we suggest to have a look at the 'GUI Callbacks' section and the 'Update Functions' section of the default auto update class to understand how to implement the custom auto update class.
```
```python
from __future__ import annotations
from typing import TYPE_CHECKING
from bec_widgets.widgets.containers.auto_update.auto_updates import AutoUpdates
if TYPE_CHECKING: # pragma: no cover
from bec_lib.messages import ScanStatusMessage
class PXIIIUpdate(AutoUpdates):
#######################################################################
################# GUI Callbacks #######################################
#######################################################################
def on_start(self) -> None:
"""
Procedure to run when the auto updates are enabled.
"""
self.start_default_dock()
def on_stop(self) -> None:
"""
Procedure to run when the auto updates are disabled.
"""
def on_scan_open(self, msg: ScanStatusMessage) -> None:
"""
Procedure to run when a scan starts.
Args:
msg (ScanStatusMessage): The scan status message.
"""
if msg.scan_name == "line_scan" and msg.scan_report_devices:
return self.simple_line_scan(msg)
if msg.scan_name == "grid_scan" and msg.scan_report_devices:
return self.simple_grid_scan(msg)
if msg.scan_report_devices:
return self.best_effort(msg)
return None
def on_scan_closed(self, msg: ScanStatusMessage) -> None:
"""
Procedure to run when a scan ends.
Args:
msg (ScanStatusMessage): The scan status message.
"""
def on_scan_abort(self, msg: ScanStatusMessage) -> None:
"""
Procedure to run when a scan is aborted.
Args:
msg (ScanStatusMessage): The scan status message.
"""
```
````{important}
In order for the custom auto update method to be found, the class must be added to the `__init__.py` file of the `auto_updates` folder. This should be done already when the plugin repository is created but it is worth mentioning here. If not, the user can add the following line to the `__init__.py` file:
```python
from .auto_updates import *
```
````
@@ -1,15 +0,0 @@
(user.getting_started)=
# Getting Started
This section provides a comprehensive guide to getting started with BEC Widgets. Whether you are new to BEC Widgets or looking to refresh your knowledge, this guide will help you set up and navigate the framework with ease.
```{toctree}
---
maxdepth: 2
hidden: true
---
installation/
quick_start/
auto_updates/
video_tutorials/
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 MiB

-32
View File
@@ -1,32 +0,0 @@
(user.installation)=
# Installation
**Prerequisites**
Before installing BEC Widgets, please ensure the following requirements are met:
1. **Python Version:** BEC Widgets requires Python version 3.11 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/).
**Standard Installation**
To install BEC Widgets using the pip package manager, execute the following command in your terminal for getting the
default PySide6 version into your python environment for BEC:
```bash
pip install 'bec_widgets[pyside6]'
```
**Troubleshooting**
If you encounter issues during installation, particularly with Qt, try purging the pip cache:
```bash
pip cache purge
```
This can resolve conflicts or issues with package installations.
```{warning}
At the moment PyQt6 is no longer officially supported by BEC Widgets due to incompatibilities with BEC Designer. Please use PySide6 instead.
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 KiB

-144
View File
@@ -1,144 +0,0 @@
(user.command_line_introduction)=
# Quick start
In order to use BEC Widgets as a plotting tool for BEC, it needs to be [installed](#user.installation) in the same Python environment as the BEC IPython client (please refer to the [BEC documentation](https://bec.readthedocs.io/en/latest/user/command_line_interface.html#start-up) for more details). Upon startup, the client will automatically launch a GUI and store it as a `gui` object in the client. The GUI backend will also be automatically connect to the BEC server, giving access to all information on the server and allowing the user to visualize the data in real-time.
## BECGuiClient
The `gui` object is the main entry point for interacting with the BEC Widgets framework. It is an instance of the {py:class}`~bec_widgets.cli.client_utils.BECGuiClient` class, which provides methods to create and manage GUI components. Upon BEC startup, a default {py:class}`~bec_widgets.cli.client.BECDockArea` instance named *bec* is automatically launched.
A launcher interface is available via the top menu bar under New → Open Launcher. This opens a window where users can launch a new {py:class}`~bec_widgets.cli.client.BECDockArea` instance, an [AutoUpdate](#user.auto_updates) instance, individual widgets or a custom *ui file* created with *BEC Designer*. Alternatively, users can launch a new {py:class}`~bec_widgets.cli.client.BECDockArea` from the command line:
```python
dock_area = gui.new() # launches a new BECDockArea instance
gui.new('my_dock_area') # launches a new BECDockArea instance with the name 'my_dock_area'
dock_area2 = gui.my_dock_area # Dynamic attribute access to created dock_area
```
``` {note}
If a name is provided, the new dock area will use that name. If the name already exists, an error is raised. If no name is specified, a name will be auto-generated following the pattern *dock_area_ii* where *ii* is the next available number. Named dock areas can be accessed dynamically as attributes of the gui object.
```
## BECDockArea
The {py:class}`~bec_widgets.cli.client.BECDockArea` is a versatile container for quickly building customized GUIs. It supports adding new widgets either through the CLI or directly via toolbar actions. Widgets must be added into {py:class}`~bec_widgets.cli.client.BECDockArea` instances, which serve as the individual containers. These docks can be arranged freely, detached from the main window, and used as floating panels.
From the CLI, you can create new docks like this:
```python
dock_area = gui.new()
dock = dock_area.new(name='my_dock_area')
dock = gui.new().new()
```
<!-- **Schema of the BECDockArea**
![BECDockArea.png](BECDockArea.png) -->
## Widgets
Widgets are the building blocks of the BEC Widgets framework. They are the visual components that allow users to interact with the data and control the behavior of the application. Each dock can contain multiple widgets, albeit we recommend for most use cases a single widget per dock. BEC Widgets provides a set of core widgets (cf. {ref}`user.widgets`). More widgets can be added by the users, and we invite you to explore the {ref}`developer.widgets` to learn how to create custom widgets.
For the introduction given here, we will focus on the plotting widgets of BECWidgets.
<!-- We also provide two methods [`plot()`](/api_reference/_autosummary/bec_widgets.cli.client.BECFigure.rst#bec_widgets.cli.client.BECFigure.plot), [`image()`](/api_reference/_autosummary/bec_widgets.cli.client.BECFigure.rst#bec_widgets.cli.client.BECFigure.image) and [`motor_map()`](/api_reference/_autosummary/bec_widgets.cli.client.BECFigure.rst#bec_widgets.cli.client.BECFigure.motor_map) as shortcuts to add a plot, image or motor map to the BECFigure. -->
**Waveform Plot**
The {py:class}`~bec_widgets.cli.client.Waveform` is a widget that can be used to visualize 1D waveform data, i.e. to plot data of a monitor against a motor position. The method {py:meth}`~bec_widgets.cli.client.Waveform.plot` returns the plot object.
```python
plt = gui.new().new().new(gui.available_widgets.Waveform)
plt.plot(device_x='samx', device_y='bpm4i')
```
Here, we create a new plot with a subscription to the devices `samx` and `bpm4i` and assign the plot to the object `plt`. We can now use this object to further customize the plot, e.g. changing the title (`title`), axis labels (`x_label`)
<!-- or limits (`x_lim`). -->
We invite you to explore the API of the WaveForm in the {ref}`user.widgets.waveform_1d` or directly in the command line.
To plot custom data, i.e. data that is not directly available through a scan in BEC, we can use the same method, but provide the data directly to the plot.
```python
plt = gui.new().new().new(gui.available_widgets.Waveform)
#
plt.plot([1,2,3,4], [1,4,9,16])
# or
plt.plot(x=np.array([1,2,3,4]), y=np.array([1,4,9,16]))
# or
plt.plot(np.random.rand(10,2))
# or if you like to receive the custom curve item
curve = plt.plot(x=[1,2,3,4], y=[1,4,9,16])
```
**Scatter Plot**
The {py:class}`~bec_widgets.cli.client.Waveform` widget can also be used to visualize 2D scatter plots. More details on setting up the scatter plot are available in the widget documentation of the {ref}`user.widgets.scatter_2d`.
**Motor Map**
The {py:class}`~bec_widgets.cli.client.MotorMap` widget can be used to visualize the position of motors. It's focused on tracking and visualizing the position of motors, crucial for precise alignment and movement tracking during scans. More details on setting up the motor map are available in the widget documentation of the {ref}`user.widgets.motor_map`.
**Image Plot**
The {py:class}`~bec_widgets.cli.client.Image` widget can be used to visualize 2D image data for example a camera. More details on setting up the image plot are available in the widget documentation of the {ref}`user.widgets.image`.
### Useful Commands
We recommend users to explore the API of the widgets by themselves since we assume that the user interface is supposed to be intuitive and self-explanatory. We appreciate feedback from user in order to constantly improve the experience and allow easy access to the gui, widgets and their functionality. We recommend checking the {ref}`user.api_reference`, but also by using BEC Widgets, exploring the available functions and check their dockstrings.
```python
gui.new? # shows the dockstring of the new method
```
In addition, we list below a few useful commands that can be used to interface with the widgets:
```python
gui.windows # Returns a dictionary of all dock areas in the GUI
gui.new() # Adds a new BECDockArea to the GUI
dock_area = gui.windows['bec']
dock = dock_area.new('my_dock') # Adds a new dock named 'my_dock' to the dock area
plt = dock.new(gui.available_widgets.Waveform) # Adds a Waveform widget to the dock
# Alternative syntax:
# dock_area.my_dock.new(gui.available_widgets.Waveform)
dock.element_list # Returns a list of all widgets in the dock
dock.elements # Equivalent to dock.element_list
plt.curves # Returns a list of all curves in the plot
```
We note that commands can also be chained. For example, `gui.new().new().new(gui.available_widgets.Waveform)` will add a new dock_area to the gui and add a new dock with a `Waveform` widget to the dock.
## Composing a larger GUI
The example given above introduces BEC Widgets with its different components, and provides an overview of how to interact with the widgets. Nevertheless, another power aspect of BEC Widgets lies in the ability to compose a larger GUI with multiple docks and widgets. This section aims to provide a tutorial like guide on how to compose a more complex GUI that (A) live-plots a 1D waveform, (B) plots data from a camera, and (C) tracks the positions of two motors.
Let's assume BEC was just started and the `gui` object is available in the client. A single dock is already attached together with a BEC Figure. Let's add the 1D waveform to this dock, change the color of the line to white and add the title *1D Waveform* to the plot.
```python
dock_area = gui.new()
plt = dock_area.new().new(gui.available_widgets.Waveform)
plt.plot(device_x='samx', device_y='bpm4i')
plt.curves[0].set_color(color="white")
plt.title = '1D Waveform'
```
Next, we add 2 new docks to the gui, one to plot the data of a camera and one to track the positions of two motors.
```ipython
cam_widget= dock_area.new().new(gui.available_widgets.Image)
cam_widget.image("eiger")
motor_widget = dock_area.new().new(gui.available_widgets.MotorMap)
motor_widget.map("samx", "samy")
```
Note, we chain commands here which is possible since the `new()` and `new()` methods return the dock and the widget respectively. We can now further customize the widgets by changing the title, axis labels, etc.
```python
cam_widget.title = "Camera Image Eiger"
cam_widget.vrange = [0, 100]
```
As a final step, we can now add also a RingProgressBar to a new dock, and perform a grid_scan with the motors *samx* and *samy*.
As you see in the example below, all docks are arranged below each other. This is the default behavior of the `new()` method. However, the docks can be freely arranged by drag and drop as desired by the user. We invite you to explore this by yourself following the example in the video, and build your custom GUI with BEC Widgets.
```python
prog_bar = dock_area.new().new(gui.available_widgets.RingProgressBar)
prog_bar.set_line_widths(15)
scans.grid_scan(dev.samy, -2, 2, 10, dev.samx, -5, 5, 10, exp_time=0.1, relative=False)
```
![gui_complex_gui](./gui_complex_gui.gif)
@@ -1,17 +0,0 @@
(user.video_tutorials)=
# Video Tutorials
This section includes video tutorials that demonstrate various use cases of `bec-widgets`, including video tutorials,
presentations, and conference talks.
## BSEG Meeting 24th July 2024
This video is a presentation of the BEC Widgets project at the BSEG meeting on the 24th July 2024. The presentation
covers the basic interactions, including visualization of live data acquisition and how to steer experiments using
user-friendly tools. Learn how BEC Widgets can enhance your experimental control projects with its intuitive interface
and powerful features.
Used version of BEC Widgets: 0.91.0
<iframe width="560" height="315" src="https://www.youtube.com/embed/qZ8fWXRAdHE" frameborder="0" allowfullscreen></iframe>
-58
View File
@@ -1,58 +0,0 @@
(user.plugin_widgets)=
# Plugin repository widgets
## Adding widgets to the plugin repository
Widgets can be created by users and added to a beamline plugin repository, then they can be used in
all the same ways as built-in widgets. To make this work, the widget author should follow a few
simple guidelines.
Widgets should be added in `plugin_repo.bec_widgets.widgets`. They may be added in submodules. If
so, please make sure that these are properly defined python submodules with `__init__.py` files, so
that the widgets are discoverable.
### Preparing a widget to be a plugin
- make sure that the widget class inherits from both `BECWidget` as well as `QWidget` or a subclass
of it, such as `QComboBox` or `QLineEdit`.
- make sure it initialises each of these superclasses in its `__init__()` method, and passes the
`parent` keyword argument on to `QWidget.__init__()`.
- add `PLUGIN = True` as a class variable to the widget class
- add `USER_ACCESS = [...]`, including any methods and properties which should be accessible in the
client to the list, as strings.
(Search the `bec_widgets` code for one of the above names for examples of these magic variables)
### Example / template
```Python
class TestWidget(BECWidget, QWidget):
USER_ACCESS = ["set_text"]
PLUGIN = True
def __init__(self, parent=None, **kwargs):
super().__init__(**kwargs)
QWidget.__init__(self, parent=parent)
self.setLayout(QHBoxLayout())
self._text_widget = QLabel("Test widget text")
self.layout().addWidget(self._text_widget)
def set_text(self, value: str):
self._text_widget.setText(value)
```
### Generating the plugin files and RPC client template
To allow the BEC client to communicate with the GUI server and to know which widgets are available,
as well as to allow the BEC Designer to find the available widgets, a code generation tool should be
run to prepare a client file which lists all the available widget classes and functions. Make sure
you are in the BEC python environment where your plugin repository is also installed, and run:
```bash
$ bw-generate-cli --target plugin_repo
```
replacing `plugin_repo` with the name of your repository. This will overwrite the file for
`plugin_repo.bec_widgets.client`. This file should not be edited by hand, and should always be
regenerated when changes are made to widgets in the plugin repository. BEC will need to be restarted
for changes made here to take effect.
-80
View File
@@ -1,80 +0,0 @@
(user)=
# User
Welcome to the User section of the BEC Widgets documentation! BEC Widgets is a versatile GUI framework tailored for beamline scientists, enabling efficient and intuitive interaction with beamline experiments. This section is designed to guide both new and experienced users through the essential aspects of utilizing BEC Widgets.
```{toctree}
---
maxdepth: 2
hidden: false
---
customisation.md
plugin_widgets.md
```
```{toctree}
---
maxdepth: 2
hidden: true
---
getting_started/getting_started.md
applications/applications.md
widgets/widgets.md
api_reference/api_reference.md
```
***
````{grid} 2
:gutter: 5
```{grid-item-card}
:link: user.getting_started
:link-type: ref
:img-top: /assets/rocket_launch_48dp.svg
:text-align: center
:class-item: index-card
## Getting Started
Learn how to install BEC Widgets and get started with the framework.
```
```{grid-item-card}
:link: user.applications
:link-type: ref
:img-top: /assets/display_settings_48dp.svg
:text-align: center
:class-item: index-card
## Applications
Learn how to use BEC Widgets Applications, to modify and create new applications.
```
```{grid-item-card}
:link: user.widgets
:link-type: ref
:img-top: /assets/apps_48dp.svg
:text-align: center
:class-item: index-card
## Widgets
Learn about the building blocks of larger applications: widgets.
```
```{grid-item-card}
:link: user.api_reference
:link-type: ref
:img-top: /assets/index_api.svg
:text-align: center
:class-item: index-card
## API reference
Comprehensive reference of all user-facing classes, functions, and methods.
```
````
@@ -1,42 +0,0 @@
(user.widgets.bec_progressbar)=
# BEC Progressbar
```{tab} Overview
The {py:class}`~bec_widgets.cli.client.BECProgressBar` widget is a general purpose progress bar that follows the BEC theme and style. It can be embedded in any application to display the progress of a task or operation.
## Key Features:
- **Modern Design**: The BEC Progressbar widget is designed with a modern and sleek appearance, following the BEC theme.
- **Customizable**: Users can customize the appearance and behavior of the progress bar to suit their application.
- **Responsive**: The progress bar updates in real-time to reflect the progress of the task or operation.
## Screenshot
![BEC Progressbar](./bec_progressbar_running.png)
![BEC Progressbar](./bec_progressbar_completed.png)
```
````{tab} Examples
The `BECProgressBar` widget can be integrated within a [`BECDockArea`](user.widgets.bec_dock_area) or used as an individual component in your application through `BEC Designer`. Below are examples demonstrating how to create and use the `BECProgressBar` widget.
## Example 1 - Adding BEC Status Box to BECDockArea
In this example, we demonstrate how to add a `BECProgressBar` widget to a `BECDockArea`, allowing users to manually set and update the progress states.
```python
# Add a new dock with a BEC Progressbar widget
dock_area = gui.new()
pb = dock_area.new().new(gui.available_widgets.BECProgressBar)
pb.set_value(50)
```
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.BECProgressBar
:members:
:show-inheritance:
```
````
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

@@ -1,40 +0,0 @@
(user.widgets.bec_status_box)=
# BEC Status Box
````{tab} Overview
The {py:class}`~bec_widgets.cli.client.BECStatusBox` widget is designed to monitor the status and health of all running BEC processes. This widget provides a real-time overview of the BEC core services, including DeviceServer, ScanServer, SciHub, ScanBundler, and FileWriter. The top-level display indicates the overall state of the BEC services, while the collapsed view allows users to delve into the status of each individual process. By double-clicking on a specific process, users can access a detailed popup window with live updates of the metrics for that process.
## Key Features:
- **Comprehensive Service Monitoring**: Track the state of individual BEC services, including real-time updates on their health and status.
- **Automatic Service Tracking**: Automatically detects and monitors additional clients connecting to the BEC services.
- **Detailed Metrics**: Provides live updates of the metrics for each process, accessible through an interactive popup window.
![BECStatus](./bec_status_box.gif)
````
````{tab} Examples
The `BECStatusBox` widget can be integrated within a [`BECDockArea`](user.widgets.bec_dock_area) or used as an individual component in your application through `BEC Designer`. Below are examples demonstrating how to create and use the `BECStatusBox` widget.
## Example 1 - Adding BEC Status Box to BECDockArea
In this example, we demonstrate how to add a `BECStatusBox` widget to a `BECDockArea`, allowing users to monitor the status of BEC processes directly from the GUI.
```python
# Add a new dock with a BECStatusBox widget
sb = gui.bec.new().new(widget=gui.available_widgets.BECStatusBox)
```
```{hint}
Once the `BECStatusBox` is added, users can interact with it to view the status of individual processes. By expanding the view, you can see the status of each BEC service in detail.
```
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.BECStatusBox
:members:
:show-inheritance:
```
````
@@ -1,159 +0,0 @@
(user.widgets.buttons_appearance)=
# Appearance Buttons
`````{tab} Overview
This section consolidates various buttons designed to manage the appearance of the BEC GUI, allowing users to easily switch themes, select colors, and choose colormaps.
## Dark Mode Button
The `Dark Mode Button` is a toggle control that allows users to switch between light and dark themes in the BEC GUI. It provides a convenient way to adjust the interface's appearance based on user preferences or environmental conditions.
````{grid} 2
:gutter: 2
```{grid-item-card} Dark Mode
:img-top: ./dark_mode_enabled.png
```
```{grid-item-card} Light Mode
:img-top: ./dark_mode_disabled.png
```
````
**Key Features:**
- **Theme Switching**: Enables users to switch between light and dark themes with a single click.
- **Configurable from BEC Designer**: The defaults for the dark mode can be set in the BEC Designer, allowing users to customize the startup appearance of the GUI.
## Color Button
The `Color Button` is a user interface element that provides a dialog to select colors. This button, adapted from `pyqtgraph`, is a simple yet powerful tool to integrate color selection functionality into the BEC GUIs.
**Key Features:**
- **Color Selection**: Opens a dialog for selecting colors, returning the selected color in both RGBA and HEX formats.
## Colormap Selector
The `Colormap Selector` is a specialized combobox that allows users to select a colormap. It includes a preview of the colormap, making it easier for users to choose the appropriate one for their needs.
**Key Features:**
- **Colormap Selection**: Provides a dropdown to select from all available colormaps in `pyqtgraph`.
- **Visual Preview**: Displays a small preview of the colormap next to its name, enhancing usability.
## Colormap Button
The `Colormap Button` is a custom widget that displays the current colormap and, upon clicking, shows a nested menu for selecting a different colormap. It integrates the `ColorMapMenu` from `pyqtgraph`, providing an intuitive and interactive way for users to choose colormaps within the GUI.
**Key Features:**
- **Current Colormap Display**: Shows the name and a gradient icon of the current colormap directly on the button.
- **Nested Menu Selection**: Offers a nested menu with categorized colormaps, making it easy to find and select the desired colormap.
- **Signal Emission**: Emits a signal when the colormap changes, providing the new colormap name as a string.
- **BEC Designer Integration**: Exposes properties and signals to be used within BEC Designer, allowing for customization within the designer interface.
- **Resizable and Styled**: Features adjustable size policies and styles to match the look and feel of standard `QPushButton` widgets, including rounded edges.
`````
````{tab} Examples
Integrating these buttons into a BEC GUI layout is straightforward. The following examples demonstrate how to embed these buttons within a custom GUI layout using `QtWidgets`.
## Example 1 - Adding a Dark Mode Button
```python
from qtpy.QtWidgets import QWidget, QVBoxLayout
from bec_widgets.widgets.buttons import DarkModeButton
class MyGui(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setLayout(QVBoxLayout(self))
# Create and add the DarkModeButton to the layout
self.dark_mode_button = DarkModeButton(parent=self)
self.layout().addWidget(self.dark_mode_button)
# Example of how this custom GUI might be used:
my_gui = MyGui()
my_gui.show()
```
## Example 2 - Adding a Color Button
```python
from qtpy.QtWidgets import QWidget, QVBoxLayout
from bec_widgets.widgets.buttons import ColorButton
class MyGui(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setLayout(QVBoxLayout(self))
# Create and add the ColorButton to the layout
self.color_button = ColorButton(self)
self.layout().addWidget(self.color_button)
# Example of how this custom GUI might be used:
my_gui = MyGui()
my_gui.show()
```
## Example 3 - Adding a Colormap Selector
```python
from qtpy.QtWidgets import QWidget, QVBoxLayout
from bec_widgets.widgets.buttons import ColormapSelector
class MyGui(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setLayout(QVBoxLayout(self))
# Create and add the ColormapSelector to the layout
self.colormap_selector = ColormapSelector(self)
self.layout().addWidget(self.colormap_selector)
# Example of how this custom GUI might be used:
my_gui = MyGui()
my_gui.show()
```
## Example 4 - Adding a Colormap Button
```python
from qtpy.QtWidgets import QWidget, QVBoxLayout
from bec_widgets.widgets.buttons import ColormapButton
class MyGui(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setLayout(QVBoxLayout(self))
# Create and add the ColormapButton to the layout
self.colormap_button = ColormapButton(self)
self.layout().addWidget(self.colormap_button)
# Connect the signal to handle colormap changes
self.colormap_button.colormap_changed_signal.connect(self.on_colormap_changed)
def on_colormap_changed(self, colormap_name):
print(f"Selected colormap: {colormap_name}")
# Example of how this custom GUI might be used:
my_gui = MyGui()
my_gui.show()
```
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.DarkModeButton
:members:
:show-inheritance:
.. autoclass:: bec_widgets.cli.client.ColorButton
:members:
:show-inheritance:
.. autoclass:: bec_widgets.cli.client.ColormapSelector
:members:
:show-inheritance:
```
````
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

@@ -1,86 +0,0 @@
(user.widgets.buttons_queue)=
# Queue Control Buttons
```{tab} Overview
This section consolidates various buttons designed to manage the BEC scan queue, providing essential controls for operations like stopping, resuming, aborting, and resetting the scan queue.
## Stop Button
The `Stop Button` is a specialized control that provides an immediate interface to halt ongoing operations in the BEC Client. It is essential for scenarios where operations need to be terminated quickly, such as in the case of an error or when an operation needs to be interrupted by the user.
**Key Features:**
- **Immediate Termination**: Instantly halts the execution of the current script or process.
- **Queue Management**: Stops the current scan or the entire scan queue.
## Resume Button
The `Resume Button` allows users to continue the paused scan queue. Its useful in scenarios where the scan queue has been halted and needs to be resumed.
**Key Features:**
- **Queue Continuation**: Resumes the scan queue after a pause.
- **Toolbar and Button Options**: Can be configured as a toolbar button or a standard push button.
## Abort Button
The `Abort Button` provides an interface to abort a specific scan or the entire queue. This is useful for scenarios where an operation needs to be terminated but in a controlled manner.
**Key Features:**
- **Scan Abortion**: Aborts the current scan or a specific scan in the queue.
- **Toolbar and Button Options**: Can be configured as a toolbar button or a standard push button.
## Reset Queue Button
The `Reset Button` is used to reset the scan queue. It prompts the user for confirmation before resetting, ensuring that the action is intentional.
**Key Features:**
- **Queue Reset**: Resets the entire scan queue.
- **Confirmation Dialog**: Prompts the user to confirm the reset action to prevent accidental resets.
- **Toolbar and Button Options**: Can be configured as a toolbar button or a standard push button.
```
````{tab} Examples
Integrating these buttons into a BEC GUI layout is straightforward. The following examples demonstrate how to embed these buttons within a custom GUI layout using `QtWidgets`.
### Example 1 - Embedding a Stop Button in a Custom GUI Layout
```python
import sys
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
from bec_widgets.widgets.control.buttons.stop_button.stop_button import StopButton
class MyGui(QWidget):
def __init__(self):
super().__init__()
self.setLayout(QVBoxLayout())
# Create and add the StopButton to the layout
self.stop_button = StopButton()
self.layout().addWidget(self.stop_button)
# Example of how this custom GUI might be used:
app = QApplication([])
my_gui = MyGui()
my_gui.show()
app.exec_()
```
`ResumeButton`, `ResetButton`, and `AbortButton` may be used in an exactly analogous way.
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.StopButton
:members:
:show-inheritance:
.. autoclass:: bec_widgets.cli.client.ResumeButton
:members:
:show-inheritance:
.. autoclass:: bec_widgets.cli.client.AbortButton
:members:
:show-inheritance:
.. autoclass:: bec_widgets.cli.client.ResetButton
:members:
:show-inheritance:
```
````
@@ -1,41 +0,0 @@
(user.widgets.dap_combo_box)=
# DAP Combobox
````{tab} Overview
The {py:class}`~bec_widgets.widgets.dap_combo_box.dap_combo_box.DAPComboBox` is a widget that extends the functionality of a standard `QComboBox` to allow the user to select a DAP process from all available DAP models.
One of its signals `new_dap_config` is designed to be connected to the {py:class}`~bec_widgets.widgets.plots.waveform.waveform.Waveform.add_dap_curve` slot from the Waveform widget to add a DAP process.
## Key Features:
- **Select DAP model**: Select one of the available DAP models.
- **Signal/Slot Interaction**: Signal and slots to configure the fit_model, x_axis, and y_axis, and to add a DAP model to the BECWaveformWidget.
```{figure} /assets/widget_screenshots/dap_combo_box.png
---
name: lmfit_dialog
---
LMFit Dialog
```
````
````{tab} Summary of Signals
The following signals are emitted by the `DAP ComboBox` widget:
- `new_dap_config(str, str, str)` : Signal to add a DAP model to the BECWaveformWidget
- `x_axis_updated(str)` : Signal to emit the current x axis
- `y_axis_updated(str)` : Signal to emit the current y axis
- `fit_model_updated(str)` : Signal to emit the current fit model
````
````{tab} Summary of Slots
The following slots are available for the `DAP ComboBox` widget:
- `select_x_axis(str)` : Slot to select the current x axis, emits the `x_axis_updated` signal
- `select_y_axis(str)` : Slot to select the current y axis, emits the `x_axis_updated` signal
- `select_fit_model(str)` : Slot to select the current fit model, emits the `fit_model_updated` signal. If x and y axis are set, it will also emit the `new_dap_config` signal.
````
@@ -1,41 +0,0 @@
(user.widgets.device_browser)=
# Device Browser
````{tab} Overview
The {py:class}`~bec_widgets.cli.client.DeviceBrowser` widget provides a user-friendly interface for browsing through all available devices in the current BEC session. As it supports drag functionality, users can easily drag and drop device into other widgets or applications.
```{note}
The `Device Browser` widget is currently under development. Other widgets may not support drag and drop functionality yet.
```
## Key Features:
- **Device Search**: Allows users to search for devices using regular expressions.
- **Drag and Drop**: Supports drag and drop functionality for easy transfer of devices to other widgets or applications.
```{figure} ./device_browser.png
```
````
````{tab} Examples
In this example, we demonstrate how to add a `DeviceBrowser` widget to a `BECDockArea` to visualize the progress of a task.
```python
# Add a new dock with a DeviceBrowser widget
dock_area = gui.new()
browser = dock_area.new("device_browser").new(gui.available_widgets.DeviceBrowser)
# You can also access the DeviceBrowser widget directly from the dock_area
dock_area.device_browser.DeviceBrowser
```
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.DeviceBrowser
:members:
:show-inheritance:
```
````
Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

@@ -1,129 +0,0 @@
(user.widgets.device_input)=
# Device Input Widgets
````{tab} Overview
The `Device Input Widgets` consist of two primary widgets: `DeviceLineEdit` and `DeviceComboBox`. Both widgets are designed to facilitate the selection of devices within the BEC environment, allowing users to filter, search, and select devices dynamically. These widgets are highly customizable and can be integrated into a GUI either through direct code instantiation or by using `BEC Designer`.
## DeviceLineEdit
The `DeviceLineEdit` widget provides a line edit interface with autocomplete functionality for device names, making it easier for users to quickly search and select devices.
## DeviceComboBox
The `DeviceComboBox` widget offers a dropdown interface for device selection, providing a more visual way to browse through available devices.
## Key Features:
- **Device Filtering**: Both widgets allow users to filter devices by device type and readout priority, ensuring that only relevant devices are shown.
- **Default Device Setting**: Users can set a default device to be pre-selected when the widget is initialized.
- **Set Device Selection**: Both widgets allow users to set the available devices to be displayed independent of the applied filters.
- **Real-Time Autocomplete (LineEdit)**: The `DeviceLineEdit` widget supports real-time autocomplete, helping users find devices faster.
- **Real-Time Input Validation (LineEdit)**: User input is validated in real-time with a red border around the `DeviceLineEdit` indicating an invalid input.
- **Dropdown Selection (ComboBox)**: The `DeviceComboBox` widget displays devices in a dropdown list, making selection straightforward.
- **BEC Designer Integration**: Both widgets can be added as custom widgets in `BEC Designer` or instantiated directly in code.
## Screenshot
```{figure} /assets/widget_screenshots/device_inputs.png
```
````
````{tab} Examples
Both `DeviceLineEdit` and `DeviceComboBox` can be integrated within a GUI application through direct code instantiation or by using `BEC Designer`. Below are examples demonstrating how to create and use these widgets.
## Example 1 - Creating a DeviceLineEdit in Code
In this example, we demonstrate how to create a `DeviceLineEdit` widget in code and customize its behavior.
We filter down to Positioners with readout_priority Baseline.
Note, if we do not specify a device_filter or readout_filter, all enabled devices will be included.
```python
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
from bec_lib.device import ReadoutPriority
from bec_widgets.widgets.base_classes.device_input_base import BECDeviceFilter
class MyGui(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setLayout(QVBoxLayout(self)) # Initialize the layout for the widget
# Create and add the DeviceLineEdit to the layout
self.device_line_edit = DeviceLineEdit(parent=self, device_filter=BECDeviceFilter.POSITIONER, readout_priority_filter=ReadoutPriority.BASELINE)
self.layout().addWidget(self.device_line_edit)
# Example of how this custom GUI might be used:
app = QApplication([])
my_gui = MyGui()
my_gui.show()
app.exec_()
```
## Example 2 - Creating a DeviceComboBox in Code
Similarly, here is an example of creating a `DeviceComboBox` widget in code and customizing its behavior.
```python
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
from bec_lib.device import ReadoutPriority
from bec_widgets.widgets.base_classes.device_input_base import BECDeviceFilter
class MyGui(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setLayout(QVBoxLayout(self)) # Initialize the layout for the widget
# Create and add the DeviceComboBox to the layout
self.device_combobox = DeviceComboBox(parent=self, device_filter=BECDeviceFilter.POSITIONER, readout_priority_filter=ReadoutPriority.BASELINE)
self.layout().addWidget(self.device_combobox)
# Example of how this custom GUI might be used:
app = QApplication([])
my_gui = MyGui()
my_gui.show()
app.exec_()
```
## Example 3 - Setting Default Device
Both `DeviceLineEdit` and `DeviceComboBox` allow you to set a default device that will be selected when the widget is initialized.
```python
# Set default device for DeviceLineEdit
self.device_line_edit.set_device("motor1")
# Set default device for DeviceComboBox
self.device_combo_box.set_device("motor2")
# Set the available devices to be displayed independent of the applied filters
self.device_combo_box.set_available_devices(["motor1", "motor2", "motor3"])
```
````
````{tab} BEC Designer
Both widgets are also available as plugins for the BEC Designer. We have included Qt properties for both widgets, allowing customization of filtering and default device settings directly from the designer. In addition to the common signals and slots for `DeviceLineEdit` and `DeviceComboBox`, the following slots are available:
- `set_device(str)` to set the default device
- `update_devices()` to refresh the devices list
The following Qt properties are also included:
```{figure} ./QProperties_DeviceInput.png
```
````
````{tab} API - ComboBox
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.DeviceComboBox
:members:
:show-inheritance:
```
````
````{tab} API - LineEdit
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.DeviceLineEdit
:members:
:show-inheritance:
```
````
Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

@@ -1,122 +0,0 @@
(user.widgets.bec_dock_area)=
# BECDockArea
````{tab} Overview
`BECDockArea` is a powerful and flexible container designed to host various widgets and docks within a grid layout. It provides an environment for organizing and managing complex user interfaces, making it ideal for applications that require multiple tools and data visualizations to be displayed simultaneously. BECDockArea is particularly useful for embedding not only visualization tools but also other interactive components, allowing users to tailor their workspace to their specific needs.
- **Flexible Dock Management**: Easily add, remove, and rearrange docks within `BECDockArea`, providing a customized layout for different tasks.
- **State Persistence**: Save and restore the state of the dock area, enabling consistent user experiences across sessions.
- **Dock Customization**: Add docks with customizable positions, names, and behaviors, such as floating or closable docks.
- **Integration with Widgets**: Integrate various widgets like [`WaveformWidget`](user.widgets.waveform_widget), [`ImageWidget`](user.widgets.image_widget), and [`MotorMapWidget`](user.widgets.motor_map) into `BECDockArea`, either as standalone tools or as part of a more complex interface.
**BEC Dock Area Components Schema**
![BECDockArea.png](BECDockArea.png)
````
````{tab} Examples - CLI
In the following examples, we will use `BECIPythonClient` as the main object to interact with the `BECDockArea`. These tutorials focus on how to work with the `BECDockArea` framework, such as adding and removing docks, saving and restoring layouts, and managing the docked widgets. By default the `BECDockArea` is referred to as `gui` in `BECIPythonClient`. For more detailed examples of each individual component, please refer to the example sections of each individual [`widget`](user.widgets).
## Example 1 - Adding Docks to BECDockArea
In this example, we will demonstrate how to add different docks to a single `BECDockArea` widget. New docks are always added to the bottom of the dock area by default; however, you can specify the position of the dock by using the `position` and `relative_to` arguments.
```python
# Create a new dock_area from GUI object
dock_area = gui.new()
# Add a new dock with a Waveform to the BECDockArea
dock_area.new(name="waveform_dock", widget="Waveform")
dock1 = dock_area.waveform_dock # dynamic namespace was created
# Add a second dock with a MotorMapWidget to the BECDockArea to the right of the first dock
dock2 = dock_area.new(name="motor_dock", widget="MotorMap",relative_to="Waveform Dock", position="right")
# Add a third dock with an ImageWidget to the BECDockArea, placing it on bottom of the dock area
dock3 = dock_area.new(name="image_dock", widget="Image")
```
```{hint}
You can move docks around by dragging them with the mouse using the dock's title bar. The dock will snap to the grid layout of the dock area.
```
## Example 2 - Access of Docks in BECDockArea
Docks can be accessed by their name or by the dock object. The dock object can be used to modify the dock properties or to add widgets to the dock.
```python
# All docks can be accessed by their name from the panels dictionary
dock_area.panels
# Output
{'waveform_dock': <BECDock with name: waveform_dock>,
'motor_dock': <BECDock with name: motor_dock>,
'image_dock': <BECDock with name: image_dock>}
# Access all docks from the dock area via list
dock_area.panel_list
# Access through dynamic namespace mapping
dock_area.waveform_dock
dock_area.motor_dock
dock_area.image_dock
# If objects were closed, we will keep a reference that will indicate that the dock was deleted
# Try closing the window with the dock_area via mouse click on x
dock_area
# Output
<Deleted widget with gui_id BECDockArea_2025_04_24_14_28_11_742887>
```
## Example 3 - Detaching and Attaching Docks in BECDockArea
Docks in `BECDockArea` can be detached (floated) or reattached to the main dock area. This is useful when you want to temporarily undock a widget for better visibility or organization.
```python
# Detach the dock named "Waveform Dock"
dock_area.detach_dock("waveform_dock")
# Alternatively, you can use the dock object to detach the dock
dock1 = dock_area.waveform_dock
dock1.detach()
# Docks can be individually reattached to the main dock area
dock2.attach()
# Reattach all floating docks to the main dock area
gui.attach_all()
```
```{note}
Floating docks are always returned to the original dock area if they are closed manually. Docks can also be detached by double-clicking on the dock title.
```
## Example 4 - Removing Docks from BECDockArea
Docks can be removed from the dock area by their name or by the dock object. The dock object can be used to remove the dock from the dock area.
```python
# Removing docks by their name
dock_area.delete("waveform_dock")
# Alternatively, you can use the dock object to remove the dock
dock1 = dock_area.motor_dock
dock1.remove()
# Removing all docks from the dock area
gui.delete_all()
```
```{warning}
When removing a dock, all widgets within the dock will be removed as well. This action cannot be undone, and all references to the dock and its widgets will be lost.
```
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.BECDockArea
:members:
:show-inheritance:
```
````
-11
View File
@@ -1,11 +0,0 @@
(user.widgets.games)=
# Game widgets
To provide some entertainment during long nights at the beamline, there are game widgets available. Well, only one, so far.
## Minesweeper
![Minesweeper](./minesweeper.png)
The classic game Minesweeper. You may select from three different levels. The game can be ended or reset by clicking on the icon in the top-centre (the robot in the screenshot).
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 KiB

-108
View File
@@ -1,108 +0,0 @@
(user.widgets.heatmap_widget)=
# Heatmap widget
````{tab} Overview
The Heatmap widget is a specialized plotting tool designed for visualizing 2D grid data with color mapping for the z-axis. It excels at displaying data from grid scans or arbitrary step scans, automatically interpolating scattered data points into a coherent 2D image. Directly integrated with the `BEC` framework, it can display live data streams from scanning experiments within the current `BEC` session.
## Key Features:
- **Flexible Integration**: The widget can be integrated into [`BECDockArea`](user.widgets.bec_dock_area), or used as an individual component in your application through `BEC Designer`.
- **Live Grid Scan Visualization**: Real-time plotting of grid scan data with automatic positioning and color mapping based on scan parameters.
- **Dual Scan Support**: Handles both structured grid scans (with pre-allocated grids) and unstructured step scans (with interpolation).
- **Intelligent Data Interpolation**: For arbitrary step scans, the widget automatically interpolates scattered (x, y, z) data points into a smooth 2D heatmap using various interpolation methods.
- **Oversampling**: Supports oversampling to enhance the appearance of the heatmap, allowing for smoother transitions and better visual representation of data. Especially useful the for nearest-neighbor interpolation.
- **Customizable Color Maps**: Wide variety of color maps available for data visualization, with support for both simple and full color bars.
- **Real-time Image Processing**: Apply real-time processing techniques such as FFT and logarithmic scaling to enhance data visualization.
- **Interactive Controls**: Comprehensive toolbar with settings for heatmap configuration, crosshair tools, mouse interaction, and data export capabilities.
```{figure} ./heatmap_grid_scan.gif
:width: 60%
Real-time heatmap visualization of a 2D grid scan showing motor positions and detector intensity
```
```{figure} ./heatmap_fermat_scan.gif
:width: 80%
Real-time heatmap visualization of an (not path-optimized) scan following Fermat's spiral pattern. On the left, the heatmap widget is shown with the oversampling option set to 10 and the interpolation method set to nearest neighbor. On the right, the scatter waveform widget is shown with the same data.
```
````
````{tab} Examples - CLI
`HeatmapWidget` can be embedded in [`BECDockArea`](user.widgets.bec_dock_area), or used as an individual component in your application through `BEC Designer`. The command-line API is the same for all cases.
## Example 1 - Visualizing Grid Scan Data
In this example, we demonstrate how to add a `HeatmapWidget` to visualize live data from a 2D grid scan with motor positions and detector readout.
```python
# Add a new dock with HeatmapWidget
dock_area = gui.new()
heatmap_widget = dock_area.new().new(gui.available_widgets.Heatmap)
# Plot a heatmap with x and y motor positions and z detector signal
heatmap_widget.plot(
device_x='samx', # X-axis motor
device_y='samy', # Y-axis motor
device_z='bpm4i', # Z-axis detector signal
color_map='plasma'
)
heatmap_widget.title = "Grid Scan - Sample Position vs BPM Intensity"
```
## Example 2 - Step Scan with Custom Entries
This example shows how to visualize data from an arbitrary step scan by specifying custom data entries for each axis.
```python
# Add a new dock with HeatmapWidget
dock_area = gui.new()
heatmap_widget = dock_area.new().new(gui.available_widgets.Heatmap)
# Plot heatmap with specific data entries
heatmap_widget.plot(
device_x='motor1',
device_y='motor2',
device_z='detector1',
signal_x='RBV', # Use readback value for x
signal_y='RBV', # Use readback value for y
signal_z='value', # Use main value for z
color_map='viridis',
reload=True # Force reload of data
)
```
## Example 3 - Real-time Processing and Customization
The `Heatmap` widget provides real-time processing capabilities and extensive customization options for enhanced data visualization.
```python
# Configure heatmap appearance and processing
heatmap_widget.color_map = 'plasma'
heatmap_widget.lock_aspect_ratio = True
# Apply real-time processing
heatmap_widget.fft = True # Apply FFT to the data
heatmap_widget.log = True # Use logarithmic scaling
# Configure color bar and range
heatmap_widget.enable_full_colorbar = True
heatmap_widget.v_min = 0
heatmap_widget.v_max = 1000
```
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.widgets.plots.heatmap.heatmap.Heatmap
:members:
:show-inheritance:
```
````
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 MiB

-112
View File
@@ -1,112 +0,0 @@
(user.widgets.image_widget)=
# Image widget
````{tab} Overview
The Image widget is a versatile tool designed for visualizing both 1D and 2D data, such as camera images or waveform data, in real-time. Directly integrated with the `BEC` framework, it can display live data streams from connected detectors or other data sources within the current `BEC` session. The widget provides advanced customization options for color maps and scale bars, allowing users to tailor the visualization to their specific needs.
## Key Features:
- **Flexible Integration**: The widget can be integrated into [`BECDockArea`](user.widgets.bec_dock_area), or used as an individual component in your application through `BEC Designer`.
- **Live Data Visualization**: Real-time plotting of both 1D and 2D data from detectors or other data sources, provided that a data stream is available in the BEC session.
- **Support for Multiple Monitor Types**: The Image widget supports different monitor types (`'1d'` and `'2d'`), allowing visualization of various data dimensions. It can automatically determine the best way to visualise the data based on the shape of the data source.
- **Customizable Color Maps and Scale Bars**: Users can customize the appearance of images with various color maps and adjust scale bars to better interpret the visualized data.
- **Real-time Image Processing**: Apply real-time image processing techniques directly within the widget to enhance the quality or analyze specific aspects of the data, such as rotation, logarithmic scaling, and Fast Fourier Transform (FFT).
- **Data Export**: Export visualized data to various formats such as PNG, TIFF, or H5 for further analysis or reporting.
- **Interactive Controls**: Offers interactive controls for zooming, panning, and adjusting the visual properties of the images on the fly.
![Image 2D](./image.gif)
````
````{tab} Examples - CLI
`ImageWidget` can be embedded in [`BECDockArea`](user.widgets.bec_dock_area), or used as an individual component in your application through `BEC Designer`. The command-line API is the same for all cases.
## Example 1 - Visualizing 2D Image Data from a Detector
In this example, we demonstrate how to add an `ImageWidget` to a [`BECDockArea`](user.widgets.bec_dock_area) to visualize live 2D image data from a connected camera detector.
```python
# Add a new dock with BECFigure widget
dock_area = gui.new()
img_widget = dock_area.new().new(gui.available_widgets.Image)
# Add an ImageWidget to the BECFigure for a 2D detector
img_widget.image(device='eiger', signal='preview')
img_widget.title = "Camera Image - Eiger Detector"
```
## Example 2 - Visualizing 1D Waveform Data from a Detector
This example demonstrates how to set up the Image widget to visualize 1D waveform data from a detector, such as a line detector or a spectrometer. The widget will stack incoming 1D data arrays to construct a 2D image.
```python
# Add a new dock with BECFigure widget
dock_area = gui.new()
img_widget = dock_area.new().new(gui.available_widgets.Image)
# Add an ImageWidget to the BECFigure for a 2D detector
img_widget.image(device='waveform', signal='data')
img_widget.title = "Line Detector Data"
# Optional: Set the color map and value range
img_widget.colormap = "plasma"
img_widget.vrange= [0, 100]
```
## Example 3 - Real-time Image Processing
The `Image` provides real-time image processing capabilities, such as rotating, scaling, applying logarithmic scaling, and performing FFT on the displayed images. The following example demonstrates how to apply these transformations to an image.
```python
# Rotate the image by 90 degrees (1,2,3,4 are multiplied by 90 degrees)
img_widget.num_rotation_90 = 1
# Transpose the image
img_widget.transpose = True
# Apply FFT to the image
img_widget.fft = True
# Set logarithmic scaling for the image display
img_widget.log = True
# Set autorange for the image color map
img_widget.autorange = True
img_widget.autorange_mode = 'mean'# or 'max'
```
<!--
## Example 6 - Setting Up for Different Detectors
The Image Widget can be configured for different detectors by specifying the correct monitor name and monitor type. Here's how to set it up for various detectors:
### For a 2D Camera Detector (e.g., 'eiger')
```python
# For a 2D camera detector
img_widget = fig.image(device='eiger', signal='preview')
img_widget.set_title("Eiger Camera Image")
```
### For a 1D Line Detector (e.g., 'waveform')
```python
# For a 1D line detector
img_widget = fig.image(device='waveform', signal='data')
img_widget.set_title("Line Detector Data")
```
```{note}
Since the Image Widget does not have prior information about the shape of incoming data, it is essential to specify the correct `monitor_type` when setting up the widget. This ensures that the data is processed and displayed correctly.
``` -->
````
````{tab} API
```{eval-rst}
.. autoclass:: bec_widgets.cli.client.Image
:members:
:show-inheritance:
```
````
@@ -1,46 +0,0 @@
(user.widgets.lmfit_dialog)=
# LMFit Dialog
````{tab} Overview
The `LMFitDialog` is a widget that is developed to be used together with the `Waveform` widget. The `Waveform` widget allows user to submit a fit request to BEC's [DAP server](https://bec.readthedocs.io/en/latest/developer/getting_started/architecture.html) choosing from a selection of [LMFit models](https://lmfit.github.io/lmfit-py/builtin_models.html#) to fit monitored data sources. The `LMFit Dialog` provides an interface to monitor these fits, including statistics and fit parameters in real time.
Within the `Waveform` widget, the dialog is accessible via the toolbar and will be automatically linked to the current waveform widget. For a more customised use, we can embed the `LMFit Dialog` in a larger GUI using the *BEC Designer*. In this case, one has to connect the `update_summary_tree` slot of the LMFit Dialog to the `dap_summary_update` signal of the Waveform widget to ensure its functionality.
## Key Features:
- **Fit Summary**: Display updates on LMFit DAP processes and fit statistics.
- **Fit Parameter**: Display current fit parameter.
- **`Waveform` Widget Integration**: Directly connect to `Waveform` widget to display fit statistics and parameters.
```{figure} /assets/widget_screenshots/lmfit_dialog.png
---
name: lmfit_dialog
---
LMFit Dialog
```
````
````{tab} Connect in BEC Designer
The `LMFit Dialog` widget can be connected to a `Waveform` widget to display fit statistics and parameters from the LMFit DAP process hooked up to the waveform widget. You can use the signal/slot editor from the BEC Designer to connect the `dap_summary_update` signal of the `Waveform` widget to the `update_summary_tree` slot of the LMFit Dialog.
```{figure} /assets/widget_screenshots/lmfit_dialog_connect.png
````
````{tab} Connect in Python
It is also possible to directly connect the `dap_summary_update` signal of the `Waveform` widget to the `update_summary_tree` slot of the LMFit Dialog in Python.
```python
waveform = Waveform(...)
lmfit_dialog = LMFitDialog(...)
waveform.dap_summary_update.connect(lmfit_dialog.update_summary_tree)
```
````
-39
View File
@@ -1,39 +0,0 @@
(user.widgets.log_panel)=
# LogPanel widget
The LogPanel widget can be used to view logs:
![LogPanel](./logpanel.png)
It automatically subscribes to log updates. You can fetch the log history with the "Fetch history" button.
## Filtering based on log level
If you select a dropdown box, only logs of that priority level or higher will be displayed:
![LogPanel](./logpanel_level.png)
## Filtering based on a search string
If you type in a search string into the box in the toolbar, and hit enter or press the update button, that filter will be applied:
![LogPanel](./logpanel_text.png)
This search uses the [Python regular expression syntax](https://docs.python.org/3/library/re.html) if the checkbox for this option is selected:
![LogPanel](./logpanel_regex.png)
## Filtering based on time range
You may filter the logs to those occurring within a given time range.
![LogPanel](./logpanel_timerange.png)
## Filtering based on service
You can select which services to show logs from.
![LogPanel](./logpanel_services.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

Some files were not shown because too many files have changed in this diff Show More