Compare commits
421 Commits
feat/plugi
...
v0.94.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5733fea98c | ||
| 98b79aac7b | |||
|
|
4212fe0e32 | ||
| 93d397759c | |||
|
|
8c5b901a37 | ||
| 0273bf4856 | |||
| c80a7cd108 | |||
|
|
a50d9c7b3f | ||
| 281633deff | |||
| 0d190c5c59 | |||
| 6269009e54 | |||
| 6d2442d23c | |||
|
|
110b27351b | ||
| 37aa371e7c | |||
| eb54e9f788 | |||
|
|
482efeb340 | ||
| 99ee545e41 | |||
| cf94599c25 | |||
| b50b3a27e6 | |||
| bf6294ecbf | |||
| a3d4f5ac4b | |||
| bc264975b1 | |||
| ad07bbf85e | |||
| 9856857f4c | |||
| f9e5897900 | |||
|
|
39fb22b716 | ||
| a372925fff | |||
|
|
ec54440569 | ||
| af86860bf3 | |||
| 302ae90139 | |||
|
|
1405068925 | ||
| 5aad401ef8 | |||
|
|
885dcfda89 | ||
| 30fef929cf | |||
| 1f30dd73a9 | |||
| 73cd11e472 | |||
| 7616ca0e14 | |||
|
|
ca29a69779 | ||
| dcc5fd71ee | |||
|
|
fee4901657 | ||
| 71873ddf35 | |||
|
|
f8552ca551 | ||
| 995a795060 | |||
|
|
7ab81c5797 | ||
| bc1e23944c | |||
| a3fe20500a | |||
| 61a4e32deb | |||
| 3d681f77e1 | |||
| 5a9ccfd1f6 | |||
| fc57b7a126 | |||
| 06205e0790 | |||
| 4be6fd6b83 | |||
| 714e1e139e | |||
|
|
01c0e0b1df | ||
| 4457ef2147 | |||
| 8ca60d54b3 | |||
| 5696c993dc | |||
| 1206e15309 | |||
|
|
4f2b51b211 | ||
| 1b9c55a46a | |||
| f4844d2e06 | |||
| 06fab0eab9 | |||
| a16b87ac28 | |||
| cce1367a72 | |||
| 28f26e92a4 | |||
|
|
2f5cc3030d | ||
| 1cf6e32303 | |||
| 7f49893d2c | |||
| ba0d1ea903 | |||
| 70fb276fdf | |||
| 43711680ba | |||
| 3d2ca4855c | |||
| fe7e542b19 | |||
| 501eb923f1 | |||
| c15035b6b7 | |||
| 6a9317facd | |||
|
|
95e515114a | ||
| fd6ae91993 | |||
| 3798714369 | |||
|
|
067496b18c | ||
| ad112d1f08 | |||
| a3dff7decc | |||
| 2bcaa4256d | |||
|
|
006f7c01fd | ||
| 2c8764a27d | |||
| 50135b5fe9 | |||
| 8d764e2d46 | |||
| 6eb313fa76 | |||
| 1f8ef52b60 | |||
| 2be009c647 | |||
| 8df6b003e5 | |||
| 7089cf356a | |||
| 1e551d6e96 | |||
| 8e588d79c8 | |||
| 8d93405399 | |||
| 6ff6111091 | |||
| a8b6ef20cc | |||
| a8ff1d4cd0 | |||
| 47fcb9ebfe | |||
| e8305652fd | |||
| 33495cfe03 | |||
| 8ac35d7280 | |||
| c926a75a79 | |||
| fa9b17191d | |||
| 755b394c1c | |||
|
|
717df63d62 | ||
| d75c55b2b1 | |||
| e52ee2604c | |||
| c7feb6952d | |||
| d64758f268 | |||
| 6202d224fe | |||
|
|
4ac90e1e56 | ||
| 8f104cf402 | |||
| 787f74949b | |||
| 196ef7afe1 | |||
|
|
18ac3ffac0 | ||
| ba69e7957c | |||
|
|
5acb47532c | ||
| b5b0aa4f82 | |||
|
|
9a91583ed0 | ||
| b98fd00ade | |||
|
|
d5c5e12589 | ||
| e495fd30c4 | |||
| 8516a1d639 | |||
| 006992e43c | |||
| 48911e9348 | |||
| e4e1a905d1 | |||
| fc935d9fc8 | |||
| 0c6a9f2310 | |||
| d23fd8bd07 | |||
| 9d6ae87d0f | |||
| fc5a8bdd8b | |||
| b8717f1327 | |||
| 0aa317aae5 | |||
|
|
edc19bdff8 | ||
| 11a7204c98 | |||
| eab7883979 | |||
| 2d4249e73a | |||
| 63db1352ee | |||
| 8308115f36 | |||
|
|
02fce838db | ||
| 360d171355 | |||
| eb26e2a11b | |||
| 2b29e34b52 | |||
| fd8766ed87 | |||
| 5de8804da1 | |||
| 2988fd387e | |||
| 1b017edfad | |||
| 903ce7d46b | |||
| 41bcb80167 | |||
|
|
d3f85060ca | ||
| 90178e2f61 | |||
|
|
b9f9a003a2 | ||
| 734f4c7750 | |||
| c78cd898f2 | |||
| 74a249bd06 | |||
| 2020953b93 | |||
| 3826bb3d9e | |||
| 7ffc06f3c7 | |||
|
|
eea1a75d4a | ||
| b9bff38b64 | |||
| f04862933f | |||
| f5b8375fd3 | |||
| db1cdf4280 | |||
| fa1e86ff07 | |||
|
|
9a95454723 | ||
| dd1875ea5c | |||
|
|
df4fabb32a | ||
| 99114f14f6 | |||
|
|
fc3a69bbb0 | ||
| 9594be2606 | |||
|
|
96fd239608 | ||
| 61de7e9e22 | |||
|
|
24c4cdc39f | ||
| fadbf77866 | |||
| 03819a3d90 | |||
| d6d0777113 | |||
| 1aa83e0ef1 | |||
|
|
b09c644e01 | ||
| e403870874 | |||
| 1586ce2d6c | |||
| 576353cfe8 | |||
|
|
cefc415c98 | ||
| bc0ef7893e | |||
|
|
0e802d8194 | ||
| d7718d4dcb | |||
|
|
4c2e02e912 | ||
| b8774e0b0b | |||
| 6e75642090 | |||
| aaa0d1003d | |||
| 5960918137 | |||
| 3dc0532df0 | |||
| 96863adf53 | |||
|
|
08425a623e | ||
| b787759f44 | |||
|
|
25ef7c05e6 | ||
| c36bb80d6a | |||
|
|
c069f3e1b3 | ||
| 215d59c8bf | |||
| 008a33a9b1 | |||
| 3e787234c7 | |||
| 1173510105 | |||
| a391f3018c | |||
| b6e1e20b7c | |||
| 572f2fb811 | |||
| 2e2d422910 | |||
| f0556e4411 | |||
| 4a97105e4b | |||
| 797f73c39a | |||
| b8f796fd3f | |||
| 78673ea11a | |||
| c6a14c0768 | |||
|
|
70a966d8dc | ||
| c42511dd44 | |||
|
|
db62f9e998 | ||
| 0610d2f9f0 | |||
| c1dd0ee190 | |||
| a45c407568 | |||
|
|
813f57861c | ||
| 3faee98ec8 | |||
| ca02132c8d | |||
|
|
cb4ef25b73 | ||
| c8b7367815 | |||
| a268caaa30 | |||
| 6b25abff70 | |||
| 21c807f358 | |||
| 56fdae4275 | |||
| e6a06c9f43 | |||
| f979a63d3d | |||
|
|
327bc54e22 | ||
| a51b15da3f | |||
| 7271b422f9 | |||
| 1866ba66c8 | |||
|
|
6175a04a90 | ||
| 7120f3e93b | |||
| acc13183e2 | |||
| f75fc19c5b | |||
|
|
2650c8b8cf | ||
| 1de3cbf65a | |||
|
|
4a9d0c9e44 | ||
| 88ecd05b95 | |||
| df812eaad5 | |||
|
|
d62da494c8 | ||
| e631fc15d8 | |||
|
|
ecbf1ce0c8 | ||
| e5c0087c9a | |||
| 4348ed1bb2 | |||
|
|
5c11fde0a9 | ||
| 4ca1efeeb8 | |||
| aa7ce2ea27 | |||
|
|
174f0cdcb6 | ||
| 860517a321 | |||
|
|
66daae6d9e | ||
| 83001a0d82 | |||
| 1b7921a7f2 | |||
| 8badb6adc1 | |||
| 37682e7b8a | |||
| 56e74a0e7d | |||
| ec4574ed5c | |||
| 21d20e0fc7 | |||
| 7ce3a83c58 | |||
| 6dff1879c4 | |||
| c09644b29d | |||
| d8cf44134c | |||
| ca856384f3 | |||
| 4e2c9df6a4 | |||
| 8b822e0fa8 | |||
| 67d398caf7 | |||
|
|
c2c27f8279 | ||
| 50b3422528 | |||
| 4639eee0b9 | |||
| b4b27aea3d | |||
| e483b282db | |||
| 36391db607 | |||
| 5362334ff3 | |||
| fdf11d8147 | |||
|
|
204f653b72 | ||
| 48ae950d57 | |||
| 925c893f3f | |||
|
|
b54423a151 | ||
| ce374163ca | |||
| 3644f344da | |||
| d1266a1ce1 | |||
| f7d0b0768a | |||
| 630616ec72 | |||
|
|
7f7bef7581 | ||
| d2f2b206bb | |||
| 6fa1c06053 | |||
| 5d4ca816cd | |||
| 443b6c1d7b | |||
| 505a5ec833 | |||
|
|
3a7289bf5e | ||
| 2718bc6247 | |||
|
|
515d2651bf | ||
| ef25f56380 | |||
|
|
5b280ccc1e | ||
| cbbd23aa33 | |||
|
|
860d0ad014 | ||
| fa344a5799 | |||
|
|
3919de5bd5 | ||
| 1a0a98a453 | |||
| d79f7e9ccd | |||
| 50e41ff261 | |||
| 430b282039 | |||
|
|
17133771bb | ||
| e5a7d47b21 | |||
|
|
71ec61e27b | ||
| b3575eb068 | |||
| 216511b951 | |||
| 6dabbf874f | |||
|
|
d5aad06c88 | ||
| 5d6672069e | |||
| 140ad83380 | |||
| ea805d1362 | |||
| 9e16f2faf9 | |||
| 2a36d9364f | |||
| 27426ce7a5 | |||
|
|
69adadd6d7 | ||
| 6f96498de6 | |||
| 836b6e64f6 | |||
|
|
fab7dd7eec | ||
| 9263f8ef5c | |||
|
|
658728efef | ||
| 6b8432f5b2 | |||
| bc709c4184 | |||
| b49462abeb | |||
| d9d4e3c9bf | |||
| fe04dd80e5 | |||
|
|
718950cf0d | ||
| 17a0068757 | |||
| abc6caa2d0 | |||
|
|
99fb82561b | ||
| 61ba08d0b8 | |||
| 40b5688158 | |||
|
|
0a4e253cbd | ||
| 6428e38ab9 | |||
| fc4f4f81ad | |||
| f6629852eb | |||
| 3adf6cfd58 | |||
| b15816ca9f | |||
| 6b1d5827d6 | |||
| f0391f59c9 | |||
| 006a0894b8 | |||
| 9c5a471234 | |||
| 1c7f4912ce | |||
| df1be10057 | |||
| 954c576131 | |||
| 867720a897 | |||
| 2b40602bdc | |||
| 11173b9c0a | |||
|
|
52d46e77db | ||
| e7838b0f2f | |||
|
|
2ae3810cf6 | ||
| 178fe4d2da | |||
| 2d79ef8fe5 | |||
| d56c5493cd | |||
| cf6e5a40fc | |||
| 64abd67b9b | |||
|
|
c19e856800 | ||
| 02a26086c4 | |||
|
|
35f880bc2f | ||
| c0ddeceeea | |||
| 67fd5e8581 | |||
| bf699ec1fb | |||
| 3094632134 | |||
| 6985ff0fce | |||
| 33f7be42c5 | |||
|
|
36fac70361 | ||
| ca5e8d2fbb | |||
| 828067f486 | |||
|
|
e5f4c0b952 | ||
| edb1775967 | |||
|
|
d0d6908a74 | ||
| c037b87675 | |||
| 52bc322b2b | |||
| 8479caf53a | |||
| 82e2c898d2 | |||
|
|
4852076e4a | ||
| 15cbc21e5b | |||
| ffae5ee54e | |||
|
|
10d77f20d1 | ||
| 4be0d14b74 | |||
| e883dbad81 | |||
| a2abad344f | |||
| d44b1cf8b1 | |||
| c5b6499e41 | |||
| a951ebf1be | |||
| 32da803df9 | |||
| 07d60cf735 | |||
|
|
fceb851c32 | ||
| e1af5ca60f | |||
| 7fb31fc4d7 | |||
| 5c6ba65469 | |||
| cd9fc46ff8 | |||
| 2a88e17b23 | |||
| 69f4371007 | |||
|
|
af2c816d35 | ||
| f51b25f0af | |||
| c3f4845b4f | |||
| 8ae323f5c3 | |||
|
|
a3805a765b | ||
| 8c03034acf | |||
| 4160f3d6d7 | |||
|
|
4742e1ff6a | ||
| 4af1abe4e1 | |||
| 131f49da8e | |||
|
|
f9bf496bd3 | ||
| 9648e3ea96 | |||
| 4be756a867 | |||
| 46face0ee5 | |||
| 6f3b1ea985 | |||
| 3c9181d93d | |||
|
|
a05f24785e | ||
| 9d615c915c | |||
| d2539918b2 | |||
|
|
ed264cb528 | ||
| ad208a5ef8 | |||
| ddc9510c2b | |||
| 855be3551a | |||
| db301b1be2 | |||
| 07b99d91a5 |
115
.gitlab-ci.yml
@@ -1,7 +1,7 @@
|
||||
# This file is a template, and might need editing before it works on your project.
|
||||
# Official language image. Look for the different tagged releases at:
|
||||
# https://hub.docker.com/r/library/python/tags/
|
||||
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:3.10
|
||||
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:3.11
|
||||
#commands to run in the Docker container before starting each job.
|
||||
variables:
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
@@ -22,7 +22,13 @@ workflow:
|
||||
|
||||
include:
|
||||
- template: Security/Secret-Detection.gitlab-ci.yml
|
||||
|
||||
- project: "bec/awi_utils"
|
||||
file: "/templates/check-packages-job.yml"
|
||||
inputs:
|
||||
stage: test
|
||||
path: "."
|
||||
pytest_args: "-v --random-order tests/"
|
||||
exclude_packages: ""
|
||||
|
||||
# different stages in the pipeline
|
||||
stages:
|
||||
@@ -32,8 +38,29 @@ stages:
|
||||
- End2End
|
||||
- Deploy
|
||||
|
||||
.install-qt-webengine-deps: &install-qt-webengine-deps
|
||||
- apt-get -y install libnss3 libxdamage1 libasound2 libatomic1 libxcursor1
|
||||
- export QTWEBENGINE_DISABLE_SANDBOX=1
|
||||
|
||||
.clone-repos: &clone-repos
|
||||
- echo -e "\033[35;1m Using branch $BEC_CORE_BRANCH of BEC CORE \033[0;m";
|
||||
- git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
|
||||
- echo -e "\033[35;1m Using branch $OPHYD_DEVICES_BRANCH of OPHYD_DEVICES \033[0;m";
|
||||
- git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
|
||||
- export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
|
||||
|
||||
.install-repos: &install-repos
|
||||
- pip install -e ./ophyd_devices
|
||||
- pip install -e ./bec/bec_lib[dev]
|
||||
- pip install -e ./bec/bec_ipython_client
|
||||
|
||||
.install-os-packages: &install-os-packages
|
||||
- apt-get update
|
||||
- apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3 xvfb
|
||||
- *install-qt-webengine-deps
|
||||
|
||||
before_script:
|
||||
- if [[ "$CI_PROJECT_PATH" != "bec/bec_widgets" ]]; then
|
||||
- if [[ "$CI_PROJECT_PATH" != "bec/bec_widgets" ]]; then
|
||||
echo -e "\033[35;1m Using branch $CHILD_PIPELINE_BRANCH of BEC Widgets \033[0;m";
|
||||
test -d bec_widgets || git clone --branch $CHILD_PIPELINE_BRANCH https://gitlab.psi.ch/bec/bec_widgets.git; cd bec_widgets;
|
||||
fi
|
||||
@@ -65,7 +92,7 @@ pylint:
|
||||
- ./pylint/
|
||||
expire_in: 1 week
|
||||
rules:
|
||||
- if: $CI_PROJECT_PATH == "bec/bec_widgets"
|
||||
- if: $CI_PROJECT_PATH == "bec/bec_widgets"
|
||||
|
||||
pylint-check:
|
||||
stage: Formatter
|
||||
@@ -76,18 +103,21 @@ pylint-check:
|
||||
- apt-get update
|
||||
- apt-get install -y bc
|
||||
script:
|
||||
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
|
||||
# Identify changed Python files
|
||||
- if [ "$CI_PIPELINE_SOURCE" == "merge_request_event" ]; then
|
||||
TARGET_BRANCH_COMMIT_SHA=$(git rev-parse $CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
|
||||
CHANGED_FILES=$(git diff --name-only $SOURCE_BRANCH_COMMIT_SHA $TARGET_BRANCH_COMMIT_SHA | grep '\.py$' || true);
|
||||
TARGET_BRANCH_COMMIT_SHA=$(git rev-parse origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME);
|
||||
CHANGED_FILES=$(git diff --name-only $TARGET_BRANCH_COMMIT_SHA HEAD | grep '\.py$' || true);
|
||||
else
|
||||
CHANGED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' || true);
|
||||
CHANGED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' || true);
|
||||
fi
|
||||
- if [ -z "$CHANGED_FILES" ]; then echo "No Python files changed."; exit 0; fi
|
||||
|
||||
- echo "Changed Python files:"
|
||||
- $CHANGED_FILES
|
||||
# Run pylint only on changed files
|
||||
- mkdir ./pylint
|
||||
- pylint $CHANGED_FILES --output-format=text . | tee ./pylint/pylint_changed_files.log || pylint-exit $?
|
||||
- pylint $CHANGED_FILES --output-format=text | tee ./pylint/pylint_changed_files.log || pylint-exit $?
|
||||
- PYLINT_SCORE=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' ./pylint/pylint_changed_files.log)
|
||||
- echo "Pylint score is $PYLINT_SCORE"
|
||||
|
||||
@@ -98,20 +128,17 @@ pylint-check:
|
||||
- ./pylint/
|
||||
expire_in: 1 week
|
||||
rules:
|
||||
- if: $CI_PROJECT_PATH == "bec/bec_widgets"
|
||||
- if: $CI_PROJECT_PATH == "bec/bec_widgets"
|
||||
|
||||
tests:
|
||||
stage: test
|
||||
needs: []
|
||||
variables:
|
||||
QT_QPA_PLATFORM: "offscreen"
|
||||
QT_QPA_PLATFORM: "offscreen"
|
||||
script:
|
||||
- git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
|
||||
- git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
|
||||
- export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
|
||||
- apt-get update
|
||||
- apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3
|
||||
- pip install -e ./bec/bec_lib[dev]
|
||||
- *clone-repos
|
||||
- *install-os-packages
|
||||
- *install-repos
|
||||
- pip install -e .[dev,pyqt6]
|
||||
- coverage run --source=./bec_widgets -m pytest -v --junitxml=report.xml --random-order --full-trace ./tests/unit_tests
|
||||
- coverage report
|
||||
@@ -123,18 +150,34 @@ tests:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: coverage.xml
|
||||
paths:
|
||||
- tests/reference_failures/
|
||||
when: always
|
||||
|
||||
test-matrix:
|
||||
parallel:
|
||||
matrix:
|
||||
- PYTHON_VERSION:
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
QT_PCKG:
|
||||
- "pyside6"
|
||||
- "pyqt6"
|
||||
|
||||
tests-3.11:
|
||||
extends: "tests"
|
||||
stage: AdditionalTests
|
||||
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:3.11
|
||||
allow_failure: true
|
||||
|
||||
tests-3.12:
|
||||
extends: "tests"
|
||||
stage: AdditionalTests
|
||||
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:3.12
|
||||
needs: []
|
||||
variables:
|
||||
QT_QPA_PLATFORM: "offscreen"
|
||||
PYTHON_VERSION: ""
|
||||
QT_PCKG: ""
|
||||
image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:$PYTHON_VERSION
|
||||
script:
|
||||
- *clone-repos
|
||||
- *install-os-packages
|
||||
- *install-repos
|
||||
- pip install -e .[dev,$QT_PCKG]
|
||||
- pytest -v --junitxml=report.xml --random-order ./tests/unit_tests
|
||||
allow_failure: true
|
||||
|
||||
end-2-end-conda:
|
||||
@@ -145,29 +188,24 @@ end-2-end-conda:
|
||||
variables:
|
||||
QT_QPA_PLATFORM: "offscreen"
|
||||
script:
|
||||
- apt-get update
|
||||
- apt-get install -y libgl1-mesa-glx libegl1-mesa x11-utils libxkbcommon-x11-0 libdbus-1-3
|
||||
- *clone-repos
|
||||
- *install-os-packages
|
||||
- conda config --prepend channels conda-forge
|
||||
- conda config --set channel_priority strict
|
||||
- conda config --set always_yes yes --set changeps1 no
|
||||
- conda create -q -n test-environment python=3.10
|
||||
- conda create -q -n test-environment python=3.11
|
||||
- conda init bash
|
||||
- source ~/.bashrc
|
||||
- conda activate test-environment
|
||||
|
||||
- git clone --branch $BEC_CORE_BRANCH https://gitlab.psi.ch/bec/bec.git
|
||||
- git clone --branch $OPHYD_DEVICES_BRANCH https://gitlab.psi.ch/bec/ophyd_devices.git
|
||||
- export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
|
||||
|
||||
- cd ./bec
|
||||
- source ./bin/install_bec_dev.sh -t
|
||||
|
||||
- pip install -e ./bec_lib[dev]
|
||||
- pip install -e ./bec_ipython_client[dev]
|
||||
- cd ../
|
||||
- pip install -e ./ophyd_devices
|
||||
|
||||
- pip install -e .[dev,pyqt6]
|
||||
- cd ./tests/end-2-end
|
||||
- pytest --start-servers --flush-redis --random-order
|
||||
- pytest -v --start-servers --flush-redis --random-order
|
||||
|
||||
artifacts:
|
||||
when: on_failure
|
||||
@@ -183,7 +221,6 @@ end-2-end-conda:
|
||||
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"'
|
||||
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "production"'
|
||||
|
||||
|
||||
semver:
|
||||
stage: Deploy
|
||||
needs: ["tests"]
|
||||
@@ -202,7 +239,7 @@ semver:
|
||||
- pip install python-semantic-release==9.* wheel build twine
|
||||
- export GL_TOKEN=$CI_UPDATES
|
||||
- semantic-release -vv version
|
||||
|
||||
|
||||
# check if any artifacts were created
|
||||
- if [ ! -d dist ]; then echo No release will be made; exit 0; fi
|
||||
- twine upload dist/* -u __token__ -p $CI_PYPI_TOKEN --skip-existing
|
||||
@@ -218,7 +255,7 @@ pages:
|
||||
variables:
|
||||
TARGET_BRANCH: $CI_COMMIT_REF_NAME
|
||||
rules:
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
- if: "$CI_COMMIT_TAG != null"
|
||||
variables:
|
||||
TARGET_BRANCH: $CI_COMMIT_TAG
|
||||
- if: '$CI_COMMIT_REF_NAME == "main" && $CI_PROJECT_PATH == "bec/bec_widgets"'
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code.
|
||||
extension-pkg-allow-list=PyQt5, pyqtgraph
|
||||
extension-pkg-allow-list=PyQt6, PySide6, pyqtgraph
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
|
||||
274
CHANGELOG.md
@@ -1,171 +1,149 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.94.2 (2024-08-13)
|
||||
|
||||
### Fix
|
||||
|
||||
## v0.55.0 (2024-05-24)
|
||||
* fix(image): image is single image mode do not raise popup error when connected twice with the same monitor ([`98b79aa`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/98b79aac7b47b73137f4d582f7f1d552b1d95366))
|
||||
|
||||
## v0.94.1 (2024-08-12)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: issue #292, wrong key was used to clean _slots internal dictionary ([`93d3977`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/93d397759c756397604ebff5e24f3a580be8620d))
|
||||
|
||||
## v0.94.0 (2024-08-08)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(widgets/progressbar): SpiralProgressBar added with rpc interface ([`76bd0d3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/76bd0d339ac9ae9e8a3baa0d0d4e951ec1d09670))
|
||||
|
||||
|
||||
## v0.54.0 (2024-05-24)
|
||||
|
||||
### Build
|
||||
|
||||
* build: added pyqt6 as sphinx build dependency ([`a47a8ec`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a47a8ec413934cf7fce8d5b7a5913371d4b3b4a5))
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(figure): changes to support direct plot functionality ([`fc4d0f3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fc4d0f3bb2a7c2fca9c326d86eb68b305bcd548b))
|
||||
* feat: add PositionerControlLine ([`c80a7cd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c80a7cd1083baa9543a2cee2e3c3a51dfd209b19))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(reconstruction): repository structure is changed to separate assets needed for each widget ([`3455c60`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3455c602361d3b5cc3ff9190f9d2870474becf8a))
|
||||
* refactor: adjust dimensions ([`0273bf4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0273bf485694609325b5b556a3c69fb53c18446e))
|
||||
|
||||
* refactor(clean-up): 1st generation widgets are removed ([`edc25fb`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/edc25fbf9d5a0321e5f0a80b492b6337df807849))
|
||||
|
||||
|
||||
## v0.53.3 (2024-05-16)
|
||||
## v0.93.5 (2024-08-08)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: removed apparently unnecessary sleep while waiting for an rpc response ([`7d64cac`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7d64cac6610b39d3553ff650354f78ead8ee6b55))
|
||||
|
||||
|
||||
## v0.53.2 (2024-05-15)
|
||||
|
||||
### Ci
|
||||
|
||||
* ci: added echo to highlight the current branch ([`0490e80`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0490e80c48563e4fb486bce903b3ce1f08863e83))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: check device class without importing to speed up initial import time ([`9f8fbdd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9f8fbdd5fc13cf2be10eacb41e10cf742864cd92))
|
||||
|
||||
* fix: speed up initial import times using lazy import (from bec_lib) ([`d1e6cd3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d1e6cd388c6c9f345f52d6096d8a75a1fa7e6934))
|
||||
|
||||
* fix: adapt to bec_lib changes (no more submodules in `__init__.py`) ([`5d09a13`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5d09a13d8820a8bdb900733c97593b723a2fce1d))
|
||||
|
||||
|
||||
## v0.53.1 (2024-05-09)
|
||||
|
||||
### Ci
|
||||
|
||||
* ci: fixed rtd pages url ([`8ff3610`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8ff36105d1e637c429915b4bfc2852d54a3c6f19))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: docs config ([`0f6a5e5`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0f6a5e5fa9530969c98a9266c9ca7b89a378ff70))
|
||||
|
||||
|
||||
## v0.53.0 (2024-05-09)
|
||||
|
||||
### Ci
|
||||
|
||||
* ci: use formatter config of toml file ([`5cc816d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5cc816d0af73e20c648e044a027c589704ab1625))
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs: update install instructions ([`57ee735`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/57ee735e5c2436d45a285507cdc939daa20e8e8f))
|
||||
|
||||
### Feature
|
||||
|
||||
* feat: moved to pyproject.toml; closes #162 ([`c86ce30`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c86ce302a964d71ee631f0817609ab5aa0e3ab0f))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: fixed semver job and upgraded to v9 ([`32e1a9d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/32e1a9d8472eb1c25d30697d407a8ffecd04e75d))
|
||||
* fix(positioner_box): icons fixed ([`281633d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/281633deff15b6879dac3a4f0770fa6949aaecdc))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor: applied formatter ([`4117fd7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4117fd7b5b2090ff4fb7ad9e0d92cc87cd13ed5f))
|
||||
|
||||
|
||||
## v0.52.1 (2024-05-08)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(docstrings): docstrings formating fixed for sphinx to properly format readdocs ([`7f2f7cd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7f2f7cd07a14876617cd83cedde8c281fdc52c3a))
|
||||
|
||||
|
||||
## v0.52.0 (2024-05-07)
|
||||
|
||||
### Ci
|
||||
|
||||
* ci: fixed support for child pipelines ([`e65c7f3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e65c7f3be895ada407bd358edf67d569d2cab08e))
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(utils/layout_manager): added GridLayoutManager to extend functionalities of native QGridLayout ([`fcd6ef0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fcd6ef0975dc872f69c9d6fb2b8a1ad04a423aae))
|
||||
|
||||
* feat(widget/dock): BECDock and BECDock area for dockable windows ([`d8ff8af`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d8ff8afcd474660a6069bbdab05f10a65f221727))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(widgets/dock): BECDockArea close overwrites the default pyqtgraph Container close + minor improvements ([`ceae979`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ceae979f375ecc33c5c97148f197655c1ca57b6c))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(widget/plots): WidgetConfig changed to SubplotConfig ([`03fa1f2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/03fa1f26d0fa6b58ed05556fb2438d1e62f6c107))
|
||||
|
||||
|
||||
## v0.51.0 (2024-05-07)
|
||||
|
||||
### Build
|
||||
|
||||
* build(cli): changed repo name to bec_widgets ([`799ea55`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/799ea554de9a7f3720d100be4886a63f02c6a390))
|
||||
|
||||
* build(setup): fakeredis added to dev env ([`df32350`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/df323504fea024a97304d96c2e39e61450714069))
|
||||
|
||||
* build(setup): PyQt6 version is set to 6.7 ([`0ab8aa3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0ab8aa3a2fe51b5c38b25fca44c1c422bb42478d))
|
||||
|
||||
### Ci
|
||||
|
||||
* ci: added rule for parent-child pipelines ([`e085125`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e0851250eecb85503db929d37f75d2ba366308a6))
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(utils): added plugin helper to find and load ([`5ece269`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5ece269adb0e9b0c2a468f1dfbaa6212e86d3561))
|
||||
|
||||
|
||||
## v0.50.2 (2024-04-30)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: 'disconnect_slot' has to be symmetric with 'connect_slot' regarding QtThreadSafeCallback ([`0dfcaa4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0dfcaa4b708948af0a40ec7cf34d03ff1e96ffac))
|
||||
|
||||
|
||||
## v0.50.1 (2024-04-29)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(cli): BECFigure takes the port to connect to redis from the current BECClient, supporting plugins ([`57cb136`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/57cb136a098e87a452414bf44e627edb562f6799))
|
||||
|
||||
|
||||
## v0.50.0 (2024-04-29)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(plots): universal cleanup and remove also for children items ([`381d713`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/381d713837bb9217c58ba1d8b89691aa35c9f5ec))
|
||||
|
||||
* feat(rpc/rpc_register): singleton rpc register for all rpc connections for session ([`a898e7e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a898e7e4f14e9ae854703dddbd1eb8c50cb640ff))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(widgets/figure): access pattern changed for getting widgets by coordinates for rpc ([`13c018a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/13c018a79704a7497c140df57179d294e43ecffa))
|
||||
|
||||
* fix(plots): cleanup policy reviewed for children items ([`8f20a0b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8f20a0b3b1b5dd117b36b45645717190b9ee9cbf))
|
||||
|
||||
* fix(rpc/client_utils): getoutput more transparent + error handling ([`6b6a6b2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6b6a6b2249f24d3d02bd5fcd7ef1c63ed794c304))
|
||||
|
||||
* fix(rpc_register): thread lock for listign all connections ([`2ca3267`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2ca32675ec3f00137e2140259db51f6e5aa7bb71))
|
||||
* refactor: add button for positioner selection ([`0d190c5`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0d190c5c5996e59fec4bdd44d2003e10e200b009))
|
||||
|
||||
### Test
|
||||
|
||||
* test(cli/rpc_register): e2e RPCRegister ([`4f261be`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4f261be4c7cfe54501443d031f9266f4f838f6e2))
|
||||
* test(dap): wait for fit ([`6269009`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6269009e5451f830cdee58a514c7858483488a8d))
|
||||
|
||||
* test(cli/rpc_register): rpc_register tests added ([`40eb75f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/40eb75f85a4d99d498b086a37e799276a9d2ac3f))
|
||||
* test(auto-update): wait for rendering ([`6d2442d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6d2442d23c683fe92af13df982ce681c07e99cde))
|
||||
|
||||
## v0.93.4 (2024-08-07)
|
||||
|
||||
## v0.49.1 (2024-04-26)
|
||||
### Fix
|
||||
|
||||
* fix: rename DeviceBox to PositionerBox, fix test for validation ([`37aa371`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/37aa371e7c4c62d70abf37abc125db0c088790fe))
|
||||
|
||||
* fix: add validation for bec_lib.device.Positioner; closes #268 ([`eb54e9f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/eb54e9f788e97af23db8fe0c78f8facb8688bb99))
|
||||
|
||||
## v0.93.3 (2024-08-07)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(dock): properly shut down docks and temp areas ([`99ee545`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/99ee545e41c6078654958b668b5b329f85553d16))
|
||||
|
||||
* fix(settings): shut down settings dialog ([`b50b3a2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b50b3a27e68956e10e8169a0aa698c911d2d9642))
|
||||
|
||||
* fix(website): fixed teardown of website widgets ([`a3d4f5a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a3d4f5ac4bc52acfed2791a1724fade6972ed320))
|
||||
|
||||
* fix(dock): properly shut down docks and dock areas ([`bc26497`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bc264975b1363c9dfea516621d7878c320677d15))
|
||||
|
||||
* fix(figure): cleanup pyqtgraph ([`ad07bbf`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ad07bbf85e9c8d9838bdd686f69d41c235b7db19))
|
||||
|
||||
### Test
|
||||
|
||||
* test: removed quit from teardown ([`cf94599`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cf94599c2544d6831c8afbe7b340082077557ed1))
|
||||
|
||||
* test: removed explicit call to close the widget ([`bf6294e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bf6294ecbfd494565d2dc215e4d7e0c280ac7745))
|
||||
|
||||
* test: use factory instead of fixture to properly cleanup widgets on teardown ([`9856857`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9856857f4cc7fa229c10d00fbae4452464a207cb))
|
||||
|
||||
* test: ensure all toplevelwidgets are closed ([`f9e5897`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f9e58979009cf632feea529700ad191401dd7eb8))
|
||||
|
||||
## v0.93.2 (2024-08-07)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(scan_group_box): Scan Spinboxes limits increased to max allowed values; setting dialog for step size and decimal precision for ScanDoubleSpinBox on right click ([`a372925`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a372925fffa787c686198ae7cb3f9c15b459c109))
|
||||
|
||||
## v0.93.1 (2024-08-06)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs: added video tutorial section with BSEG YT video ([`302ae90`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/302ae90139f6a88e2401fe29fe312387486e27a9))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(dock): docks have more recognizable red icon for closing docks ([`af86860`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/af86860bf35474805fb1a7bc3725cf8835ed4cc7))
|
||||
|
||||
## v0.93.0 (2024-08-05)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(themes): moved themes to bec_qthemes
|
||||
|
||||
This reverts commit fd6ae91993a23a7b8dbb2cf3c4b7c3eda6d2b0f6 ([`5aad401`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5aad401ef8774c7330784f72cd3b9d8c253e2b6a))
|
||||
|
||||
## v0.92.5 (2024-08-05)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(spinner): stop timer on close event ([`30fef92`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/30fef929cf6fb4b73f48151c92a0ee54c734031d))
|
||||
|
||||
* fix(status_box): fix cleanup of status box ([`1f30dd7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1f30dd73a9c1e3135087a5eef92c7329f54a604e))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(queue): refactored bec queue to inherit only from qwidget ([`7616ca0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7616ca0e145e233ccb48029a8c0b54b54b5b4194))
|
||||
|
||||
### Test
|
||||
|
||||
* test: register all widgets with qtbot and close them ([`73cd11e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/73cd11e47277e4437554b785a9551b28a572094f))
|
||||
|
||||
## v0.92.4 (2024-07-31)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: fix missmatch of signal/slot in image and motormap ([`dcc5fd7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/dcc5fd71ee9f51767a7b2b1ed6200e89d1ef754c))
|
||||
|
||||
## v0.92.3 (2024-07-28)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(docs): moved to pyside6 ([`71873dd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/71873ddf359516ded8f74f4d2f73df4156aa1368))
|
||||
|
||||
## v0.92.2 (2024-07-28)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(widgets): fixed import for tictactoe example ([`995a795`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/995a795060bebe25c17108d80ae0fa30463f03b1))
|
||||
|
||||
## v0.92.1 (2024-07-28)
|
||||
|
||||
### Build
|
||||
|
||||
* build(ci): install ophyd_devices in editable mode for pipelines ([`06205e0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/06205e07903d93accf40abab153f440059f236ed))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: use SafeSlot instead of Slot ([`bc1e239`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bc1e23944cc0e5a861e3d0b4dc5b4ac6292d5269))
|
||||
|
||||
* fix: linting ([`a3fe205`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a3fe20500ae2ac03dcde07432f7e21ce5262ce46))
|
||||
|
||||
* fix: always add a QApplication for tests ([`61a4e32`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/61a4e32deb337ed27f2f43358b88b7266413b58e))
|
||||
|
||||
* fix: add xvfb to draw offscreen ([`3d681f7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3d681f77e144e74138fc5fa65630004d7c166878))
|
||||
|
||||
* fix: reset ErrorPopup singleton between tests ([`5a9ccfd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5a9ccfd1f6d2aacd5d86c1a34f74163b272d1ae4))
|
||||
|
||||
* fix: metaclass + QObject segfaults PyQt(cpp bindings) ([`fc57b7a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fc57b7a1262031a2df9e6a99493db87e766b779a))
|
||||
|
||||
@@ -17,7 +17,7 @@ cd bec_widgets
|
||||
pip install -e .[dev,pyqt6]
|
||||
```
|
||||
|
||||
BEC Widgets currently supports both PyQt5 and PyQt6, however, no default distribution is specified. As a result, users must install one of the supported
|
||||
BEC Widgets currently supports both Pyside6 and PyQt6, however, no default distribution is specified. As a result, users must install one of the supported
|
||||
Python Qt distributions manually.
|
||||
|
||||
To select a specific Python Qt distribution, install the package with an additional tag:
|
||||
@@ -28,7 +28,7 @@ pip install bec_widgets[pyqt6]
|
||||
or
|
||||
|
||||
```bash
|
||||
pip install bec_widgets[pyqt5]
|
||||
pip install bec_widgets[pyside6]
|
||||
```
|
||||
## Documentation
|
||||
|
||||
|
||||
BIN
bec_widgets/assets/app_icons/BEC-Dark.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
BIN
bec_widgets/assets/designer_icons/code.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
bec_widgets/assets/designer_icons/color_button.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
bec_widgets/assets/designer_icons/colormap_selector.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
bec_widgets/assets/designer_icons/device_combo_box.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
bec_widgets/assets/designer_icons/device_line_edit.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
bec_widgets/assets/designer_icons/dock_area.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
bec_widgets/assets/designer_icons/games.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
bec_widgets/assets/designer_icons/image.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
bec_widgets/assets/designer_icons/motor_map.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
bec_widgets/assets/designer_icons/position_indicator.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
bec_widgets/assets/designer_icons/positioner_box.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
bec_widgets/assets/designer_icons/queue.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
bec_widgets/assets/designer_icons/ring_progress.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
bec_widgets/assets/designer_icons/scan_control.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
bec_widgets/assets/designer_icons/spinner.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
bec_widgets/assets/designer_icons/status.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
bec_widgets/assets/designer_icons/stop.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
bec_widgets/assets/designer_icons/text.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
bec_widgets/assets/designer_icons/toggle.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
bec_widgets/assets/designer_icons/waveform.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
bec_widgets/assets/designer_icons/web.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
3
bec_widgets/assets/status_icons/error.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#EA3323">
|
||||
<path d="M479.85-265.87q19.8 0 32.69-12.46 12.9-12.46 12.9-32.26 0-19.8-12.75-32.98-12.74-13.17-32.54-13.17-19.8 0-32.69 13.16-12.9 13.15-12.9 32.95 0 19.8 12.75 32.28 12.74 12.48 32.54 12.48Zm-36.46-166.56h79.22v-262.61h-79.22v262.61Zm36.95 366.56q-86.2 0-161.5-32.39-75.3-32.4-131.74-88.84-56.44-56.44-88.84-131.73-32.39-75.3-32.39-161.59t32.39-161.67q32.4-75.37 88.75-131.34t131.69-88.62q75.34-32.65 161.67-32.65 86.34 0 161.78 32.61 75.45 32.6 131.37 88.5 55.93 55.89 88.55 131.45 32.63 75.56 32.63 161.87 0 86.29-32.65 161.58t-88.62 131.48q-55.97 56.18-131.42 88.76-75.46 32.58-161.67 32.58Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 718 B |
3
bec_widgets/assets/status_icons/not_connected.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#EA3323">
|
||||
<path d="m759.04-283.09-63.13-62q49.31-9.43 84.44-46.02 35.13-36.59 35.13-86.14 0-55.49-39.42-95.08-39.43-39.58-94.93-39.58h-153.3v-79.79h152.74q89.28 0 151.7 62.71Q894.7-566.28 894.7-477q0 63.7-38.26 115.96-38.27 52.26-97.4 77.95ZM596.83-443.61l-65.66-66.78h110.05v66.78h-44.39ZM804.96-56 58.48-802.48 106-850l746.48 746.48L804.96-56ZM443.22-265.87H279.43q-89.28 0-151.7-62.42Q65.3-390.72 65.3-480q0-72.57 43.09-129.54 43.09-56.98 112.09-76.07l70.13 70.7h-11.18q-55.73 0-95.32 39.3-39.59 39.31-39.59 95.61t39.66 95.61q39.66 39.3 95.5 39.3h163.54v79.22ZM319.35-446.61v-66.78h77.3l66.78 66.78H319.35Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 721 B |
3
bec_widgets/assets/status_icons/refresh.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFF55">
|
||||
<path d="M478.3-145.87q-138.65 0-236.39-97.74-97.74-97.74-97.74-236.25t97.74-236.68q97.74-98.16 236.39-98.16 88.4 0 155.45 35.76 67.04 35.76 115.86 98.9V-814.7h66.78v274.92H540.91V-606h165.74q-38.56-57.74-95.3-93.33-56.74-35.58-133.05-35.58-106.88 0-180.89 73.98-74.02 73.99-74.02 180.83 0 106.84 74.02 180.93 74.02 74.08 180.91 74.08 80.16 0 147.74-46.08 67.59-46.09 95.16-121.83H803q-29.56 110.65-119.67 178.89-90.1 68.24-205.03 68.24Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 559 B |
3
bec_widgets/assets/status_icons/running.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#75FB4C">
|
||||
<path d="m419.87-289.52 289.22-289.22-57.31-56.87L419.87-403.7 304.96-518.61l-56.31 56.87 171.22 172.22Zm60.21 223.65q-85.47 0-161.01-32.39-75.53-32.4-131.97-88.84-56.44-56.44-88.84-131.89-32.39-75.46-32.39-160.93 0-86.47 32.39-162.01 32.4-75.53 88.75-131.5t131.85-88.62q75.5-32.65 161.01-32.65 86.52 0 162.12 32.61 75.61 32.6 131.53 88.5 55.93 55.89 88.55 131.45Q894.7-566.58 894.7-480q0 85.55-32.65 161.07-32.65 75.53-88.62 131.9-55.97 56.37-131.42 88.77-75.46 32.39-161.93 32.39Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 604 B |
3
bec_widgets/assets/status_icons/warning.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#F19E39">
|
||||
<path d="M27.56-112.65 480-894.7l452.44 782.05H27.56Zm456.62-125.48q13.15 0 22.61-9.64 9.47-9.65 9.47-22.8t-9.64-22.33q-9.65-9.19-22.8-9.19t-22.61 9.36q-9.47 9.36-9.47 22.51 0 13.15 9.64 22.62 9.65 9.47 22.8 9.47ZM454-348h60v-219.48h-60V-348Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 364 B |
3
bec_widgets/assets/toolbar_icons/add.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M440.39-440.39H185.87v-79.22h254.52V-774.7h79.22v255.09H774.7v79.22H519.61v254.52h-79.22v-254.52Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 228 B |
3
bec_widgets/assets/toolbar_icons/attach_all.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="m145.26-88.13-57.13-57.13 137.39-137.39H105.87v-79.22h256v256h-79.22v-119.65L145.26-88.13Zm669.48 0L677.91-225.52v119.65h-79.78v-256H854.7v79.22H734.48l137.39 137.39-57.13 57.13Zm-708.87-510v-79.78h119.65L88.13-814.74l57.13-57.13 137.39 137.39V-854.7h79.22v256.57h-256Zm492.26 0V-854.7h79.78v120.22l137.83-138.39 57.13 57.13-138.39 137.83H854.7v79.78H598.13Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 489 B |
3
bec_widgets/assets/toolbar_icons/auto_range.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M114.02-114.02v-308.13h68.13v192.02l547.72-547.72H537.85v-68.37h308.37v308.37h-68.37v-192.02L230.13-182.15h192.02v68.13H114.02Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 258 B |
3
bec_widgets/assets/toolbar_icons/compare.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="m311.5-154.02-47.74-47.74 116.94-116.7H74.02v-68.37H380.7L263.76-503.76l47.74-47.74 198.98 198.74L311.5-154.02Zm337-254.72L449.76-607.48 648.5-806.22l47.74 47.74-116.7 116.94h306.68v68.37H579.54l116.7 116.69-47.74 47.74Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 351 B |
4
bec_widgets/assets/toolbar_icons/connection.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#FFFFFF">
|
||||
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||
<path d="M17 7h-4v2h4c1.65 0 3 1.35 3 3s-1.35 3-3 3h-4v2h4c2.76 0 5-2.24 5-5s-2.24-5-5-5zm-6 8H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-2zm-3-4h8v2H8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 341 B |
3
bec_widgets/assets/toolbar_icons/device_line_edit.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M180-404.87v-50.26h289.75v50.26H180Zm0-162.57v-50.25h454.62v50.25H180Zm0-162.3V-780h454.62v50.26H180ZM524.62-180v-105.69l217.15-216.16q7.46-7.07 16.11-10.3 8.65-3.23 17.3-3.23 9.43 0 18.25 3.53 8.82 3.54 16.03 10.62l37 37.38q6.87 7.47 10.21 16.16Q860-439 860-430.31t-3.37 17.69q-3.37 9-10.52 16.46L630.31-180H524.62Zm250.69-211.69 37-38.62-37-37.38-38 38 38 38Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 492 B |
3
bec_widgets/assets/toolbar_icons/drag_pan_mode.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M480-54 303.43-230.56 361-288.13l79.39 78.83v-231.09H209.3L283.13-366l-57.57 57.57L54-480l172.56-172.57L284.13-595l-74.83 75.39h231.09v-231.65L366-676.87l-57.57-57.57L480-906l171.57 171.56L594-676.87l-74.39-74.39v231.65h231.65L676.87-594l57.57-57.57L906-480 734.44-308.43 676.87-366l74.39-74.39H519.61v231.09L599-288.13l57.57 57.57L480-54Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 470 B |
9
bec_widgets/assets/toolbar_icons/export.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="48px" viewBox="0 0 24 24" width="48px"
|
||||
fill="#FFFFFF">
|
||||
<g>
|
||||
<rect fill="none" height="24" width="24"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M18,15v3H6v-3H4v3c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-3H18z M7,9l1.41,1.41L11,7.83V16h2V7.83l2.59,2.58L17,9l-5-5L7,9z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 371 B |
11
bec_widgets/assets/toolbar_icons/fft.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 100 96" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<rect id="Artboard1" x="0" y="0" width="100" height="96.486" style="fill:none;"/>
|
||||
<g id="Artboard11" serif:id="Artboard1">
|
||||
<path d="M11.379,24.832C11.379,24.261 11.843,23.798 12.414,23.798C18.11,23.798 20.117,19.072 22.06,14.503C23.704,10.634 25.403,6.634 29.483,6.634C33.902,6.634 35.376,12.91 36.934,19.555C38.473,26.113 40.065,32.893 44.138,32.893C48.25,32.893 50.78,28.962 53.457,24.8C56.279,20.412 59.198,15.876 64.31,15.876C69.322,15.876 72.165,20.305 74.915,24.588C77.707,28.935 80.343,33.04 84.999,33.04C85.571,33.04 86.034,33.503 86.034,34.075C86.034,34.647 85.571,35.11 84.999,35.11C79.212,35.11 76.004,30.115 73.175,25.708C70.612,21.716 68.192,17.946 64.31,17.946C60.328,17.946 57.835,21.819 55.197,25.92C52.338,30.366 49.381,34.963 44.138,34.963C38.425,34.963 36.643,27.371 34.92,20.028C33.613,14.46 32.262,8.703 29.482,8.703C26.953,8.703 25.71,11.2 23.963,15.311C21.964,20.014 19.479,25.867 12.413,25.867C11.843,25.867 11.379,25.403 11.379,24.832M44.361,44.584C43.504,44.584 42.557,44.882 42.557,45.739L42.586,50.703L39.522,50.703L43.922,61.878L48.807,50.703L45.691,50.703L45.604,46.255C45.602,45.398 45.218,44.584 44.361,44.584ZM6.034,37.487L6.034,6.674L5,6.674L5,38.522L95,38.522L95,37.487L6.034,37.487M77.414,91.881L77.414,63.849C77.414,63.277 76.951,62.814 76.379,62.814C75.808,62.814 75.345,63.277 75.345,63.849L75.345,91.881C75.345,92.045 75.391,92.194 75.458,92.332L61.955,92.332C62.022,92.194 62.068,92.045 62.068,91.881L62.068,82.718C62.068,82.146 61.605,81.683 61.034,81.683C60.462,81.683 59.999,82.146 59.999,82.718L59.999,91.881C59.999,92.045 60.045,92.194 60.112,92.332L45.059,92.332C45.126,92.194 45.172,92.045 45.172,91.881L45.172,75.943C45.172,75.372 44.709,74.909 44.138,74.909C43.567,74.909 43.104,75.372 43.104,75.943L43.104,91.881C43.104,92.045 43.15,92.194 43.217,92.332L23.852,92.332C23.92,92.194 23.966,92.045 23.966,91.881L23.966,63.849C23.966,63.277 23.502,62.814 22.931,62.814C22.36,62.814 21.897,63.277 21.897,63.849L21.897,91.881C21.897,92.045 21.943,92.194 22.011,92.332L6.034,92.332L6.034,62.881L5,62.881L5,93.366L95,93.366L95,92.332L77.301,92.332C77.368,92.194 77.414,92.045 77.414,91.881"
|
||||
style="fill:white;fill-rule:nonzero;stroke:white;stroke-width:5px;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
3
bec_widgets/assets/toolbar_icons/fitting_parameters.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="m78.89-112.59 263.02-367.17h202l303.5-354.22v721.39H78.89Zm62.24-262.74-54.7-39.78 166.59-233.02h201L640.46-864.8l51.45 44.26-205.82 240.78H287.33l-146.2 204.43Zm70.54 194.37h567.37v-468.78L574.98-411.63H376.22L211.67-180.96Zm567.37 0Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 366 B |
4
bec_widgets/assets/toolbar_icons/history.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#FFFFFF">
|
||||
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||
<path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.25 2.52.77-1.28-3.52-2.09V8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 392 B |
3
bec_widgets/assets/toolbar_icons/image.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M185.09-105.87q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87v-589.82q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h589.82q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v589.82q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H185.09Zm43.56-166.04h503.7L578-481.48l-132 171-93-127-124.35 165.57Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 413 B |
3
bec_widgets/assets/toolbar_icons/image_autorange.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M283.85-289.91h67.41l42.32-112.66h172.59l43.33 112.66h68.85l-164-428h-67.5l-163 428Zm127.74-165.72 67.34-182.87H481l68.41 182.87H411.59Zm68.53 381.61q-86.32 0-160.51-31t-128.89-85.7q-54.7-54.7-85.7-128.89-31-74.19-31-160.51 0-85.31 30.94-159.4t85.7-128.9q54.76-54.8 128.95-86.3t160.51-31.5q85.31 0 159.42 31.47 74.1 31.47 128.91 86.27 54.82 54.8 86.29 128.88 31.48 74.08 31.48 159.6 0 86.2-31.5 160.39-31.5 74.19-86.3 128.95-54.81 54.76-128.9 85.7-74.09 30.94-159.4 30.94ZM480-480Zm-.04 337.85q144.08 0 240.99-96.74 96.9-96.74 96.9-241.07 0-144.32-96.86-241.11-96.86-96.78-240.95-96.78-144.08 0-240.99 96.74-96.9 96.74-96.9 241.07 0 144.32 96.86 241.11 96.86 96.78 240.95 96.78Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 809 B |
9
bec_widgets/assets/toolbar_icons/import.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="48px" viewBox="0 0 24 24" width="48px"
|
||||
fill="#FFFFFF">
|
||||
<g>
|
||||
<rect fill="none" height="24" width="24"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M18,15v3H6v-3H4v3c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-3H18z M17,11l-1.41-1.41L13,12.17V4h-2v8.17L8.41,9.59L7,11l5,5 L17,11z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 377 B |
3
bec_widgets/assets/toolbar_icons/line_axis.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M110.39-110.39v-89.57l77.52-77.52v167.09h-77.52Zm165.57 0v-250.13l77.52-77.52v327.65h-77.52Zm165.56 0v-327.65l77.52 77.95v249.7h-77.52Zm165.57 0v-250.83l77.52-76.96v327.79h-77.52Zm165.56 0v-411.83l76.96-76.96v488.79h-76.96ZM110.39-335.65v-112.7L400-735.96l160 160 289.61-290.61v112.14L560-463.26l-160-160-289.61 287.61Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 450 B |
3
bec_widgets/assets/toolbar_icons/line_curve.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M725.93-155.93q0-118.18-45-222.09t-122-180.91q-77-77-180.91-122t-222.09-45v-68.14q132.68 0 248.61 50.23 115.92 50.23 202.5 136.75 86.57 86.53 136.8 202.53 50.23 116.01 50.23 248.63h-68.14Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 319 B |
3
bec_widgets/assets/toolbar_icons/lock_aspect_ratio.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M571.91-279.09h191v-194h-60v134h-131v60ZM198.09-486.91h60v-134h131v-60h-191v194Zm-53 341.04q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87v-509.82q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h669.82q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v509.82q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H145.09Zm0-79.22h669.82v-509.82H145.09v509.82Zm0 0v-509.82 509.82Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 487 B |
BIN
bec_widgets/assets/toolbar_icons/log_scale.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
3
bec_widgets/assets/toolbar_icons/motor_map.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M443.78-28.43v-75Q305.65-118 211.54-212.11q-94.11-94.11-108.11-231.67h-75v-72.44h75Q118-654.35 212.11-748.46q94.11-94.11 231.67-108.11v-75h72.44v75q137.56 14 231.67 108.11Q842-654.35 856.57-516.22h75v72.44h-75q-14 137.56-108.11 231.67Q654.35-118 516.22-103.43v75h-72.44Zm36.12-152.66q123.4 0 211.21-87.7 87.8-87.71 87.8-211.11 0-123.4-87.7-211.21-87.71-87.8-211.11-87.8-123.4 0-211.21 87.7-87.8 87.71-87.8 211.11 0 123.4 87.7 211.21 87.71 87.8 211.11 87.8ZM480-330q-63 0-106.5-43.5T330-480q0-63 43.5-106.5T480-630q63 0 106.5 43.5T630-480q0 63-43.5 106.5T480-330Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 693 B |
3
bec_widgets/assets/toolbar_icons/photo_library.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M354.61-386.61h391l-127-171-103 135-68-87-93 123ZM274.7-195.48q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87v-549.82q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h549.82q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v549.82q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H274.7Zm0-79.22h549.82v-549.82H274.7v549.82ZM135.48-55.69q-32.74 0-56.26-23.53-23.53-23.52-23.53-56.26v-629.04h79.79v629.04h629.04v79.79H135.48ZM274.7-824.52v549.82-549.82Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 564 B |
3
bec_widgets/assets/toolbar_icons/positioner_box.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M403.39-158.74 82.13-480l321.26-321.26v642.52Zm153.22 0v-642.52L878.44-480 556.61-158.74Zm81.57-195.74L763.13-480 638.18-605.52v251.04Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 266 B |
3
bec_widgets/assets/toolbar_icons/progress.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M480-65.87q-87.51 0-162.97-31.89-75.47-31.89-131.43-87.84-55.95-55.96-87.84-131.43Q65.87-392.49 65.87-480q0-87.47 31.88-162.87 31.89-75.39 87.75-131.51 55.87-56.11 131.41-88.21Q392.44-894.7 480-894.7q15.96 0 27.78 12.16 11.83 12.16 11.83 28.07 0 15.9-11.83 27.73-11.82 11.83-27.78 11.83-139.31 0-237.11 97.8-97.8 97.8-97.8 237.1 0 139.31 97.8 237.12 97.8 97.8 237.1 97.8 139.31 0 237.12-97.8 97.8-97.8 97.8-237.11 0-15.96 11.83-27.78 11.83-11.83 27.73-11.83 15.91 0 28.07 11.83Q894.7-495.96 894.7-480q0 87.56-32.14 163.1-32.14 75.54-88.11 131.44-55.97 55.9-131.44 87.74Q567.55-65.87 480-65.87Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 724 B |
3
bec_widgets/assets/toolbar_icons/queue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M854.7-105.87H105.87v-209.61H854.7v209.61Zm0-269.61H105.87v-209.04H854.7v209.04Zm0-269.04H105.87V-854.7H854.7v210.18Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 248 B |
3
bec_widgets/assets/toolbar_icons/rectangle_mode.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M444.19-421.3q39.72 0 67.4-27.78 27.67-27.78 27.67-66.91 0-39.14-27.71-66.57Q483.83-610 444.4-610q-39.44 0-66.92 27.28Q350-555.44 350-516.3q0 39.13 27.36 67.06 27.35 27.94 66.83 27.94ZM634.52-274 532.78-375.74q-22.56 12.31-44.41 19.02-21.84 6.72-43.28 6.72-69.57 0-117.7-48.62-48.13-48.62-48.13-117.88 0-67.98 48.29-116.39t117.08-48.41q68.79 0 117.08 48.41Q610-584.48 610-515.75q0 21.72-6.93 44.13-6.94 22.4-20.37 44.97l102.73 102.74L634.52-274ZM185.09-105.87q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87V-352h79.22v166.91H352v79.22H185.09Zm422.91 0v-79.22h166.91V-352h79.79v166.91q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H608ZM105.87-608v-166.91q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53H352v79.79H185.09V-608h-79.22Zm669.04 0v-166.91H608v-79.79h166.91q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26V-608h-79.79Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 946 B |
5
bec_widgets/assets/toolbar_icons/remove.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="48px" viewBox="0 0 24 24" width="48px"
|
||||
fill="#8B1A10">
|
||||
<rect fill="none" height="24" width="24"/>
|
||||
<path d="M19,19H5V5h14V19z M3,3v18h18V3H3z M17,15.59L15.59,17L12,13.41L8.41,17L7,15.59L10.59,12L7,8.41L8.41,7L12,10.59L15.59,7 L17,8.41L13.41,12L17,15.59z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 357 B |
3
bec_widgets/assets/toolbar_icons/reset_settings.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M473.54-344.48v-63.59h187.18v63.59H473.54Zm81.92 230.46v-56.15h-81.92v-63.59h81.92v-56.39h63.58v176.13h-63.58Zm103.58-56.15v-63.59h187.18v63.59H659.04Zm41.68-116.92v-177.13h63.58v56.15h81.92v63.59H764.3v57.39h-63.58ZM841.22-540h-68.46q-22.98-101.89-103.94-170.83-80.95-68.93-188.89-68.93-125.29 0-212.37 87.18T180.48-480q0 78.61 36.59 143.32 36.58 64.7 96.95 104.46v-108.26h66.46v226.46H154.02v-66.46h117.41q-71.56-48.72-114.48-127.36-42.93-78.64-42.93-172.16 0-76.22 28.86-142.78 28.86-66.57 78.29-116.04 49.42-49.47 116.01-78.43 66.58-28.97 142.82-28.97 136.52 0 237.87 87.8Q819.22-670.63 841.22-540Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 733 B |
3
bec_widgets/assets/toolbar_icons/restore_state.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M336.04-487.39 145.09-678.35v156.65H65.87v-293H358.3v79.79H201.22l191.39 190.95-56.57 56.57ZM145.09-145.87q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87V-451.7h79.22v226.61H493v79.22H145.09Zm669.82-278.3v-310.74H428.3v-79.79h386.61q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v310.74h-79.79Zm79.79 60v218.87H553v-218.87h341.7Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 455 B |
3
bec_widgets/assets/toolbar_icons/ring_progress.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M479.87-54q-87.96 0-165.74-33.42-77.79-33.43-135.53-91.18-57.75-57.74-91.18-135.66Q54-392.17 54-480.13q0-87.96 33.42-165.74 33.43-77.79 91.18-135.53 57.74-57.75 135.62-91.18Q392.09-906 480-906h36.22v340.7q24.82 10.69 40.8 33.52Q573-508.96 573-480.17q0 38.43-27.38 65.8Q518.24-387 479.79-387q-38.44 0-65.62-27.37Q387-441.74 387-480.17q0-28.79 15.98-51.61 15.98-22.83 40.8-33.52v-97.22Q378.22-650.39 336-599.76q-42.22 50.63-42.22 119.5 0 78.19 54.12 132.33 54.12 54.15 132.02 54.15 77.91 0 132.1-54.09 54.2-54.1 54.2-131.79 0-42.47-16.28-77.88-16.29-35.42-45.42-60.98l52.05-52.05q38.18 35.64 60.7 84.75 22.51 49.11 22.51 105.82 0 108.57-75.58 183.9-75.59 75.32-184.13 75.32-108.55 0-183.92-75.32-75.37-75.33-75.37-183.89 0-99.62 63.68-172.01 63.67-72.39 159.32-85.65v-93.22Q309.39-817.61 218.2-717.8 127-617.98 127-480.14q0 147.23 103.1 250.18Q333.19-127 480.14-127t249.9-103.02Q833-333.04 833-479.81q0-76.45-29.58-141.91-29.57-65.46-80.81-114.89l51.48-51.48q61.05 58.34 96.48 137.6Q906-571.23 906-479.73q0 87.82-33.42 165.6-33.43 77.79-91.18 135.53-57.74 57.75-135.66 91.18Q567.83-54 479.87-54Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
3
bec_widgets/assets/toolbar_icons/rotate_left.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M435-72.11q-49.67-7-95.99-25.36-46.31-18.36-86.55-49.55l49.21-49.74q31.76 24 65.29 37.26 33.52 13.26 68.04 19.02v68.37Zm90 0v-68.37q109.28-21.24 181.07-102.9 71.78-81.66 71.78-197.71 0-124.37-84.11-210.87t-208.72-86.5h-18.8L540.67-664l-49.74 49.74L332.2-773l158.73-158.74 49.74 49.26-75.41 75.65h19.28q75.48 0 141.34 28.72t114.98 78.56q49.12 49.83 77.24 116.29 28.12 66.46 28.12 142.17 0 142.39-90.8 245.07Q664.63-93.35 525-72.11ZM189.46-209.78q-28.96-38.72-47.82-86.3-18.86-47.57-25.62-100.01h68.89q5 37.76 18.38 72.17 13.38 34.4 36.14 64.16l-49.97 49.98Zm-73.44-276.31q6.52-50.71 25-97.29 18.48-46.58 48.44-87.77l50.21 48.26q-22.76 33-36.14 67.52-13.38 34.52-18.62 69.28h-68.89Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 811 B |
3
bec_widgets/assets/toolbar_icons/rotate_right.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M527-72.11v-68.37q34.52-5.76 68.04-19.02 33.53-13.26 65.29-37.26l49.21 49.74q-40.24 31.19-86.55 49.55Q576.67-79.11 527-72.11Zm-90 0Q297.37-93.35 206.7-196.02q-90.68-102.68-90.68-245.07 0-75.71 28-142.17t77.12-116.29q49.12-49.84 114.98-78.56 65.86-28.72 141.34-28.72h19.28l-75.41-75.65 49.74-49.26L629.8-773 471.07-614.26 421.33-664l74.69-74.46h-19.04q-124.61 0-208.72 86.5t-84.11 210.87q0 116.05 71.78 197.71 71.79 81.66 181.07 102.9v68.37Zm335.54-137.67-49.97-49.98q22.76-29.76 36.14-64.16 13.38-34.41 18.38-72.17h69.13q-7 52.44-25.86 100.01-18.86 47.58-47.82 86.3Zm73.68-276.31h-69.13q-5.24-34.76-18.62-69.28t-36.14-67.52l50.21-48.26q29.96 41.19 48.44 87.77 18.48 46.58 25.24 97.29Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 815 B |
3
bec_widgets/assets/toolbar_icons/save.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M854.7-689.22v504.13q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H185.09q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87v-589.82q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h504.13L854.7-689.22Zm-79.79 35.48L653.74-774.91H185.09v589.82h589.82v-468.65ZM479.76-250.09q43.24 0 73.74-30.26 30.5-30.27 30.5-73.5 0-43.24-30.26-73.74-30.27-30.5-73.5-30.5-43.24 0-73.74 30.27-30.5 30.26-30.5 73.5 0 43.23 30.26 73.73 30.27 30.5 73.5 30.5ZM238.09-578.91h358v-143h-358v143Zm-53-74.83v468.65-589.82 121.17Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 621 B |
3
bec_widgets/assets/toolbar_icons/save_state.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M185.87-98.52v-681.39q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h429.82q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v681.39L480-224.17 185.87-98.52Zm79.22-120.39L480-309.18l214.91 90.27v-561H265.09v561Zm0-561h429.82-429.82Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 354 B |
3
bec_widgets/assets/toolbar_icons/scan_control.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M185.09-105.87q-32.93 0-56.08-23.14-23.14-23.15-23.14-56.08v-589.82q0-33.16 23.14-56.47 23.15-23.32 56.08-23.32h589.82q33.16 0 56.47 23.32 23.32 23.31 23.32 56.47v589.82q0 32.93-23.32 56.08-23.31 23.14-56.47 23.14H185.09Zm439.21-79.22h71l79.61-79.61v-40.39H744.3l-120 120ZM281-389.48l141-140 90 90L725.52-654 679-700.52l-167 167-90-90L234.48-436 281-389.48Zm-95.91 204.39h34.56l120-120h-71l-83.56 83.57v36.43Zm350.91 0 120-120h-71l-120 120h71Zm-159.87 0 120-120h-71l-120 120h71Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 609 B |
4
bec_widgets/assets/toolbar_icons/settings.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#FFFFFF">
|
||||
<path d="M0 0h24v24H0V0z" fill="none"/>
|
||||
<path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
3
bec_widgets/assets/toolbar_icons/status.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M286.83-277h60v-205h-60v205Zm326.91 0h60v-420h-60v420ZM450-277h60v-118h-60v118Zm0-205h60v-60h-60v60ZM185.09-105.87q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87v-589.82q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h589.82q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v589.82q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H185.09Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 452 B |
3
bec_widgets/assets/toolbar_icons/terminal.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M145.09-145.87q-32.51 0-55.87-23.35-23.35-23.36-23.35-55.87v-509.82q0-32.74 23.35-56.26 23.36-23.53 55.87-23.53h669.82q32.74 0 56.26 23.53 23.53 23.52 23.53 56.26v509.82q0 32.51-23.53 55.87-23.52 23.35-56.26 23.35H145.09Zm0-79.22h669.82v-425.82H145.09v425.82ZM300-292l-42-42 103-104-104-104 43-42 146 146-146 146Zm190 4v-60h220v60H490Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 466 B |
3
bec_widgets/assets/toolbar_icons/transform.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M636.17-32.59 480.35-188.41l45.82-46.07 77.13 77.37v-137.32H356.93q-28.1 0-46.8-18.55-18.7-18.54-18.7-46.95V-600.3H74.02v-65.27h217.41v-137.32l-77.36 77.37-45.59-45.83 155.59-155.82 156.06 155.82-46.06 45.83-77.14-77.37v442.96h529.29v65.5H669.04v137.32l77.13-77.37L792-188.41 636.17-32.59ZM603.3-419.93V-600.3H416.93v-65.27H603.3q28.37 0 47.06 18.56 18.68 18.55 18.68 46.71v180.37H603.3Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 518 B |
3
bec_widgets/assets/toolbar_icons/waveform.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#FFFFFF">
|
||||
<path d="M126-206.43 66.43-266 380-579.57 539.43-419.7l298-335 56.14 54.57-352.44 399.26L380-460.43l-254 254Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 231 B |
@@ -1,8 +1 @@
|
||||
from bec_lib.utils.import_utils import lazy_import_from
|
||||
|
||||
# from .auto_updates import AutoUpdates, ScanInfo
|
||||
# TODO: put back when Pydantic gets faster
|
||||
AutoUpdates, ScanInfo = lazy_import_from(
|
||||
"bec_widgets.cli.auto_updates", ("AutoUpdates", "ScanInfo")
|
||||
)
|
||||
from .client import BECDockArea, BECFigure
|
||||
from .client import *
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
|
||||
from pydantic import BaseModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .client import BECFigure
|
||||
from .client import BECDockArea, BECFigure
|
||||
|
||||
|
||||
class ScanInfo(BaseModel):
|
||||
@@ -15,12 +15,24 @@ class ScanInfo(BaseModel):
|
||||
scan_report_devices: list
|
||||
monitored_devices: list
|
||||
status: str
|
||||
model_config: dict = {"validate_assignment": True}
|
||||
|
||||
|
||||
class AutoUpdates:
|
||||
def __init__(self, figure: BECFigure, enabled: bool = True):
|
||||
self.enabled = enabled
|
||||
self.figure = figure
|
||||
create_default_dock: bool = False
|
||||
enabled: bool = False
|
||||
dock_name: str = None
|
||||
|
||||
def __init__(self, gui: BECDockArea):
|
||||
self.gui = gui
|
||||
|
||||
def start_default_dock(self):
|
||||
"""
|
||||
Create a default dock for the auto updates.
|
||||
"""
|
||||
dock = self.gui.add_dock("default_figure")
|
||||
dock.add_widget("BECFigure")
|
||||
self.dock_name = "default_figure"
|
||||
|
||||
@staticmethod
|
||||
def get_scan_info(msg) -> ScanInfo:
|
||||
@@ -44,6 +56,18 @@ class AutoUpdates:
|
||||
status=status,
|
||||
)
|
||||
|
||||
def get_default_figure(self) -> BECFigure | None:
|
||||
"""
|
||||
Get the default figure from the GUI.
|
||||
"""
|
||||
dock = self.gui.panels.get(self.dock_name, [])
|
||||
if not dock:
|
||||
return None
|
||||
widgets = dock.widget_list
|
||||
if not widgets:
|
||||
return None
|
||||
return widgets[0]
|
||||
|
||||
def run(self, msg):
|
||||
"""
|
||||
Run the update function if enabled.
|
||||
@@ -86,33 +110,44 @@ class AutoUpdates:
|
||||
"""
|
||||
Simple line scan.
|
||||
"""
|
||||
fig = self.get_default_figure()
|
||||
if not fig:
|
||||
return
|
||||
dev_x = info.scan_report_devices[0]
|
||||
dev_y = self.get_selected_device(info.monitored_devices, self.figure.selected_device)
|
||||
dev_y = self.get_selected_device(info.monitored_devices, self.gui.selected_device)
|
||||
if not dev_y:
|
||||
return
|
||||
self.figure.clear_all()
|
||||
plt = self.figure.plot(dev_x, dev_y)
|
||||
fig.clear_all()
|
||||
plt = fig.plot(x_name=dev_x, y_name=dev_y, label=f"Scan {info.scan_number} - {dev_y}")
|
||||
plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
|
||||
|
||||
def simple_grid_scan(self, info: ScanInfo) -> None:
|
||||
"""
|
||||
Simple grid scan.
|
||||
"""
|
||||
fig = self.get_default_figure()
|
||||
if not fig:
|
||||
return
|
||||
dev_x = info.scan_report_devices[0]
|
||||
dev_y = info.scan_report_devices[1]
|
||||
dev_z = self.get_selected_device(info.monitored_devices, self.figure.selected_device)
|
||||
self.figure.clear_all()
|
||||
plt = self.figure.plot(dev_x, dev_y, dev_z, label=f"Scan {info.scan_number}")
|
||||
dev_z = self.get_selected_device(info.monitored_devices, self.gui.selected_device)
|
||||
fig.clear_all()
|
||||
plt = fig.plot(
|
||||
x_name=dev_x, y_name=dev_y, z_name=dev_z, label=f"Scan {info.scan_number} - {dev_z}"
|
||||
)
|
||||
plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
|
||||
|
||||
def best_effort(self, info: ScanInfo) -> None:
|
||||
"""
|
||||
Best effort scan.
|
||||
"""
|
||||
fig = self.get_default_figure()
|
||||
if not fig:
|
||||
return
|
||||
dev_x = info.scan_report_devices[0]
|
||||
dev_y = self.get_selected_device(info.monitored_devices, self.figure.selected_device)
|
||||
dev_y = self.get_selected_device(info.monitored_devices, self.gui.selected_device)
|
||||
if not dev_y:
|
||||
return
|
||||
self.figure.clear_all()
|
||||
plt = self.figure.plot(dev_x, dev_y, label=f"Scan {info.scan_number}")
|
||||
fig.clear_all()
|
||||
plt = fig.plot(x_name=dev_x, y_name=dev_y, label=f"Scan {info.scan_number} - {dev_y}")
|
||||
plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import importlib.metadata as imd
|
||||
import json
|
||||
import os
|
||||
import select
|
||||
import subprocess
|
||||
@@ -13,19 +14,27 @@ from functools import wraps
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.utils.import_utils import isinstance_based_on_class_name, lazy_import, lazy_import_from
|
||||
from qtpy.QtCore import QCoreApplication
|
||||
from qtpy.QtCore import QEventLoop, QSocketNotifier, QTimer
|
||||
|
||||
import bec_widgets.cli.client as client
|
||||
from bec_widgets.cli.auto_updates import AutoUpdates
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bec_lib.device import DeviceBase
|
||||
|
||||
from bec_widgets.cli.client import BECDockArea, BECFigure
|
||||
|
||||
from bec_lib.serialization import MsgpackSerialization
|
||||
|
||||
messages = lazy_import("bec_lib.messages")
|
||||
# from bec_lib.connector import MessageObject
|
||||
MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
|
||||
BECDispatcher = lazy_import_from("bec_widgets.utils.bec_dispatcher", ("BECDispatcher",))
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
def rpc_call(func):
|
||||
"""
|
||||
@@ -58,20 +67,90 @@ def rpc_call(func):
|
||||
return wrapper
|
||||
|
||||
|
||||
def _get_output(process, logger) -> None:
|
||||
log_func = {process.stdout: logger.debug, process.stderr: logger.error}
|
||||
stream_buffer = {process.stdout: [], process.stderr: []}
|
||||
try:
|
||||
os.set_blocking(process.stdout.fileno(), False)
|
||||
os.set_blocking(process.stderr.fileno(), False)
|
||||
while process.poll() is None:
|
||||
readylist, _, _ = select.select([process.stdout, process.stderr], [], [], 1)
|
||||
for stream in (process.stdout, process.stderr):
|
||||
buf = stream_buffer[stream]
|
||||
if stream in readylist:
|
||||
buf.append(stream.read(4096))
|
||||
output, _, remaining = "".join(buf).rpartition("\n")
|
||||
if output:
|
||||
log_func[stream](output)
|
||||
buf.clear()
|
||||
buf.append(remaining)
|
||||
except Exception as e:
|
||||
print(f"Error reading process output: {str(e)}")
|
||||
|
||||
|
||||
def _start_plot_process(gui_id: str, gui_class: type, config: dict | str, logger=None) -> None:
|
||||
"""
|
||||
Start the plot in a new process.
|
||||
|
||||
Logger must be a logger object with "debug" and "error" functions,
|
||||
or it can be left to "None" as default. None means output from the
|
||||
process will not be captured.
|
||||
"""
|
||||
# pylint: disable=subprocess-run-check
|
||||
command = ["bec-gui-server", "--id", gui_id, "--gui_class", gui_class.__name__]
|
||||
if config:
|
||||
if isinstance(config, dict):
|
||||
config = json.dumps(config)
|
||||
command.extend(["--config", config])
|
||||
|
||||
env_dict = os.environ.copy()
|
||||
env_dict["PYTHONUNBUFFERED"] = "1"
|
||||
if logger is None:
|
||||
stdout_redirect = subprocess.DEVNULL
|
||||
stderr_redirect = subprocess.DEVNULL
|
||||
else:
|
||||
stdout_redirect = subprocess.PIPE
|
||||
stderr_redirect = subprocess.PIPE
|
||||
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
text=True,
|
||||
start_new_session=True,
|
||||
stdout=stdout_redirect,
|
||||
stderr=stderr_redirect,
|
||||
env=env_dict,
|
||||
)
|
||||
if logger is None:
|
||||
process_output_processing_thread = None
|
||||
else:
|
||||
process_output_processing_thread = threading.Thread(
|
||||
target=_get_output, args=(process, logger)
|
||||
)
|
||||
process_output_processing_thread.start()
|
||||
return process, process_output_processing_thread
|
||||
|
||||
|
||||
class BECGuiClientMixin:
|
||||
def __init__(self, **kwargs) -> None:
|
||||
super().__init__(**kwargs)
|
||||
self._process = None
|
||||
self.update_script = self._get_update_script()
|
||||
self._process_output_processing_thread = None
|
||||
self.auto_updates = self._get_update_script()
|
||||
self._target_endpoint = MessageEndpoints.scan_status()
|
||||
self._selected_device = None
|
||||
self.stderr_output = []
|
||||
|
||||
def _get_update_script(self) -> AutoUpdates:
|
||||
def _get_update_script(self) -> AutoUpdates | None:
|
||||
eps = imd.entry_points(group="bec.widgets.auto_updates")
|
||||
for ep in eps:
|
||||
if ep.name == "plugin_widgets_update":
|
||||
return ep.load()(figure=self)
|
||||
try:
|
||||
spec = importlib.util.find_spec(ep.module)
|
||||
# if the module is not found, we skip it
|
||||
if spec is None:
|
||||
continue
|
||||
return ep.load()(gui=self)
|
||||
except Exception as e:
|
||||
print(f"Error loading auto update script from plugin: {str(e)}")
|
||||
return None
|
||||
|
||||
@property
|
||||
@@ -97,7 +176,7 @@ class BECGuiClientMixin:
|
||||
|
||||
@staticmethod
|
||||
def _handle_msg_update(msg: MessageObject, parent: BECGuiClientMixin) -> None:
|
||||
if parent.update_script is not None:
|
||||
if parent.auto_updates is not None:
|
||||
# pylint: disable=protected-access
|
||||
parent._update_script_msg_parser(msg.value)
|
||||
|
||||
@@ -105,90 +184,35 @@ class BECGuiClientMixin:
|
||||
if isinstance(msg, messages.ScanStatusMessage):
|
||||
if not self.gui_is_alive():
|
||||
return
|
||||
self.update_script.run(msg)
|
||||
self.auto_updates.run(msg)
|
||||
|
||||
def show(self) -> None:
|
||||
"""
|
||||
Show the figure.
|
||||
"""
|
||||
if self._process is None or self._process.poll() is not None:
|
||||
self._start_plot_process()
|
||||
self._start_update_script()
|
||||
self._process, self._process_output_processing_thread = _start_plot_process(
|
||||
self._gui_id, self.__class__, self._client._service_config.config
|
||||
)
|
||||
while not self.gui_is_alive():
|
||||
print("Waiting for GUI to start...")
|
||||
time.sleep(1)
|
||||
|
||||
def close(self) -> None:
|
||||
"""
|
||||
Close the figure.
|
||||
Close the gui window.
|
||||
"""
|
||||
if self._process is None:
|
||||
return
|
||||
if self.gui_is_alive():
|
||||
self._run_rpc("close", (), wait_for_rpc_response=True)
|
||||
else:
|
||||
self._run_rpc("close", (), wait_for_rpc_response=False)
|
||||
self._process.terminate()
|
||||
self._process_output_processing_thread.join()
|
||||
self._process = None
|
||||
|
||||
self._client.shutdown()
|
||||
|
||||
def _start_plot_process(self) -> None:
|
||||
"""
|
||||
Start the plot in a new process.
|
||||
"""
|
||||
self._start_update_script()
|
||||
# pylint: disable=subprocess-run-check
|
||||
config = self._client._service_config.redis
|
||||
monitor_module = importlib.import_module("bec_widgets.cli.server")
|
||||
monitor_path = monitor_module.__file__
|
||||
gui_class = self.__class__.__name__
|
||||
|
||||
command = [
|
||||
sys.executable,
|
||||
"-u",
|
||||
monitor_path,
|
||||
"--id",
|
||||
self._gui_id,
|
||||
"--config",
|
||||
config,
|
||||
"--gui_class",
|
||||
gui_class,
|
||||
]
|
||||
self._process = subprocess.Popen(
|
||||
command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
self._process_output_processing_thread = threading.Thread(target=self._get_output)
|
||||
self._process_output_processing_thread.start()
|
||||
|
||||
def print_log(self) -> None:
|
||||
"""
|
||||
Print the log of the plot process.
|
||||
"""
|
||||
if self._process is None:
|
||||
return
|
||||
print("".join(self.stderr_output))
|
||||
# Flush list
|
||||
self.stderr_output.clear()
|
||||
|
||||
def _get_output(self) -> str:
|
||||
try:
|
||||
os.set_blocking(self._process.stdout.fileno(), False)
|
||||
os.set_blocking(self._process.stderr.fileno(), False)
|
||||
while self._process.poll() is None:
|
||||
readylist, _, _ = select.select(
|
||||
[self._process.stdout, self._process.stderr], [], [], 1
|
||||
)
|
||||
if self._process.stdout in readylist:
|
||||
output = self._process.stdout.read(1024)
|
||||
if output:
|
||||
print(output, end="")
|
||||
if self._process.stderr in readylist:
|
||||
error_output = self._process.stderr.read(1024)
|
||||
if error_output:
|
||||
print(error_output, end="", file=sys.stderr)
|
||||
self.stderr_output.append(error_output)
|
||||
except Exception as e:
|
||||
print(f"Error reading process output: {str(e)}")
|
||||
if self._process:
|
||||
self._process.terminate()
|
||||
if self._process_output_processing_thread:
|
||||
self._process_output_processing_thread.join()
|
||||
self._process.wait()
|
||||
self._process = None
|
||||
|
||||
|
||||
class RPCResponseTimeoutError(Exception):
|
||||
@@ -200,6 +224,48 @@ class RPCResponseTimeoutError(Exception):
|
||||
)
|
||||
|
||||
|
||||
class QtRedisMessageWaiter:
|
||||
def __init__(self, redis_connector, message_to_wait):
|
||||
self.ev_loop = QEventLoop()
|
||||
self.response = None
|
||||
self.connector = redis_connector
|
||||
self.message_to_wait = message_to_wait
|
||||
self.pubsub = redis_connector._redis_conn.pubsub()
|
||||
self.pubsub.subscribe(self.message_to_wait.endpoint)
|
||||
fd = self.pubsub.connection._sock.fileno()
|
||||
self.notifier = QSocketNotifier(fd, QSocketNotifier.Read)
|
||||
self.notifier.activated.connect(self._pubsub_readable)
|
||||
|
||||
def _msg_received(self, msg_obj):
|
||||
self.response = msg_obj.value
|
||||
self.ev_loop.quit()
|
||||
|
||||
def wait(self, timeout=1):
|
||||
timer = QTimer()
|
||||
timer.singleShot(timeout * 1000, self.ev_loop.quit)
|
||||
self.ev_loop.exec_()
|
||||
timer.stop()
|
||||
self.notifier.setEnabled(False)
|
||||
self.pubsub.close()
|
||||
return self.response
|
||||
|
||||
def _pubsub_readable(self, fd):
|
||||
while True:
|
||||
msg = self.pubsub.get_message()
|
||||
if msg:
|
||||
if msg["type"] == "subscribe":
|
||||
# get_message buffers, so we may already have the answer
|
||||
# let's check...
|
||||
continue
|
||||
else:
|
||||
break
|
||||
else:
|
||||
return
|
||||
channel = msg["channel"].decode()
|
||||
msg = MessageObject(topic=channel, value=MsgpackSerialization.loads(msg["data"]))
|
||||
self.connector._execute_callback(self._msg_received, msg, {})
|
||||
|
||||
|
||||
class RPCBase:
|
||||
def __init__(self, gui_id: str = None, config: dict = None, parent=None) -> None:
|
||||
self._client = BECDispatcher().client
|
||||
@@ -226,7 +292,7 @@ class RPCBase:
|
||||
parent = parent._parent
|
||||
return parent
|
||||
|
||||
def _run_rpc(self, method, *args, wait_for_rpc_response=True, **kwargs):
|
||||
def _run_rpc(self, method, *args, wait_for_rpc_response=True, timeout=3, **kwargs):
|
||||
"""
|
||||
Run the RPC call.
|
||||
|
||||
@@ -248,16 +314,24 @@ class RPCBase:
|
||||
|
||||
# pylint: disable=protected-access
|
||||
receiver = self._root._gui_id
|
||||
if wait_for_rpc_response:
|
||||
redis_msg = QtRedisMessageWaiter(
|
||||
self._client.connector, MessageEndpoints.gui_instruction_response(request_id)
|
||||
)
|
||||
|
||||
self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
|
||||
|
||||
if not wait_for_rpc_response:
|
||||
return None
|
||||
response = self._wait_for_response(request_id)
|
||||
# get class name
|
||||
if not response.content["accepted"]:
|
||||
raise ValueError(response.content["message"]["error"])
|
||||
msg_result = response.content["message"].get("result")
|
||||
return self._create_widget_from_msg_result(msg_result)
|
||||
if wait_for_rpc_response:
|
||||
response = redis_msg.wait(timeout)
|
||||
|
||||
if response is None:
|
||||
raise RPCResponseTimeoutError(request_id, timeout)
|
||||
|
||||
# get class name
|
||||
if not response.accepted:
|
||||
raise ValueError(response.message["error"])
|
||||
msg_result = response.message.get("result")
|
||||
return self._create_widget_from_msg_result(msg_result)
|
||||
|
||||
def _create_widget_from_msg_result(self, msg_result):
|
||||
if msg_result is None:
|
||||
@@ -280,30 +354,6 @@ class RPCBase:
|
||||
return cls(parent=self, **msg_result)
|
||||
return msg_result
|
||||
|
||||
def _wait_for_response(self, request_id: str, timeout: int = 5):
|
||||
"""
|
||||
Wait for the response from the server.
|
||||
|
||||
Args:
|
||||
request_id(str): The request ID.
|
||||
timeout(int): The timeout in seconds.
|
||||
|
||||
Returns:
|
||||
The response from the server.
|
||||
"""
|
||||
start_time = time.time()
|
||||
response = None
|
||||
|
||||
while response is None and self.gui_is_alive() and (time.time() - start_time) < timeout:
|
||||
response = self._client.connector.get(
|
||||
MessageEndpoints.gui_instruction_response(request_id)
|
||||
)
|
||||
QCoreApplication.processEvents() # keep UI responsive (and execute signals/slots)
|
||||
if response is None and (time.time() - start_time) >= timeout:
|
||||
raise RPCResponseTimeoutError(request_id, timeout)
|
||||
|
||||
return response
|
||||
|
||||
def gui_is_alive(self):
|
||||
"""
|
||||
Check if the GUI is alive.
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
# pylint: disable=missing-module-docstring
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
import black
|
||||
import isort
|
||||
|
||||
from bec_widgets.utils.generate_designer_plugin import DesignerPluginGenerator
|
||||
from bec_widgets.utils.plugin_utils import BECClassContainer, get_rpc_classes
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
from typing import get_overloads
|
||||
@@ -14,30 +20,55 @@ else:
|
||||
"If you want to use the real function 'typing.get_overloads()', please use Python 3.11 or later."
|
||||
)
|
||||
|
||||
def get_overloads(obj):
|
||||
# Dummy function for Python versions before 3.11
|
||||
def get_overloads(_obj):
|
||||
"""
|
||||
Dummy function for Python versions before 3.11.
|
||||
"""
|
||||
return []
|
||||
|
||||
|
||||
class ClientGenerator:
|
||||
def __init__(self):
|
||||
self.header = """# This file was automatically generated by generate_cli.py\n
|
||||
from bec_widgets.cli.client_utils import rpc_call, RPCBase, BECGuiClientMixin
|
||||
from typing import Literal, Optional, overload"""
|
||||
import enum
|
||||
from typing import Literal, Optional, overload
|
||||
|
||||
from bec_widgets.cli.client_utils import RPCBase, rpc_call, BECGuiClientMixin
|
||||
|
||||
# pylint: skip-file"""
|
||||
|
||||
self.content = ""
|
||||
|
||||
def generate_client(self, published_classes: list):
|
||||
def generate_client(self, class_container: BECClassContainer):
|
||||
"""
|
||||
Generate the client for the published classes.
|
||||
|
||||
Args:
|
||||
published_classes(list): The list of published classes (e.g. [BECWaveform1D, BECFigure]).
|
||||
class_container: The class container with the classes to generate the client for.
|
||||
"""
|
||||
for cls in published_classes:
|
||||
rpc_top_level_classes = class_container.rpc_top_level_classes
|
||||
rpc_top_level_classes.sort(key=lambda x: x.__name__)
|
||||
connector_classes = class_container.connector_classes
|
||||
connector_classes.sort(key=lambda x: x.__name__)
|
||||
|
||||
self.write_client_enum(rpc_top_level_classes)
|
||||
for cls in connector_classes:
|
||||
self.content += "\n\n"
|
||||
self.generate_content_for_class(cls)
|
||||
|
||||
def write_client_enum(self, published_classes: list[type]):
|
||||
"""
|
||||
Write the client enum to the content.
|
||||
"""
|
||||
self.content += """
|
||||
class Widgets(str, enum.Enum):
|
||||
\"\"\"
|
||||
Enum for the available widgets.
|
||||
\"\"\"
|
||||
"""
|
||||
for cls in published_classes:
|
||||
self.content += f'{cls.__name__} = "{cls.__name__}"\n '
|
||||
|
||||
def generate_content_for_class(self, cls):
|
||||
"""
|
||||
Generate the content for the class.
|
||||
@@ -47,11 +78,6 @@ from typing import Literal, Optional, overload"""
|
||||
"""
|
||||
|
||||
class_name = cls.__name__
|
||||
module = cls.__module__
|
||||
|
||||
# Generate the header
|
||||
# self.header += f"""
|
||||
# from {module} import {class_name}"""
|
||||
|
||||
# Generate the content
|
||||
if cls.__name__ == "BECDockArea":
|
||||
@@ -60,6 +86,9 @@ class {class_name}(RPCBase, BECGuiClientMixin):"""
|
||||
else:
|
||||
self.content += f"""
|
||||
class {class_name}(RPCBase):"""
|
||||
if not cls.USER_ACCESS:
|
||||
self.content += """...
|
||||
"""
|
||||
for method in cls.USER_ACCESS:
|
||||
obj = getattr(cls, method)
|
||||
if isinstance(obj, property):
|
||||
@@ -101,39 +130,60 @@ class {class_name}(RPCBase):"""
|
||||
except black.NothingChanged:
|
||||
formatted_content = full_content
|
||||
|
||||
isort.Config(
|
||||
profile="black",
|
||||
line_length=100,
|
||||
multi_line_output=3,
|
||||
include_trailing_comma=True,
|
||||
known_first_party=["bec_widgets"],
|
||||
)
|
||||
formatted_content = isort.code(formatted_content)
|
||||
|
||||
with open(file_name, "w", encoding="utf-8") as file:
|
||||
file.write(formatted_content)
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main entry point for the script, controlled by command line arguments.
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser(description="Auto-generate the client for RPC widgets")
|
||||
parser.add_argument("--core", action="store_true", help="Whether to generate the core client")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.core:
|
||||
current_path = os.path.dirname(__file__)
|
||||
client_path = os.path.join(current_path, "client.py")
|
||||
|
||||
rpc_classes = get_rpc_classes("bec_widgets")
|
||||
|
||||
generator = ClientGenerator()
|
||||
generator.generate_client(rpc_classes)
|
||||
generator.write(client_path)
|
||||
|
||||
for cls in rpc_classes.plugins:
|
||||
plugin = DesignerPluginGenerator(cls)
|
||||
if not hasattr(plugin, "info"):
|
||||
continue
|
||||
|
||||
# if the class directory already has a register, plugin and pyproject file, skip
|
||||
if os.path.exists(
|
||||
os.path.join(plugin.info.base_path, f"register_{plugin.info.plugin_name_snake}.py")
|
||||
):
|
||||
continue
|
||||
if os.path.exists(
|
||||
os.path.join(plugin.info.base_path, f"{plugin.info.plugin_name_snake}_plugin.py")
|
||||
):
|
||||
continue
|
||||
if os.path.exists(
|
||||
os.path.join(plugin.info.base_path, f"{plugin.info.plugin_name_snake}.pyproject")
|
||||
):
|
||||
continue
|
||||
plugin.run()
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
import os
|
||||
|
||||
from bec_widgets.utils import BECConnector
|
||||
from bec_widgets.widgets import BECDock, BECDockArea, BECFigure, SpiralProgressBar
|
||||
from bec_widgets.widgets.figure.plots.image.image import BECImageShow
|
||||
from bec_widgets.widgets.figure.plots.image.image_item import BECImageItem
|
||||
from bec_widgets.widgets.figure.plots.motor_map.motor_map import BECMotorMap
|
||||
from bec_widgets.widgets.figure.plots.plot_base import BECPlotBase
|
||||
from bec_widgets.widgets.figure.plots.waveform.waveform import BECWaveform
|
||||
from bec_widgets.widgets.figure.plots.waveform.waveform_curve import BECCurve
|
||||
from bec_widgets.widgets.spiral_progress_bar.ring import Ring
|
||||
|
||||
current_path = os.path.dirname(__file__)
|
||||
client_path = os.path.join(current_path, "client.py")
|
||||
clss = [
|
||||
BECPlotBase,
|
||||
BECWaveform,
|
||||
BECFigure,
|
||||
BECCurve,
|
||||
BECImageShow,
|
||||
BECConnector,
|
||||
BECImageItem,
|
||||
BECMotorMap,
|
||||
BECDock,
|
||||
BECDockArea,
|
||||
SpiralProgressBar,
|
||||
Ring,
|
||||
]
|
||||
generator = ClientGenerator()
|
||||
generator.generate_client(clss)
|
||||
generator.write(client_path)
|
||||
sys.argv = ["generate_cli.py", "--core"]
|
||||
main()
|
||||
|
||||
@@ -1,15 +1,37 @@
|
||||
from bec_widgets.utils import BECConnector
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
||||
|
||||
|
||||
class RPCWidgetHandler:
|
||||
"""Handler class for creating widgets from RPC messages."""
|
||||
|
||||
widget_classes = {"BECFigure": BECFigure, "SpiralProgressBar": SpiralProgressBar}
|
||||
def __init__(self):
|
||||
self._widget_classes = None
|
||||
|
||||
@staticmethod
|
||||
def create_widget(widget_type, **kwargs) -> BECConnector:
|
||||
@property
|
||||
def widget_classes(self):
|
||||
"""
|
||||
Get the available widget classes.
|
||||
|
||||
Returns:
|
||||
dict: The available widget classes.
|
||||
"""
|
||||
if self._widget_classes is None:
|
||||
self.update_available_widgets()
|
||||
return self._widget_classes
|
||||
|
||||
def update_available_widgets(self):
|
||||
"""
|
||||
Update the available widgets.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
from bec_widgets.utils.plugin_utils import get_rpc_classes
|
||||
|
||||
clss = get_rpc_classes("bec_widgets")
|
||||
self._widget_classes = {cls.__name__: cls for cls in clss.top_level_classes}
|
||||
|
||||
def create_widget(self, widget_type, **kwargs) -> BECConnector:
|
||||
"""
|
||||
Create a widget from an RPC message.
|
||||
|
||||
@@ -20,7 +42,12 @@ class RPCWidgetHandler:
|
||||
Returns:
|
||||
widget(BECConnector): The created widget.
|
||||
"""
|
||||
widget_class = RPCWidgetHandler.widget_classes.get(widget_type)
|
||||
if self._widget_classes is None:
|
||||
self.update_available_widgets()
|
||||
widget_class = self._widget_classes.get(widget_type)
|
||||
if widget_class:
|
||||
return widget_class(**kwargs)
|
||||
raise ValueError(f"Unknown widget type: {widget_type}")
|
||||
|
||||
|
||||
widget_handler = RPCWidgetHandler()
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import json
|
||||
import signal
|
||||
import sys
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from typing import Union
|
||||
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.service_config import ServiceConfig
|
||||
from bec_lib.utils.import_utils import lazy_import
|
||||
from qtpy.QtCore import QTimer
|
||||
|
||||
from bec_widgets.cli.rpc_register import RPCRegister
|
||||
from bec_widgets.utils import BECDispatcher
|
||||
from bec_widgets.utils.bec_connector import BECConnector
|
||||
from bec_widgets.utils.bec_dispatcher import QtRedisConnector
|
||||
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
|
||||
messages = lazy_import("bec_lib.messages")
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class BECWidgetsCLIServer:
|
||||
@@ -22,7 +32,7 @@ class BECWidgetsCLIServer:
|
||||
dispatcher: BECDispatcher = None,
|
||||
client=None,
|
||||
config=None,
|
||||
gui_class: Union["BECFigure", "BECDockArea"] = BECFigure,
|
||||
gui_class: Union[BECFigure, BECDockArea] = BECFigure,
|
||||
) -> None:
|
||||
self.dispatcher = BECDispatcher(config=config) if dispatcher is None else dispatcher
|
||||
self.client = self.dispatcher.client if client is None else client
|
||||
@@ -40,7 +50,7 @@ class BECWidgetsCLIServer:
|
||||
self._shutdown_event = False
|
||||
self._heartbeat_timer = QTimer()
|
||||
self._heartbeat_timer.timeout.connect(self.emit_heartbeat)
|
||||
self._heartbeat_timer.start(200) # Emit heartbeat every 1 seconds
|
||||
self._heartbeat_timer.start(200)
|
||||
|
||||
def on_rpc_update(self, msg: dict, metadata: dict):
|
||||
request_id = metadata.get("request_id")
|
||||
@@ -105,19 +115,57 @@ class BECWidgetsCLIServer:
|
||||
self.client.connector.set(
|
||||
MessageEndpoints.gui_heartbeat(self.gui_id),
|
||||
messages.StatusMessage(name=self.gui_id, status=1, info={}),
|
||||
expire=10,
|
||||
expire=1,
|
||||
)
|
||||
|
||||
def shutdown(self): # TODO not sure if needed when cleanup is done at level of BECConnector
|
||||
self._shutdown_event = True
|
||||
self._heartbeat_timer.stop()
|
||||
self.gui.close()
|
||||
self.client.shutdown()
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
class SimpleFileLikeFromLogOutputFunc:
|
||||
def __init__(self, log_func):
|
||||
self._log_func = log_func
|
||||
|
||||
def write(self, buffer):
|
||||
for line in buffer.rstrip().splitlines():
|
||||
line = line.rstrip()
|
||||
if line:
|
||||
self._log_func(line)
|
||||
|
||||
def flush(self):
|
||||
return
|
||||
|
||||
def close(self):
|
||||
return
|
||||
|
||||
|
||||
def _start_server(gui_id: str, gui_class: Union[BECFigure, BECDockArea], config: str | None = None):
|
||||
if config:
|
||||
try:
|
||||
config = json.loads(config)
|
||||
service_config = ServiceConfig(config=config)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
service_config = ServiceConfig(config_path=config)
|
||||
else:
|
||||
# if no config is provided, use the default config
|
||||
service_config = ServiceConfig()
|
||||
|
||||
bec_logger.configure(
|
||||
service_config.redis,
|
||||
QtRedisConnector,
|
||||
service_name="BECWidgetsCLIServer",
|
||||
service_config=service_config.service_config,
|
||||
)
|
||||
server = BECWidgetsCLIServer(gui_id=gui_id, config=service_config, gui_class=gui_class)
|
||||
return server
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from qtpy.QtCore import QSize
|
||||
from qtpy.QtGui import QIcon
|
||||
@@ -125,16 +173,6 @@ if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
import bec_widgets
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("BEC Figure")
|
||||
module_path = os.path.dirname(bec_widgets.__file__)
|
||||
icon = QIcon()
|
||||
icon.addFile(os.path.join(module_path, "assets", "bec_widgets_icon.png"), size=QSize(48, 48))
|
||||
app.setWindowIcon(icon)
|
||||
|
||||
win = QMainWindow()
|
||||
win.setWindowTitle("BEC Widgets")
|
||||
|
||||
parser = argparse.ArgumentParser(description="BEC Widgets CLI Server")
|
||||
parser.add_argument("--id", type=str, help="The id of the server")
|
||||
parser.add_argument(
|
||||
@@ -142,7 +180,7 @@ if __name__ == "__main__": # pragma: no cover
|
||||
type=str,
|
||||
help="Name of the gui class to be rendered. Possible values: \n- BECFigure\n- BECDockArea",
|
||||
)
|
||||
parser.add_argument("--config", type=str, help="Config to connect to redis.")
|
||||
parser.add_argument("--config", type=str, help="Config file or config string.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -157,12 +195,40 @@ if __name__ == "__main__": # pragma: no cover
|
||||
)
|
||||
gui_class = BECFigure
|
||||
|
||||
server = BECWidgetsCLIServer(gui_id=args.id, config=args.config, gui_class=gui_class)
|
||||
with redirect_stdout(SimpleFileLikeFromLogOutputFunc(logger.debug)):
|
||||
with redirect_stderr(SimpleFileLikeFromLogOutputFunc(logger.error)):
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("BEC Figure")
|
||||
module_path = os.path.dirname(bec_widgets.__file__)
|
||||
icon = QIcon()
|
||||
icon.addFile(
|
||||
os.path.join(module_path, "assets", "app_icons", "bec_widgets_icon.png"),
|
||||
size=QSize(48, 48),
|
||||
)
|
||||
app.setWindowIcon(icon)
|
||||
|
||||
gui = server.gui
|
||||
win.setCentralWidget(gui)
|
||||
win.resize(800, 600)
|
||||
win.show()
|
||||
win = QMainWindow()
|
||||
win.setWindowTitle("BEC Widgets")
|
||||
|
||||
app.aboutToQuit.connect(server.shutdown)
|
||||
sys.exit(app.exec())
|
||||
server = _start_server(args.id, gui_class, args.config)
|
||||
|
||||
gui = server.gui
|
||||
win.setCentralWidget(gui)
|
||||
win.resize(800, 600)
|
||||
win.show()
|
||||
|
||||
app.aboutToQuit.connect(server.shutdown)
|
||||
|
||||
def sigint_handler(*args):
|
||||
# display message, for people to let it terminate gracefully
|
||||
print("Caught SIGINT, exiting")
|
||||
app.quit()
|
||||
|
||||
signal.signal(signal.SIGINT, sigint_handler)
|
||||
signal.signal(signal.SIGTERM, sigint_handler)
|
||||
|
||||
sys.exit(app.exec())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
from .motor_movement import (
|
||||
MotorControlApp,
|
||||
MotorControlMap,
|
||||
MotorControlPanel,
|
||||
MotorControlPanelAbsolute,
|
||||
MotorControlPanelRelative,
|
||||
MotorCoordinateTable,
|
||||
MotorThread,
|
||||
)
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
import zmq
|
||||
from pyqtgraph.Qt import uic
|
||||
from qtpy.QtCore import Signal as pyqtSignal
|
||||
from qtpy.QtCore import Slot as pyqtSlot
|
||||
from qtpy.QtGui import QKeySequence
|
||||
from qtpy.QtWidgets import QDialog, QFileDialog, QFrame, QLabel, QShortcut, QVBoxLayout, QWidget
|
||||
|
||||
# from scipy.stats import multivariate_normal
|
||||
|
||||
|
||||
class EigerPlot(QWidget):
|
||||
update_signal = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
# pg.setConfigOptions(background="w", foreground="k", antialias=True)
|
||||
|
||||
current_path = os.path.dirname(__file__)
|
||||
uic.loadUi(os.path.join(current_path, "eiger_plot.ui"), self)
|
||||
|
||||
# Set widow name
|
||||
self.setWindowTitle("Eiger Plot")
|
||||
|
||||
self.hist_lims = None
|
||||
self.mask = None
|
||||
self.image = None
|
||||
|
||||
# UI
|
||||
self.init_ui()
|
||||
self.hook_signals()
|
||||
self.key_bindings()
|
||||
|
||||
# ZMQ Consumer
|
||||
self._zmq_consumer_exit_event = threading.Event()
|
||||
self._zmq_consumer_thread = self.start_zmq_consumer()
|
||||
|
||||
def close(self):
|
||||
super().close()
|
||||
self._zmq_consumer_exit_event.set()
|
||||
self._zmq_consumer_thread.join()
|
||||
|
||||
def init_ui(self):
|
||||
# Create Plot and add ImageItem
|
||||
self.plot_item = pg.PlotItem()
|
||||
self.plot_item.setAspectLocked(True)
|
||||
self.imageItem = pg.ImageItem()
|
||||
self.plot_item.addItem(self.imageItem)
|
||||
|
||||
# Setting up histogram
|
||||
self.hist = pg.HistogramLUTItem()
|
||||
self.hist.setImageItem(self.imageItem)
|
||||
self.hist.gradient.loadPreset("magma")
|
||||
self.update_hist()
|
||||
|
||||
# Adding Items to Graphical Layout
|
||||
self.glw.addItem(self.plot_item)
|
||||
self.glw.addItem(self.hist)
|
||||
|
||||
def hook_signals(self):
|
||||
# Buttons
|
||||
# self.pushButton_test.clicked.connect(self.start_sim_stream)
|
||||
self.pushButton_mask.clicked.connect(self.load_mask_dialog)
|
||||
self.pushButton_delete_mask.clicked.connect(self.delete_mask)
|
||||
self.pushButton_help.clicked.connect(self.show_help_dialog)
|
||||
|
||||
# SpinBoxes
|
||||
self.doubleSpinBox_hist_min.valueChanged.connect(self.update_hist)
|
||||
self.doubleSpinBox_hist_max.valueChanged.connect(self.update_hist)
|
||||
|
||||
# Signal/Slots
|
||||
self.update_signal.connect(self.on_image_update)
|
||||
|
||||
def key_bindings(self):
|
||||
# Key bindings for rotation
|
||||
rotate_plus = QShortcut(QKeySequence("Ctrl+A"), self)
|
||||
rotate_minus = QShortcut(QKeySequence("Ctrl+Z"), self)
|
||||
self.comboBox_rotation.setToolTip("Increase rotation: Ctrl+A\nDecrease rotation: Ctrl+Z")
|
||||
self.checkBox_transpose.setToolTip("Toggle transpose: Ctrl+T")
|
||||
|
||||
max_index = self.comboBox_rotation.count() - 1 # Maximum valid index
|
||||
|
||||
rotate_plus.activated.connect(
|
||||
lambda: self.comboBox_rotation.setCurrentIndex(
|
||||
min(self.comboBox_rotation.currentIndex() + 1, max_index)
|
||||
)
|
||||
)
|
||||
|
||||
rotate_minus.activated.connect(
|
||||
lambda: self.comboBox_rotation.setCurrentIndex(
|
||||
max(self.comboBox_rotation.currentIndex() - 1, 0)
|
||||
)
|
||||
)
|
||||
|
||||
# Key bindings for transpose
|
||||
transpose = QShortcut(QKeySequence("Ctrl+T"), self)
|
||||
transpose.activated.connect(self.checkBox_transpose.toggle)
|
||||
|
||||
FFT = QShortcut(QKeySequence("Ctrl+F"), self)
|
||||
FFT.activated.connect(self.checkBox_FFT.toggle)
|
||||
self.checkBox_FFT.setToolTip("Toggle FFT: Ctrl+F")
|
||||
|
||||
log = QShortcut(QKeySequence("Ctrl+L"), self)
|
||||
log.activated.connect(self.checkBox_log.toggle)
|
||||
self.checkBox_log.setToolTip("Toggle log: Ctrl+L")
|
||||
|
||||
mask = QShortcut(QKeySequence("Ctrl+M"), self)
|
||||
mask.activated.connect(self.pushButton_mask.click)
|
||||
self.pushButton_mask.setToolTip("Load mask: Ctrl+M")
|
||||
|
||||
delete_mask = QShortcut(QKeySequence("Ctrl+D"), self)
|
||||
delete_mask.activated.connect(self.pushButton_delete_mask.click)
|
||||
self.pushButton_delete_mask.setToolTip("Delete mask: Ctrl+D")
|
||||
|
||||
def update_hist(self):
|
||||
self.hist_levels = [
|
||||
self.doubleSpinBox_hist_min.value(),
|
||||
self.doubleSpinBox_hist_max.value(),
|
||||
]
|
||||
self.hist.setLevels(min=self.hist_levels[0], max=self.hist_levels[1])
|
||||
self.hist.setHistogramRange(
|
||||
self.hist_levels[0] - 0.1 * self.hist_levels[0],
|
||||
self.hist_levels[1] + 0.1 * self.hist_levels[1],
|
||||
)
|
||||
|
||||
def load_mask_dialog(self):
|
||||
options = QFileDialog.Options()
|
||||
options |= QFileDialog.ReadOnly
|
||||
file_name, _ = QFileDialog.getOpenFileName(
|
||||
self, "Select Mask File", "", "H5 Files (*.h5);;All Files (*)", options=options
|
||||
)
|
||||
if file_name:
|
||||
self.load_mask(file_name)
|
||||
|
||||
def load_mask(self, path):
|
||||
try:
|
||||
with h5py.File(path, "r") as f:
|
||||
self.mask = f["data"][...]
|
||||
if self.mask is not None:
|
||||
# Set label to mask name without path
|
||||
self.label_mask.setText(os.path.basename(path))
|
||||
except KeyError as e:
|
||||
# Update GUI with the error message
|
||||
print(f"Error: {str(e)}")
|
||||
|
||||
def delete_mask(self):
|
||||
self.mask = None
|
||||
self.label_mask.setText("No Mask")
|
||||
|
||||
@pyqtSlot()
|
||||
def on_image_update(self):
|
||||
# TODO first rotate then transpose
|
||||
if self.mask is not None:
|
||||
# self.image = np.ma.masked_array(self.image, mask=self.mask) #TODO test if np works
|
||||
self.image = self.image * (1 - self.mask) + 1
|
||||
|
||||
if self.checkBox_FFT.isChecked():
|
||||
self.image = np.abs(np.fft.fftshift(np.fft.fft2(self.image)))
|
||||
|
||||
if self.comboBox_rotation.currentIndex() > 0: # rotate
|
||||
self.image = np.rot90(self.image, k=self.comboBox_rotation.currentIndex(), axes=(0, 1))
|
||||
|
||||
if self.checkBox_transpose.isChecked(): # transpose
|
||||
self.image = np.transpose(self.image)
|
||||
|
||||
if self.checkBox_log.isChecked():
|
||||
self.image = np.log10(self.image)
|
||||
|
||||
self.imageItem.setImage(self.image, autoLevels=False)
|
||||
|
||||
###############################
|
||||
# ZMQ Consumer
|
||||
###############################
|
||||
|
||||
def start_zmq_consumer(self):
|
||||
consumer_thread = threading.Thread(
|
||||
target=self.zmq_consumer, args=(self._zmq_consumer_exit_event,), daemon=True
|
||||
)
|
||||
consumer_thread.start()
|
||||
return consumer_thread
|
||||
|
||||
def zmq_consumer(self, exit_event):
|
||||
print("starting consumer")
|
||||
live_stream_url = "tcp://129.129.95.38:20000"
|
||||
receiver = zmq.Context().socket(zmq.SUB)
|
||||
receiver.connect(live_stream_url)
|
||||
receiver.setsockopt_string(zmq.SUBSCRIBE, "")
|
||||
|
||||
poller = zmq.Poller()
|
||||
poller.register(receiver, zmq.POLLIN)
|
||||
|
||||
# code could be a bit simpler here, testing exit_event in
|
||||
# 'while' condition, but like this it is easier for the
|
||||
# 'test_zmq_consumer' test
|
||||
while True:
|
||||
if poller.poll(1000): # 1s timeout
|
||||
raw_meta, raw_data = receiver.recv_multipart(zmq.NOBLOCK)
|
||||
|
||||
meta = json.loads(raw_meta.decode("utf-8"))
|
||||
self.image = np.frombuffer(raw_data, dtype=meta["type"]).reshape(meta["shape"])
|
||||
self.update_signal.emit()
|
||||
if exit_event.is_set():
|
||||
break
|
||||
|
||||
receiver.disconnect(live_stream_url)
|
||||
|
||||
###############################
|
||||
# just simulations from here
|
||||
###############################
|
||||
|
||||
def show_help_dialog(self):
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("Help")
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
# Key bindings section
|
||||
layout.addWidget(QLabel("Keyboard Shortcuts:"))
|
||||
|
||||
key_bindings = [
|
||||
("Ctrl+A", "Increase rotation"),
|
||||
("Ctrl+Z", "Decrease rotation"),
|
||||
("Ctrl+T", "Toggle transpose"),
|
||||
("Ctrl+F", "Toggle FFT"),
|
||||
("Ctrl+L", "Toggle log scale"),
|
||||
("Ctrl+M", "Load mask"),
|
||||
("Ctrl+D", "Delete mask"),
|
||||
]
|
||||
|
||||
for keys, action in key_bindings:
|
||||
layout.addWidget(QLabel(f"{keys} - {action}"))
|
||||
|
||||
# Separator
|
||||
separator = QFrame()
|
||||
separator.setFrameShape(QFrame.HLine)
|
||||
separator.setFrameShadow(QFrame.Sunken)
|
||||
layout.addWidget(separator)
|
||||
|
||||
# Histogram section
|
||||
layout.addWidget(QLabel("Histogram:"))
|
||||
layout.addWidget(
|
||||
QLabel(
|
||||
"Use the Double Spin Boxes to adjust the minimum and maximum values of the histogram."
|
||||
)
|
||||
)
|
||||
|
||||
# Another Separator
|
||||
another_separator = QFrame()
|
||||
another_separator.setFrameShape(QFrame.HLine)
|
||||
another_separator.setFrameShadow(QFrame.Sunken)
|
||||
layout.addWidget(another_separator)
|
||||
|
||||
# Mask section
|
||||
layout.addWidget(QLabel("Mask:"))
|
||||
layout.addWidget(
|
||||
QLabel(
|
||||
"Use 'Load Mask' to load a mask from an H5 file. 'Delete Mask' removes the current mask."
|
||||
)
|
||||
)
|
||||
|
||||
dialog.setLayout(layout)
|
||||
dialog.exec()
|
||||
|
||||
###############################
|
||||
# just simulations from here
|
||||
###############################
|
||||
# def start_sim_stream(self):
|
||||
# sim_stream_thread = threading.Thread(target=self.sim_stream, daemon=True)
|
||||
# sim_stream_thread.start()
|
||||
#
|
||||
# def sim_stream(self):
|
||||
# for i in range(100):
|
||||
# # Generate 100x100 image of random noise
|
||||
# self.image = np.random.rand(100, 100) * 0.2
|
||||
#
|
||||
# # Define Gaussian parameters
|
||||
# x, y = np.mgrid[0:50, 0:50]
|
||||
# pos = np.dstack((x, y))
|
||||
#
|
||||
# # Center at (25, 25) longer along y-axis
|
||||
# rv = multivariate_normal(mean=[25, 25], cov=[[25, 0], [0, 80]])
|
||||
#
|
||||
# # Generate Gaussian in the first quadrant
|
||||
# gaussian_quadrant = rv.pdf(pos) * 40
|
||||
#
|
||||
# # Place Gaussian in the first quadrant
|
||||
# self.image[0:50, 0:50] += gaussian_quadrant * 10
|
||||
#
|
||||
# self.update_signal.emit()
|
||||
# time.sleep(0.1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
plot = EigerPlot()
|
||||
plot.show()
|
||||
sys.exit(app.exec())
|
||||
@@ -1,207 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>874</width>
|
||||
<height>762</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Plot Control</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Histogram MIN</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_hist_min">
|
||||
<property name="minimum">
|
||||
<double>-100000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Histogram MAX</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_hist_max">
|
||||
<property name="minimum">
|
||||
<double>-100000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Data Control</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_FFT">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FFT</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_log">
|
||||
<property name="text">
|
||||
<string>log</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_mask">
|
||||
<property name="text">
|
||||
<string>Load Mask</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_delete_mask">
|
||||
<property name="text">
|
||||
<string>Delete Mask</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Orientation</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboBox_rotation">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>90</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>180</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>270</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Rotation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox_transpose">
|
||||
<property name="text">
|
||||
<string>Transpose</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_mask">
|
||||
<property name="text">
|
||||
<string>No Mask</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_help">
|
||||
<property name="text">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="GraphicsLayoutWidget" name="glw"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>GraphicsLayoutWidget</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>pyqtgraph.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
92
bec_widgets/examples/general_app/general_app.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from qtpy.QtCore import QSize
|
||||
from qtpy.QtGui import QActionGroup, QIcon
|
||||
from qtpy.QtWidgets import QApplication, QMainWindow, QStyle
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.examples.general_app.web_links import BECWebLinksMixin
|
||||
from bec_widgets.utils.colors import apply_theme
|
||||
from bec_widgets.utils.ui_loader import UILoader
|
||||
|
||||
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
|
||||
class BECGeneralApp(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super(BECGeneralApp, self).__init__(parent)
|
||||
ui_file_path = os.path.join(os.path.dirname(__file__), "general_app.ui")
|
||||
self.load_ui(ui_file_path)
|
||||
|
||||
self.resize(1280, 720)
|
||||
|
||||
self.ini_ui()
|
||||
|
||||
def ini_ui(self):
|
||||
self._setup_icons()
|
||||
self._hook_menubar_docs()
|
||||
self._hook_theme_bar()
|
||||
|
||||
def load_ui(self, ui_file):
|
||||
loader = UILoader(self)
|
||||
self.ui = loader.loader(ui_file)
|
||||
self.setCentralWidget(self.ui)
|
||||
|
||||
def _hook_menubar_docs(self):
|
||||
# BEC Docs
|
||||
self.ui.action_BEC_docs.triggered.connect(BECWebLinksMixin.open_bec_docs)
|
||||
# BEC Widgets Docs
|
||||
self.ui.action_BEC_widgets_docs.triggered.connect(BECWebLinksMixin.open_bec_widgets_docs)
|
||||
# Bug report
|
||||
self.ui.action_bug_report.triggered.connect(BECWebLinksMixin.open_bec_bug_report)
|
||||
|
||||
def change_theme(self, theme):
|
||||
apply_theme(theme)
|
||||
|
||||
def _setup_icons(self):
|
||||
help_icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion)
|
||||
bug_icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxInformation)
|
||||
computer_icon = QIcon.fromTheme("computer")
|
||||
widget_icon = QIcon(os.path.join(MODULE_PATH, "assets", "designer_icons", "dock_area.png"))
|
||||
|
||||
self.ui.action_BEC_docs.setIcon(help_icon)
|
||||
self.ui.action_BEC_widgets_docs.setIcon(help_icon)
|
||||
self.ui.action_bug_report.setIcon(bug_icon)
|
||||
|
||||
self.ui.central_tab.setTabIcon(0, widget_icon)
|
||||
self.ui.central_tab.setTabIcon(1, computer_icon)
|
||||
|
||||
def _hook_theme_bar(self):
|
||||
self.ui.action_light.setCheckable(True)
|
||||
self.ui.action_dark.setCheckable(True)
|
||||
|
||||
# Create an action group to make sure only one can be checked at a time
|
||||
theme_group = QActionGroup(self)
|
||||
theme_group.addAction(self.ui.action_light)
|
||||
theme_group.addAction(self.ui.action_dark)
|
||||
theme_group.setExclusive(True)
|
||||
|
||||
# Connect the actions to the theme change method
|
||||
|
||||
self.ui.action_light.triggered.connect(lambda: self.change_theme("light"))
|
||||
self.ui.action_dark.triggered.connect(lambda: self.change_theme("dark"))
|
||||
|
||||
self.ui.action_dark.trigger()
|
||||
|
||||
|
||||
def main(): # pragma: no cover
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
icon = QIcon()
|
||||
icon.addFile(
|
||||
os.path.join(MODULE_PATH, "assets", "app_icons", "BEC-Dark.png"), size=QSize(48, 48)
|
||||
)
|
||||
app.setWindowIcon(icon)
|
||||
main_window = BECGeneralApp()
|
||||
main_window.show()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
262
bec_widgets/examples/general_app/general_app.ui
Normal file
@@ -0,0 +1,262 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1718</width>
|
||||
<height>1139</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<property name="tabShape">
|
||||
<enum>QTabWidget::TabShape::Rounded</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="central_tab">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="dock_area_tab">
|
||||
<attribute name="title">
|
||||
<string>Dock Area</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BECDockArea" name="dock_area"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="vscode_tab">
|
||||
<attribute name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::Computer"/>
|
||||
</attribute>
|
||||
<attribute name="title">
|
||||
<string>Visual Studio Code</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="VSCodeEditor" name="vscode"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1718</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="action_BEC_docs"/>
|
||||
<addaction name="action_BEC_widgets_docs"/>
|
||||
<addaction name="action_bug_report"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTheme">
|
||||
<property name="title">
|
||||
<string>Theme</string>
|
||||
</property>
|
||||
<addaction name="action_light"/>
|
||||
<addaction name="action_dark"/>
|
||||
</widget>
|
||||
<addaction name="menuTheme"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QDockWidget" name="dock_scan_control">
|
||||
<property name="windowTitle">
|
||||
<string>Scan Control</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="ScanControl" name="scan_control"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="dock_status_2">
|
||||
<property name="windowTitle">
|
||||
<string>BEC Service Status</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BECStatusBox" name="bec_status_box_2"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="dock_queue">
|
||||
<property name="windowTitle">
|
||||
<string>Scan Queue</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="BECQueue" name="bec_queue">
|
||||
<row/>
|
||||
<column/>
|
||||
<column/>
|
||||
<column/>
|
||||
<item row="0" column="0"/>
|
||||
<item row="0" column="1"/>
|
||||
<item row="0" column="2"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<action name="action_BEC_docs">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>BEC Docs</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_BEC_widgets_docs">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>BEC Widgets Docs</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_bug_report">
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DialogError"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bug Report</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_light">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Light</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_dark">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dark</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>WebsiteWidget</class>
|
||||
<extends>QWebEngineView</extends>
|
||||
<header>website_widget</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BECQueue</class>
|
||||
<extends>QTableWidget</extends>
|
||||
<header>bec_queue</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ScanControl</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>scan_control</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>VSCodeEditor</class>
|
||||
<extends>WebsiteWidget</extends>
|
||||
<header>vs_code_editor</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BECStatusBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>bec_status_box</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BECDockArea</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>dock_area</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QWebEngineView</class>
|
||||
<extends></extends>
|
||||
<header location="global">QtWebEngineWidgets/QWebEngineView</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
15
bec_widgets/examples/general_app/web_links.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import webbrowser
|
||||
|
||||
|
||||
class BECWebLinksMixin:
|
||||
@staticmethod
|
||||
def open_bec_docs():
|
||||
webbrowser.open("https://beamline-experiment-control.readthedocs.io/en/latest/")
|
||||
|
||||
@staticmethod
|
||||
def open_bec_widgets_docs():
|
||||
webbrowser.open("https://bec.readthedocs.io/projects/bec-widgets/en/latest/")
|
||||
|
||||
@staticmethod
|
||||
def open_bec_bug_report():
|
||||
webbrowser.open("https://gitlab.psi.ch/groups/bec/-/issues/")
|
||||
@@ -2,35 +2,23 @@ import os
|
||||
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtWidgets, uic
|
||||
from qtconsole.inprocess import QtInProcessKernelManager
|
||||
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
||||
from qtpy.QtCore import QSize
|
||||
from qtpy.QtGui import QIcon
|
||||
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
||||
from qtpy.QtWidgets import (
|
||||
QApplication,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
QSplitter,
|
||||
QTabWidget,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from bec_widgets.cli.rpc_register import RPCRegister
|
||||
from bec_widgets.utils import BECDispatcher
|
||||
from bec_widgets.widgets import BECFigure
|
||||
from bec_widgets.utils.colors import apply_theme
|
||||
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
||||
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
||||
|
||||
|
||||
class JupyterConsoleWidget(RichJupyterWidget): # pragma: no cover:
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.kernel_manager = QtInProcessKernelManager()
|
||||
self.kernel_manager.start_kernel(show_banner=False)
|
||||
self.kernel_client = self.kernel_manager.client()
|
||||
self.kernel_client.start_channels()
|
||||
|
||||
self.kernel_manager.kernel.shell.push({"np": np, "pg": pg})
|
||||
# self.set_console_font_size(70)
|
||||
|
||||
def shutdown_kernel(self):
|
||||
self.kernel_client.stop_channels()
|
||||
self.kernel_manager.shutdown_kernel()
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
from bec_widgets.widgets.jupyter_console.jupyter_console import BECJupyterConsole
|
||||
|
||||
|
||||
class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
@@ -39,49 +27,61 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
current_path = os.path.dirname(__file__)
|
||||
uic.loadUi(os.path.join(current_path, "jupyter_console_window.ui"), self)
|
||||
|
||||
self._init_ui()
|
||||
|
||||
self.splitter.setSizes([200, 100])
|
||||
self.safe_close = False
|
||||
# self.figure.clean_signal.connect(self.confirm_close)
|
||||
|
||||
self.register = RPCRegister()
|
||||
self.register.add_rpc(self.figure)
|
||||
|
||||
# console push
|
||||
self.console.kernel_manager.kernel.shell.push(
|
||||
{
|
||||
"fig": self.figure,
|
||||
"register": self.register,
|
||||
"dock": self.dock,
|
||||
"w1": self.w1,
|
||||
"w2": self.w2,
|
||||
"w3": self.w3,
|
||||
"d1": self.d1,
|
||||
"d2": self.d2,
|
||||
"d3": self.d3,
|
||||
"bar": self.bar,
|
||||
"b2a": self.button_2_a,
|
||||
"b2b": self.button_2_b,
|
||||
"b2c": self.button_2_c,
|
||||
"bec": self.figure.client,
|
||||
"scans": self.figure.client.scans,
|
||||
"dev": self.figure.client.device_manager.devices,
|
||||
}
|
||||
)
|
||||
if self.console.inprocess is True:
|
||||
self.console.kernel_manager.kernel.shell.push(
|
||||
{
|
||||
"np": np,
|
||||
"pg": pg,
|
||||
"fig": self.figure,
|
||||
"dock": self.dock,
|
||||
"w1": self.w1,
|
||||
"w2": self.w2,
|
||||
"w3": self.w3,
|
||||
"w4": self.w4,
|
||||
"w5": self.w5,
|
||||
"w6": self.w6,
|
||||
"w7": self.w7,
|
||||
"w8": self.w8,
|
||||
"w9": self.w9,
|
||||
"d0": self.d0,
|
||||
"d1": self.d1,
|
||||
"d2": self.d2,
|
||||
"wave": self.wf,
|
||||
# "bar": self.bar,
|
||||
# "cm": self.colormap,
|
||||
"im": self.im,
|
||||
"mm": self.mm,
|
||||
}
|
||||
)
|
||||
|
||||
def _init_ui(self):
|
||||
# Plotting window
|
||||
self.glw_1_layout = QVBoxLayout(self.glw) # Create a new QVBoxLayout
|
||||
self.figure = BECFigure(parent=self, gui_id="remote") # Create a new BECDeviceMonitor
|
||||
self.glw_1_layout.addWidget(self.figure) # Add BECDeviceMonitor to the layout
|
||||
self.layout = QHBoxLayout(self)
|
||||
|
||||
self.dock_layout = QVBoxLayout(self.dock_placeholder)
|
||||
self.dock = BECDockArea(gui_id="remote")
|
||||
self.dock_layout.addWidget(self.dock)
|
||||
# Horizontal splitter
|
||||
splitter = QSplitter(self)
|
||||
self.layout.addWidget(splitter)
|
||||
|
||||
tab_widget = QTabWidget(splitter)
|
||||
|
||||
first_tab = QWidget()
|
||||
first_tab_layout = QVBoxLayout(first_tab)
|
||||
self.dock = BECDockArea(gui_id="dock")
|
||||
first_tab_layout.addWidget(self.dock)
|
||||
tab_widget.addTab(first_tab, "Dock Area")
|
||||
|
||||
second_tab = QWidget()
|
||||
second_tab_layout = QVBoxLayout(second_tab)
|
||||
self.figure = BECFigure(parent=self, gui_id="figure")
|
||||
second_tab_layout.addWidget(self.figure)
|
||||
tab_widget.addTab(second_tab, "BEC Figure")
|
||||
|
||||
group_box = QGroupBox("Jupyter Console", splitter)
|
||||
group_box_layout = QVBoxLayout(group_box)
|
||||
self.console = BECJupyterConsole(inprocess=True)
|
||||
group_box_layout.addWidget(self.console)
|
||||
|
||||
# add stuff to figure
|
||||
self._init_figure()
|
||||
@@ -89,55 +89,102 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
# init dock for testing
|
||||
self._init_dock()
|
||||
|
||||
self.console_layout = QVBoxLayout(self.widget_console)
|
||||
self.console = JupyterConsoleWidget()
|
||||
self.console_layout.addWidget(self.console)
|
||||
self.console.set_default_style("linux")
|
||||
self.setWindowTitle("Jupyter Console Window")
|
||||
|
||||
def _init_figure(self):
|
||||
self.figure.plot(x_name="samx", y_name="bpm4d")
|
||||
self.figure.motor_map("samx", "samy")
|
||||
self.figure.image("eiger", color_map="viridis", vrange=(0, 100))
|
||||
|
||||
self.figure.change_layout(2, 2)
|
||||
|
||||
self.w1 = self.figure[0, 0]
|
||||
self.w2 = self.figure[0, 1]
|
||||
self.w3 = self.figure[1, 0]
|
||||
|
||||
# curves for w1
|
||||
self.w1.add_curve_scan("samx", "samy", "bpm4i", pen_style="dash")
|
||||
self.w1.add_curve_scan("samx", "samy", "bpm3a", pen_style="dash")
|
||||
self.c1 = self.w1.get_config()
|
||||
self.w1 = self.figure.plot(
|
||||
x_name="samx",
|
||||
y_name="bpm4i",
|
||||
# title="Standard Plot with sync device, custom labels - w1",
|
||||
# x_label="Motor Position",
|
||||
# y_label="Intensity (A.U.)",
|
||||
row=0,
|
||||
col=0,
|
||||
)
|
||||
self.w1.set(
|
||||
title="Standard Plot with sync device, custom labels - w1",
|
||||
x_label="Motor Position",
|
||||
y_label="Intensity (A.U.)",
|
||||
)
|
||||
self.w2 = self.figure.motor_map("samx", "samy", row=0, col=1)
|
||||
self.w3 = self.figure.image(
|
||||
"eiger", color_map="viridis", vrange=(0, 100), title="Eiger Image - w3", row=0, col=2
|
||||
)
|
||||
self.w4 = self.figure.plot(
|
||||
x_name="samx",
|
||||
y_name="samy",
|
||||
z_name="bpm4i",
|
||||
color_map_z="magma",
|
||||
new=True,
|
||||
title="2D scatter plot - w4",
|
||||
row=0,
|
||||
col=3,
|
||||
)
|
||||
self.w5 = self.figure.plot(
|
||||
y_name="bpm4i",
|
||||
new=True,
|
||||
title="Best Effort Plot - w5",
|
||||
dap="GaussianModel",
|
||||
row=1,
|
||||
col=0,
|
||||
)
|
||||
self.w6 = self.figure.plot(
|
||||
x_name="timestamp", y_name="bpm4i", new=True, title="Timestamp Plot - w6", row=1, col=1
|
||||
)
|
||||
self.w7 = self.figure.plot(
|
||||
x_name="index", y_name="bpm4i", new=True, title="Index Plot - w7", row=1, col=2
|
||||
)
|
||||
self.w8 = self.figure.plot(
|
||||
y_name="monitor_async", new=True, title="Async Plot - Best Effort - w8", row=2, col=0
|
||||
)
|
||||
self.w9 = self.figure.plot(
|
||||
x_name="timestamp",
|
||||
y_name="monitor_async",
|
||||
new=True,
|
||||
title="Async Plot - timestamp - w9",
|
||||
row=2,
|
||||
col=1,
|
||||
)
|
||||
self.w10 = self.figure.plot(
|
||||
x_name="index",
|
||||
y_name="monitor_async",
|
||||
new=True,
|
||||
title="Async Plot - index - w10",
|
||||
row=2,
|
||||
col=2,
|
||||
)
|
||||
|
||||
def _init_dock(self):
|
||||
self.button_1 = QtWidgets.QPushButton("Button 1 ")
|
||||
self.button_2_a = QtWidgets.QPushButton("Button to be added at place 0,0 in d3")
|
||||
self.button_2_b = QtWidgets.QPushButton("button after without postions specified")
|
||||
self.button_2_c = QtWidgets.QPushButton("button super late")
|
||||
self.button_3 = QtWidgets.QPushButton("Button above Figure ")
|
||||
self.bar = SpiralProgressBar()
|
||||
|
||||
self.label_2 = QtWidgets.QLabel("label which is added separately")
|
||||
self.label_3 = QtWidgets.QLabel("Label above figure")
|
||||
self.d0 = self.dock.add_dock(name="dock_0")
|
||||
self.mm = self.d0.add_widget("BECMotorMapWidget")
|
||||
self.mm.change_motors("samx", "samy")
|
||||
|
||||
self.d1 = self.dock.add_dock(widget=self.button_1, position="left")
|
||||
self.d1.addWidget(self.label_2)
|
||||
self.d2 = self.dock.add_dock(widget=self.bar, position="right")
|
||||
self.d3 = self.dock.add_dock(name="figure")
|
||||
self.fig_dock3 = BECFigure()
|
||||
self.fig_dock3.plot(x_name="samx", y_name="bpm4d")
|
||||
self.d3.add_widget(self.label_3)
|
||||
self.d3.add_widget(self.button_3)
|
||||
self.d3.add_widget(self.fig_dock3)
|
||||
self.d1 = self.dock.add_dock(name="dock_1", position="right")
|
||||
self.im = self.d1.add_widget("BECImageWidget")
|
||||
self.im.image("eiger")
|
||||
|
||||
self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
|
||||
self.wf = self.d2.add_widget("BECWaveformWidget", row=0, col=0)
|
||||
self.wf.plot(x_name="samx", y_name="bpm3a")
|
||||
self.wf.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
|
||||
# self.bar = self.d2.add_widget("RingProgressBar", row=0, col=1)
|
||||
# self.bar.set_diameter(200)
|
||||
|
||||
# self.d3 = self.dock.add_dock(name="dock_3", position="bottom")
|
||||
# self.colormap = pg.GradientWidget()
|
||||
# self.d3.add_widget(self.colormap, row=0, col=0)
|
||||
|
||||
self.dock.save_state()
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Override to handle things when main window is closed."""
|
||||
self.dock.cleanup()
|
||||
self.figure.clear_all()
|
||||
self.figure.client.shutdown()
|
||||
self.dock.close()
|
||||
self.figure.cleanup()
|
||||
self.figure.close()
|
||||
self.console.close()
|
||||
|
||||
super().closeEvent(event)
|
||||
|
||||
|
||||
@@ -148,16 +195,20 @@ if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
module_path = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("Jupyter Console")
|
||||
app.setApplicationDisplayName("Jupyter Console")
|
||||
apply_theme("dark")
|
||||
icon = QIcon()
|
||||
icon.addFile(
|
||||
os.path.join(module_path, "assets", "app_icons", "terminal_icon.png"), size=QSize(48, 48)
|
||||
)
|
||||
app.setWindowIcon(icon)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
client = bec_dispatcher.client
|
||||
client.start()
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("Jupyter Console")
|
||||
app.setApplicationDisplayName("Jupyter Console")
|
||||
icon = QIcon()
|
||||
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
|
||||
app.setWindowIcon(icon)
|
||||
win = JupyterConsoleWindow()
|
||||
win.show()
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>2104</width>
|
||||
<height>966</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Plotting Console</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_1">
|
||||
<attribute name="title">
|
||||
<string>BECDock</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QWidget" name="dock_placeholder" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>BECFigure</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QWidget" name="glw" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget_console" native="true"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,159 +0,0 @@
|
||||
# import simulation_progress as SP
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from bec_lib import messages
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from qtpy.QtCore import Signal as pyqtSignal
|
||||
from qtpy.QtCore import Slot as pyqtSlot
|
||||
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
||||
|
||||
|
||||
class StreamApp(QWidget):
|
||||
update_signal = pyqtSignal()
|
||||
new_scan_id = pyqtSignal(str)
|
||||
|
||||
def __init__(self, device, sub_device):
|
||||
super().__init__()
|
||||
pg.setConfigOptions(background="w", foreground="k")
|
||||
self.init_ui()
|
||||
|
||||
self.setWindowTitle("MCA readout")
|
||||
|
||||
self.data = None
|
||||
self.scan_id = None
|
||||
self.stream_consumer = None
|
||||
|
||||
self.device = device
|
||||
self.sub_device = sub_device
|
||||
|
||||
self.start_device_consumer()
|
||||
|
||||
# self.start_device_consumer(self.device) # for simulation
|
||||
|
||||
self.new_scan_id.connect(self.create_new_stream_consumer)
|
||||
self.update_signal.connect(self.plot_new)
|
||||
|
||||
def init_ui(self):
|
||||
# Create layout and add widgets
|
||||
self.layout = QVBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
# Create plot
|
||||
self.glw = pg.GraphicsLayoutWidget()
|
||||
self.layout.addWidget(self.glw)
|
||||
|
||||
# Create Plot and add ImageItem
|
||||
self.plot_item = pg.PlotItem()
|
||||
self.plot_item.setAspectLocked(False)
|
||||
self.imageItem = pg.ImageItem()
|
||||
# self.plot_item1D = pg.PlotItem()
|
||||
# self.plot_item.addItem(self.imageItem)
|
||||
# self.plot_item.addItem(self.plot_item1D)
|
||||
|
||||
# Setting up histogram
|
||||
# self.hist = pg.HistogramLUTItem()
|
||||
# self.hist.setImageItem(self.imageItem)
|
||||
# self.hist.gradient.loadPreset("magma")
|
||||
# self.update_hist()
|
||||
|
||||
# Adding Items to Graphical Layout
|
||||
self.glw.addItem(self.plot_item)
|
||||
# self.glw.addItem(self.hist)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def create_new_stream_consumer(self, scan_id: str):
|
||||
print(f"Creating new stream consumer for scan_id: {scan_id}")
|
||||
|
||||
self.connect_stream_consumer(scan_id, self.device)
|
||||
|
||||
def connect_stream_consumer(self, scan_id, device):
|
||||
if self.stream_consumer is not None:
|
||||
self.stream_consumer.shutdown()
|
||||
|
||||
self.stream_consumer = connector.stream_consumer(
|
||||
topics=MessageEndpoints.device_async_readback(scan_id=scan_id, device=device),
|
||||
cb=self._streamer_cb,
|
||||
parent=self,
|
||||
)
|
||||
|
||||
self.stream_consumer.start()
|
||||
|
||||
def start_device_consumer(self):
|
||||
self.device_consumer = connector.consumer(
|
||||
topics=MessageEndpoints.scan_status(), cb=self._device_cv, parent=self
|
||||
)
|
||||
|
||||
self.device_consumer.start()
|
||||
|
||||
# def start_device_consumer(self, device): #for simulation
|
||||
# self.device_consumer = connector.consumer(
|
||||
# topics=MessageEndpoints.device_status(device), cb=self._device_cv, parent=self
|
||||
# )
|
||||
#
|
||||
# self.device_consumer.start()
|
||||
|
||||
def plot_new(self):
|
||||
print(f"Printing data from plot update: {self.data}")
|
||||
self.plot_item.plot(self.data[0])
|
||||
# self.imageItem.setImage(self.data, autoLevels=False)
|
||||
|
||||
@staticmethod
|
||||
def _streamer_cb(msg, *, parent, **_kwargs) -> None:
|
||||
msgMCS = msg.value
|
||||
print(msgMCS)
|
||||
row = msgMCS.content["signals"][parent.sub_device]
|
||||
metadata = msgMCS.metadata
|
||||
|
||||
# Check if the current number of rows is odd
|
||||
# if parent.data is not None and parent.data.shape[0] % 2 == 1:
|
||||
# row = np.flip(row) # Flip the row
|
||||
print(f"Printing data from callback update: {row}")
|
||||
parent.data = np.array([row])
|
||||
# if parent.data is None:
|
||||
# parent.data = np.array([row])
|
||||
# else:
|
||||
# parent.data = np.vstack((parent.data, row))
|
||||
|
||||
parent.update_signal.emit()
|
||||
|
||||
@staticmethod
|
||||
def _device_cv(msg, *, parent, **_kwargs) -> None:
|
||||
print("Getting ScanID")
|
||||
|
||||
msgDEV = msg.value
|
||||
|
||||
current_scan_id = msgDEV.content["scan_id"]
|
||||
|
||||
if parent.scan_id is None:
|
||||
parent.scan_id = current_scan_id
|
||||
parent.new_scan_id.emit(current_scan_id)
|
||||
print(f"New scan_id: {current_scan_id}")
|
||||
|
||||
if current_scan_id != parent.scan_id:
|
||||
parent.scan_id = current_scan_id
|
||||
# parent.data = None
|
||||
# parent.imageItem.clear()
|
||||
parent.new_scan_id.emit(current_scan_id)
|
||||
|
||||
print(f"New scan_id: {current_scan_id}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
from bec_lib.redis_connector import RedisConnector
|
||||
|
||||
parser = argparse.ArgumentParser(description="Stream App.")
|
||||
parser.add_argument("--port", type=str, default="pc15543:6379", help="Port for RedisConnector")
|
||||
parser.add_argument("--device", type=str, default="mcs", help="Device name")
|
||||
parser.add_argument("--sub_device", type=str, default="mca4", help="Sub-device name")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
connector = RedisConnector(args.port)
|
||||
|
||||
app = QApplication([])
|
||||
streamApp = StreamApp(device=args.device, sub_device=args.sub_device)
|
||||
|
||||
streamApp.show()
|
||||
app.exec()
|
||||
@@ -1,28 +0,0 @@
|
||||
import time
|
||||
|
||||
from bec_lib import messages
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.redis_connector import RedisConnector
|
||||
|
||||
connector = RedisConnector("localhost:6379")
|
||||
metadata = {}
|
||||
|
||||
scan_id = "ScanID1"
|
||||
|
||||
metadata.update(
|
||||
{"scan_id": scan_id, "async_update": "append"} # this will be different for each scan
|
||||
)
|
||||
for ii in range(20):
|
||||
data = {"mca1": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "mca2": [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]}
|
||||
msg = messages.DeviceMessage(signals=data, metadata=metadata).dumps()
|
||||
|
||||
connector.xadd(
|
||||
topic=MessageEndpoints.device_async_readback(
|
||||
scan_id=scan_id, device="mca"
|
||||
), # scan_id will be different for each scan
|
||||
msg={"data": msg}, # TODO should be msg_dict
|
||||
expire=1800,
|
||||
)
|
||||
|
||||
print(f"Sent {ii}")
|
||||
time.sleep(0.5)
|
||||
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1433</width>
|
||||
<height>689</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Plot Config 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="BECMonitor" name="plot_1"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="pushButton_setting_2">
|
||||
<property name="text">
|
||||
<string>Setting Plot 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" colspan="2">
|
||||
<widget class="BECMonitor" name="plot_2"/>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Plot Scan Types = True</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="pushButton_setting_1">
|
||||
<property name="text">
|
||||
<string>Setting Plot 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Plot Config 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QPushButton" name="pushButton_setting_3">
|
||||
<property name="text">
|
||||
<string>Setting Plot 3</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4" colspan="2">
|
||||
<widget class="BECMonitor" name="plot_3"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1433</width>
|
||||
<height>37</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>BECMonitor</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header location="global">bec_widgets.widgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,197 +0,0 @@
|
||||
import os
|
||||
|
||||
from qtpy import uic
|
||||
from qtpy.QtWidgets import QApplication, QMainWindow
|
||||
|
||||
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
||||
from bec_widgets.widgets import BECMonitor
|
||||
|
||||
# some default configs for demonstration purposes
|
||||
CONFIG_SIMPLE = {
|
||||
"plot_settings": {
|
||||
"background_color": "black",
|
||||
"num_columns": 2,
|
||||
"colormap": "plasma",
|
||||
"scan_types": False,
|
||||
},
|
||||
"plot_data": [
|
||||
{
|
||||
"plot_name": "BPM4i plots vs samx",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "bpm4i",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samx"}],
|
||||
"y": [{"name": "bpm4i", "entry": "bpm4i"}],
|
||||
},
|
||||
},
|
||||
# {
|
||||
# "type": "history",
|
||||
# "signals": {
|
||||
# "x": [{"name": "samx"}],
|
||||
# "y": [{"name": "bpm4i", "entry": "bpm4i"}],
|
||||
# },
|
||||
# },
|
||||
# {
|
||||
# "type": "dap",
|
||||
# 'worker':'some_worker',
|
||||
# "signals": {
|
||||
# "x": [{"name": "samx"}],
|
||||
# "y": [{"name": "bpm4i", "entry": "bpm4i"}],
|
||||
# },
|
||||
# },
|
||||
],
|
||||
},
|
||||
{
|
||||
"plot_name": "Gauss plots vs samx",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "Gauss",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samx", "entry": "samx"}],
|
||||
"y": [{"name": "gauss_bpm"}, {"name": "gauss_adc1"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
CONFIG_SCAN_MODE = {
|
||||
"plot_settings": {
|
||||
"background_color": "white",
|
||||
"num_columns": 3,
|
||||
"colormap": "plasma",
|
||||
"scan_types": True,
|
||||
},
|
||||
"plot_data": {
|
||||
"grid_scan": [
|
||||
{
|
||||
"plot_name": "Grid plot 1",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "BPM",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samx", "entry": "samx"}],
|
||||
"y": [{"name": "gauss_bpm"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"plot_name": "Grid plot 2",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "BPM",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samx", "entry": "samx"}],
|
||||
"y": [{"name": "gauss_adc1"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"plot_name": "Grid plot 3",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "BPM",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {"x": [{"name": "samy"}], "y": [{"name": "gauss_adc2"}]},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"plot_name": "Grid plot 4",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "BPM",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samy", "entry": "samy"}],
|
||||
"y": [{"name": "gauss_adc3"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
"line_scan": [
|
||||
{
|
||||
"plot_name": "BPM plots vs samx",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "Gauss",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samx", "entry": "samx"}],
|
||||
"y": [{"name": "bpm4i"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"plot_name": "Gauss plots vs samx",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "Gauss",
|
||||
"sources": [
|
||||
{
|
||||
"type": "scan_segment",
|
||||
"signals": {
|
||||
"x": [{"name": "samx", "entry": "samx"}],
|
||||
"y": [{"name": "gauss_bpm"}, {"name": "gauss_adc1"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class ModularApp(QMainWindow):
|
||||
def __init__(self, client=None, parent=None):
|
||||
super(ModularApp, self).__init__(parent)
|
||||
|
||||
# Client and device manager from BEC
|
||||
self.client = BECDispatcher().client if client is None else client
|
||||
|
||||
# Loading UI
|
||||
current_path = os.path.dirname(__file__)
|
||||
uic.loadUi(os.path.join(current_path, "modular.ui"), self)
|
||||
|
||||
self._init_plots()
|
||||
|
||||
def _init_plots(self):
|
||||
"""Initialize plots and connect the buttons to the config dialogs"""
|
||||
plots = [self.plot_1, self.plot_2, self.plot_3]
|
||||
configs = [CONFIG_SIMPLE, CONFIG_SCAN_MODE, CONFIG_SCAN_MODE]
|
||||
buttons = [self.pushButton_setting_1, self.pushButton_setting_2, self.pushButton_setting_3]
|
||||
|
||||
# hook plots, configs and buttons together
|
||||
for plot, config, button in zip(plots, configs, buttons):
|
||||
plot.on_config_update(config)
|
||||
button.clicked.connect(plot.show_config_dialog)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# BECclient global variables
|
||||
client = BECDispatcher().client
|
||||
client.start()
|
||||
|
||||
app = QApplication([])
|
||||
modularApp = ModularApp(client=client)
|
||||
|
||||
window = modularApp
|
||||
window.show()
|
||||
app.exec()
|
||||
@@ -1,9 +0,0 @@
|
||||
from .motor_control_compilations import (
|
||||
MotorControlApp,
|
||||
MotorControlMap,
|
||||
MotorControlPanel,
|
||||
MotorControlPanelAbsolute,
|
||||
MotorControlPanelRelative,
|
||||
MotorCoordinateTable,
|
||||
MotorThread,
|
||||
)
|
||||
@@ -1,17 +0,0 @@
|
||||
selected_motors:
|
||||
motor_x: "samx"
|
||||
motor_y: "samy"
|
||||
|
||||
plot_motors:
|
||||
max_points: 1000
|
||||
num_dim_points: 100
|
||||
scatter_size: 5
|
||||
precision: 3
|
||||
mode_lock: False # "Individual" or "Start/Stop". False to unlock
|
||||
extra_columns:
|
||||
- sample name: "sample 1"
|
||||
- step_x [mu]: 25
|
||||
- step_y [mu]: 25
|
||||
- exp_time [s]: 1
|
||||
- start: 1
|
||||
- tilt [deg]: 0
|
||||
@@ -1,10 +0,0 @@
|
||||
redis:
|
||||
host: pc15543
|
||||
port: 6379
|
||||
mongodb:
|
||||
host: localhost
|
||||
port: 27017
|
||||
scibec:
|
||||
host: http://localhost
|
||||
port: 3030
|
||||
beamline: MyBeamline
|
||||
@@ -1,17 +0,0 @@
|
||||
selected_motors:
|
||||
motor_x: "samx"
|
||||
motor_y: "samy"
|
||||
|
||||
plot_motors:
|
||||
max_points: 1000
|
||||
num_dim_points: 100
|
||||
scatter_size: 5
|
||||
precision: 3
|
||||
mode_lock: Start/Stop # "Individual" or "Start/Stop"
|
||||
extra_columns:
|
||||
- sample name: "sample 1"
|
||||
- step_x [mu]: 25
|
||||
- step_y [mu]: 25
|
||||
- exp_time [s]: 1
|
||||
- start: 1
|
||||
- tilt [deg]: 0
|
||||
@@ -1,256 +0,0 @@
|
||||
# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
|
||||
|
||||
import qdarktheme
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QApplication, QSplitter, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
||||
from bec_widgets.widgets.motor_control.motor_control import MotorThread
|
||||
from bec_widgets.widgets.motor_control.motor_table.motor_table import MotorCoordinateTable
|
||||
from bec_widgets.widgets.motor_control.movement_absolute.movement_absolute import (
|
||||
MotorControlAbsolute,
|
||||
)
|
||||
from bec_widgets.widgets.motor_control.movement_relative.movement_relative import (
|
||||
MotorControlRelative,
|
||||
)
|
||||
from bec_widgets.widgets.motor_control.selection.selection import MotorControlSelection
|
||||
|
||||
CONFIG_DEFAULT = {
|
||||
"motor_control": {
|
||||
"motor_x": "samx",
|
||||
"motor_y": "samy",
|
||||
"step_size_x": 3,
|
||||
"step_size_y": 3,
|
||||
"precision": 4,
|
||||
"step_x_y_same": False,
|
||||
"move_with_arrows": False,
|
||||
},
|
||||
"plot_settings": {
|
||||
"colormap": "Greys",
|
||||
"scatter_size": 5,
|
||||
"max_points": 1000,
|
||||
"num_dim_points": 100,
|
||||
"precision": 2,
|
||||
"num_columns": 1,
|
||||
"background_value": 25,
|
||||
},
|
||||
"motors": [
|
||||
{
|
||||
"plot_name": "Motor Map",
|
||||
"x_label": "Motor X",
|
||||
"y_label": "Motor Y",
|
||||
"signals": {
|
||||
"x": [{"name": "samx", "entry": "samx"}],
|
||||
"y": [{"name": "samy", "entry": "samy"}],
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class MotorControlApp(QWidget):
|
||||
def __init__(self, parent=None, client=None, config=None):
|
||||
super().__init__(parent)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
self.client = bec_dispatcher.client if client is None else client
|
||||
self.config = config
|
||||
|
||||
# Widgets
|
||||
self.motor_control_panel = MotorControlPanel(client=self.client, config=self.config)
|
||||
# Create MotorMap
|
||||
# self.motion_map = MotorMap(client=self.client, config=self.config)
|
||||
# Create MotorCoordinateTable
|
||||
self.motor_table = MotorCoordinateTable(client=self.client, config=self.config)
|
||||
|
||||
# Create the splitter and add MotorMap and MotorControlPanel
|
||||
splitter = QSplitter(Qt.Horizontal)
|
||||
# splitter.addWidget(self.motion_map)
|
||||
splitter.addWidget(self.motor_control_panel)
|
||||
splitter.addWidget(self.motor_table)
|
||||
|
||||
# Set the main layout
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(splitter)
|
||||
self.setLayout(layout)
|
||||
|
||||
# Connecting signals and slots
|
||||
# self.motor_control_panel.selection_widget.selected_motors_signal.connect(
|
||||
# lambda x, y: self.motion_map.change_motors(x, y, 0)
|
||||
# )
|
||||
self.motor_control_panel.absolute_widget.coordinates_signal.connect(
|
||||
self.motor_table.add_coordinate
|
||||
)
|
||||
self.motor_control_panel.relative_widget.precision_signal.connect(
|
||||
self.motor_table.set_precision
|
||||
)
|
||||
self.motor_control_panel.relative_widget.precision_signal.connect(
|
||||
self.motor_control_panel.absolute_widget.set_precision
|
||||
)
|
||||
|
||||
# self.motor_table.plot_coordinates_signal.connect(self.motion_map.plot_saved_coordinates)
|
||||
|
||||
|
||||
class MotorControlMap(QWidget):
|
||||
def __init__(self, parent=None, client=None, config=None):
|
||||
super().__init__(parent)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
self.client = bec_dispatcher.client if client is None else client
|
||||
self.config = config
|
||||
|
||||
# Widgets
|
||||
self.motor_control_panel = MotorControlPanel(client=self.client, config=self.config)
|
||||
# Create MotorMap
|
||||
# self.motion_map = MotorMap(client=self.client, config=self.config)
|
||||
|
||||
# Create the splitter and add MotorMap and MotorControlPanel
|
||||
splitter = QSplitter(Qt.Horizontal)
|
||||
# splitter.addWidget(self.motion_map)
|
||||
splitter.addWidget(self.motor_control_panel)
|
||||
|
||||
# Set the main layout
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(splitter)
|
||||
self.setLayout(layout)
|
||||
|
||||
# Connecting signals and slots
|
||||
# self.motor_control_panel.selection_widget.selected_motors_signal.connect(
|
||||
# lambda x, y: self.motion_map.change_motors(x, y, 0)
|
||||
# )
|
||||
|
||||
|
||||
class MotorControlPanel(QWidget):
|
||||
def __init__(self, parent=None, client=None, config=None):
|
||||
super().__init__(parent)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
self.client = bec_dispatcher.client if client is None else client
|
||||
self.config = config
|
||||
|
||||
self.motor_thread = MotorThread(client=self.client)
|
||||
|
||||
self.selection_widget = MotorControlSelection(
|
||||
client=self.client, config=self.config, motor_thread=self.motor_thread
|
||||
)
|
||||
self.relative_widget = MotorControlRelative(
|
||||
client=self.client, config=self.config, motor_thread=self.motor_thread
|
||||
)
|
||||
self.absolute_widget = MotorControlAbsolute(
|
||||
client=self.client, config=self.config, motor_thread=self.motor_thread
|
||||
)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
layout.addWidget(self.selection_widget)
|
||||
layout.addWidget(self.relative_widget)
|
||||
layout.addWidget(self.absolute_widget)
|
||||
|
||||
# Connecting signals and slots
|
||||
self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
|
||||
self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
|
||||
|
||||
# Set the window to a fixed size based on its contents
|
||||
self.layout().setSizeConstraint(layout.SetFixedSize)
|
||||
|
||||
|
||||
class MotorControlPanelAbsolute(QWidget):
|
||||
def __init__(self, parent=None, client=None, config=None):
|
||||
super().__init__(parent)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
self.client = bec_dispatcher.client if client is None else client
|
||||
self.config = config
|
||||
|
||||
self.motor_thread = MotorThread(client=self.client)
|
||||
|
||||
self.selection_widget = MotorControlSelection(
|
||||
client=client, config=config, motor_thread=self.motor_thread
|
||||
)
|
||||
self.absolute_widget = MotorControlAbsolute(
|
||||
client=client, config=config, motor_thread=self.motor_thread
|
||||
)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(self.selection_widget)
|
||||
layout.addWidget(self.absolute_widget)
|
||||
|
||||
# Connecting signals and slots
|
||||
self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
|
||||
|
||||
# Set the window to a fixed size based on its contents
|
||||
self.layout().setSizeConstraint(layout.SetFixedSize)
|
||||
|
||||
|
||||
class MotorControlPanelRelative(QWidget):
|
||||
def __init__(self, parent=None, client=None, config=None):
|
||||
super().__init__(parent)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
self.client = bec_dispatcher.client if client is None else client
|
||||
self.config = config
|
||||
|
||||
self.motor_thread = MotorThread(client=self.client)
|
||||
|
||||
self.selection_widget = MotorControlSelection(
|
||||
client=client, config=config, motor_thread=self.motor_thread
|
||||
)
|
||||
self.relative_widget = MotorControlRelative(
|
||||
client=client, config=config, motor_thread=self.motor_thread
|
||||
)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(self.selection_widget)
|
||||
layout.addWidget(self.relative_widget)
|
||||
|
||||
# Connecting signals and slots
|
||||
self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
|
||||
|
||||
# Set the window to a fixed size based on its contents
|
||||
self.layout().setSizeConstraint(layout.SetFixedSize)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
parser = argparse.ArgumentParser(description="Run various Motor Control Widgets compositions.")
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--variant",
|
||||
type=str,
|
||||
choices=["app", "map", "panel", "panel_abs", "panel_rel"],
|
||||
help="Select the variant of the motor control to run. "
|
||||
"'app' for the full application, "
|
||||
"'map' for MotorMap, "
|
||||
"'panel' for the MotorControlPanel, "
|
||||
"'panel_abs' for MotorControlPanel with absolute control, "
|
||||
"'panel_rel' for MotorControlPanel with relative control.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
client = bec_dispatcher.client
|
||||
client.start()
|
||||
|
||||
app = QApplication([])
|
||||
qdarktheme.setup_theme("auto")
|
||||
|
||||
if args.variant == "app":
|
||||
window = MotorControlApp(client=client) # , config=CONFIG_DEFAULT)
|
||||
elif args.variant == "map":
|
||||
window = MotorControlMap(client=client) # , config=CONFIG_DEFAULT)
|
||||
elif args.variant == "panel":
|
||||
window = MotorControlPanel(client=client) # , config=CONFIG_DEFAULT)
|
||||
elif args.variant == "panel_abs":
|
||||
window = MotorControlPanelAbsolute(client=client) # , config=CONFIG_DEFAULT)
|
||||
elif args.variant == "panel_rel":
|
||||
window = MotorControlPanelRelative(client=client) # , config=CONFIG_DEFAULT)
|
||||
else:
|
||||
print("Please specify a valid variant to run. Use -h for help.")
|
||||
print("Running the full application by default.")
|
||||
window = MotorControlApp(client=client) # , config=CONFIG_DEFAULT)
|
||||
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
@@ -1,926 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1561</width>
|
||||
<height>748</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1409</width>
|
||||
<height>748</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Motor Controller</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="8,5,8">
|
||||
<item>
|
||||
<widget class="GraphicsLayoutWidget" name="glw">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="Controls">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>221</width>
|
||||
<height>471</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6" stretch="1,1,1,0,1">
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorSelection">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>261</width>
|
||||
<height>145</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Motor Selection</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Motor Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBox_motor_x"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboBox_motor_y"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Motor X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="pushButton_connecMotors">
|
||||
<property name="text">
|
||||
<string>Connect Motors</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorControl">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>261</width>
|
||||
<height>339</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Motor Relative</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_enableArrows">
|
||||
<property name="text">
|
||||
<string>Move with arrow keys</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_same_xy">
|
||||
<property name="text">
|
||||
<string>Step [X] = Step [Y]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="step_grid">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_step_y">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>111</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Step [Y]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>111</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Decimal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_step_x">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>110</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_step_x">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>111</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Step [X]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_step_y">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>110</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_precision">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>110</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="direction_grid">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item row="1" column="2" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QToolButton" name="toolButton_up">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>26</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::UpArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QToolButton" name="toolButton_down">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>26</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::DownArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QToolButton" name="toolButton_left">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>26</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::LeftArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="toolButton_right">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>26</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::RightArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorControl_absolute">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>261</width>
|
||||
<height>195</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Move Absolute</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_save_with_go">
|
||||
<property name="text">
|
||||
<string>Save position with Go</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_absolute_y">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-500.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>500.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_absolute_x">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-500.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>500.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_save">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_set">
|
||||
<property name="text">
|
||||
<string>Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_go_absolute">
|
||||
<property name="text">
|
||||
<string>Go</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_stop">
|
||||
<property name="text">
|
||||
<string>Stop Movement</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget_tables">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_coordinates">
|
||||
<attribute name="title">
|
||||
<string>Coordinates</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Entries Mode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox_mode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Individual</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Start/Stop</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget_coordinates">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Show</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Move</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Tag</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="pushButton_resize_table">
|
||||
<property name="text">
|
||||
<string>Resize Table</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_resize_auto">
|
||||
<property name="text">
|
||||
<string>Resize Auto</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="pushButton_importCSV">
|
||||
<property name="text">
|
||||
<string>Import CSV</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="pushButton_exportCSV">
|
||||
<property name="text">
|
||||
<string>Export CSV</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="pushButton_help">
|
||||
<property name="text">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="pushButton_duplicate">
|
||||
<property name="text">
|
||||
<string>Duplicate Last Entry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_settings">
|
||||
<attribute name="title">
|
||||
<string>Settings</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorLimits">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Motor Limits</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="pushButton_updateLimits">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_Y_max">
|
||||
<property name="text">
|
||||
<string>+ Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_Y_min">
|
||||
<property name="text">
|
||||
<string>- Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_X_min">
|
||||
<property name="text">
|
||||
<string>- X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_X_max">
|
||||
<property name="text">
|
||||
<string>+ X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_y_max">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_y_min">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_x_min">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_x_max">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Plotting Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox_max_points">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Max Points</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox_scatter_size">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>15</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Scatter Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QPushButton" name="pushButton_update_config">
|
||||
<property name="text">
|
||||
<string>Update Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox_num_dim_points">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>N dim</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QPushButton" name="pushButton_enableGUI">
|
||||
<property name="text">
|
||||
<string>Enable Control GUI</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_queue">
|
||||
<attribute name="title">
|
||||
<string>Queue</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Work in progress</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_5">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Queue</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>queueID</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>scan_id</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>is_scan</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>scan_number</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>IQ status</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>GraphicsLayoutWidget</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>pyqtgraph.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
18
bec_widgets/examples/plugin_example_pyside/main.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
"""PySide6 port of the Qt Designer taskmenuextension example from Qt v6.x"""
|
||||
|
||||
import sys
|
||||
|
||||
from bec_ipython_client.main import BECIPythonClient
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
from bec_widgets.examples.plugin_example_pyside.tictactoe import TicTacToe
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
app = QApplication(sys.argv)
|
||||
window = TicTacToe()
|
||||
window.state = "-X-XO----"
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||