Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08c3d7d175 | ||
| af23e74f71 | |||
| 0bf1cf9b8a | |||
|
|
6dd64dd8e1 | ||
| 99a98de8a3 | |||
| 3c0e501c56 | |||
|
|
9d76d8bf6c | ||
| a3110d9814 | |||
| ec9c8f2963 | |||
| b32ced85ff | |||
|
|
d0e5643d4f | ||
| 2efd48736c | |||
| 6ed1efc6af | |||
| a568633c32 | |||
|
|
6a919be88f | ||
| 8be8295b2b | |||
| 5d73fe455a | |||
| 7dadab1f14 | |||
|
|
664bbce01d | ||
| 097946fd68 | |||
| 4a890281f7 | |||
| cdd175207e | |||
|
|
3210a42e42 | ||
| 719254cf0a | |||
|
|
02193967de | ||
| 5f37e862c9 | |||
| 9925bbdb48 | |||
|
|
1f7ca4813c | ||
| ffc871ebbd | |||
|
|
7b9a36403d | ||
| 09c6c93c39 | |||
| c31e9a3aff | |||
|
|
960d84b7fe | ||
| e6f204b6aa | |||
| 02239de0a3 | |||
|
|
0aad9a0988 | ||
| c5501860e8 | |||
| 4e5520aee2 | |||
| 4591ba8f73 | |||
| f335763280 | |||
| e890091d86 | |||
| ac2cb5197d | |||
|
|
65345187b3 | ||
| d48243483e | |||
| 1ca9499edd | |||
| 060935ffc5 | |||
|
|
50dbef52c0 | ||
| bb385f07ca | |||
| cf28730515 | |||
|
|
13ae383455 | ||
| 2265458dcc | |||
|
|
0a59f08fcc | ||
| c70724a456 | |||
| 406c263746 | |||
| df35aabff3 | |||
| cc8c166b5c | |||
| c4f3308dc0 | |||
|
|
8f3824c0e7 | ||
| afdf4e8782 | |||
| 2a82032644 | |||
| 88a2f66758 | |||
| 3f3b207295 | |||
| 44cfda1c07 | |||
| e42b84c636 | |||
| 77c5aa741c | |||
| 2b4449afeb | |||
| 36ad464159 | |||
|
|
e8ae6f2e43 | ||
| 3ecbd60627 | |||
| 82a55ddf3e | |||
|
|
7d190719b1 | ||
| 8c2e7c8259 | |||
| dd7c71bb1e | |||
|
|
7b5b7a8cbb | ||
| af28574bd5 | |||
| 617db36ed4 | |||
|
|
ebc2e44c7c | ||
| 44738057a3 | |||
| f98a9f9771 | |||
| 2fe72c9ccb | |||
| f0203d9bf6 | |||
| 37835cbf76 | |||
|
|
e005be33d1 | ||
| 9d7718c3d9 | |||
| 9d8fb0b761 | |||
|
|
9df1e0899b | ||
| 640464a654 | |||
| 84abe46050 | |||
| 1d2afaa09e | |||
| 2bf5c7096e |
@@ -140,7 +140,7 @@ tests:
|
||||
- *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 run --source=./bec_widgets -m pytest -v --junitxml=report.xml --maxfail=2 --random-order --full-trace ./tests/unit_tests
|
||||
- coverage report
|
||||
- coverage xml
|
||||
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
|
||||
@@ -177,8 +177,7 @@ test-matrix:
|
||||
- *install-os-packages
|
||||
- *install-repos
|
||||
- pip install -e .[dev,$QT_PCKG]
|
||||
- pytest -v --junitxml=report.xml --random-order ./tests/unit_tests
|
||||
allow_failure: true
|
||||
- pytest -v --maxfail=2 --junitxml=report.xml --random-order ./tests/unit_tests
|
||||
|
||||
end-2-end-conda:
|
||||
stage: End2End
|
||||
|
||||
228
CHANGELOG.md
@@ -1,153 +1,157 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.95.0 (2024-08-21)
|
||||
## v0.99.15 (2024-08-31)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(theme): update pg axes on theme update ([`af23e74`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/af23e74f71152f4abc319ab7b45e65deefde3519))
|
||||
|
||||
* fix(positioner_box): fixed positioner box dialog; added test; closes #332 ([`0bf1cf9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0bf1cf9b8ab2f9171d5ff63d4e3672eb93e9a5fa))
|
||||
|
||||
## v0.99.14 (2024-08-30)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(color_button): signal and slot added for selecting color and for emitting color after change ([`99a98de`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/99a98de8a3b7a83d71e4b567e865ac6f5c62a754))
|
||||
|
||||
* fix(color_button): inheritance changed to QWidget ([`3c0e501`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3c0e501c56227d4d98ff0ac2186ff5065bff8d7a))
|
||||
|
||||
## v0.99.13 (2024-08-30)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs(device_browser): added user docs ([`2c31cc9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2c31cc90ae751f14a653cbbdd6c353d6359aaafe))
|
||||
* docs: minor updates to the widget tutorial ([`ec9c8f2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ec9c8f29633364c45ebd998a5411d428c1ce488d))
|
||||
|
||||
* docs(user): widget gallery with documentation added ([`7357f3d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7357f3d2a189f9f04954a027f39ce07c394d57ec))
|
||||
|
||||
* docs: added sphinx-inline-tabs as sphinx dependency ([`e9ecd26`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e9ecd268c602ea9572df0e8d508e49ee62d0c170))
|
||||
|
||||
* docs(cards): changed index cards to custom css class instead of overwriting the default sd-card theme ([`91ba30e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/91ba30e8d054a9c7f6c6d98b21113a5d0b1bbbbb))
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(cli): added device_browser to cli ([`196504b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/196504b533367a899c19b88af4ccd5b39dc46aac))
|
||||
|
||||
* feat(widgets): added device_browser widget ([`73f5a2f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/73f5a2f085b289ac18fa8a918b6ad7cfed595fb4))
|
||||
* docs(widget tutorial): step by step guide added ([`b32ced8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b32ced85fff628a9e1303a781630cdae3865238e))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(device_browser): fixed plugin assignment for designer ([`6500393`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/650039303aae9bbec62c676285938416fff146ce))
|
||||
* fix(dark mode button): fixed dark mode button state for external updates, including auto ([`a3110d9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a3110d98147295dcb1f9353f9aaf5461cba9232a))
|
||||
|
||||
## v0.99.12 (2024-08-29)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(toolbar): widget action added ([`2efd487`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2efd48736cbe04e84533f7933c552ea8274e2162))
|
||||
|
||||
* fix(reset_button): reset button added ([`6ed1efc`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6ed1efc6af193908f70aa37fb73157d2ca6a62f4))
|
||||
|
||||
* fix(abort_button): abort button added; some minor fixes ([`a568633`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a568633c3206a8c26069d140f2d9a548bf4124b0))
|
||||
|
||||
## v0.99.11 (2024-08-29)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(resume_button): resume button added ([`8be8295`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8be8295b2b38f36da210ab36c5da6d0a00e330cc))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(docs): review response ([`4790afd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4790afde3d61fc9beb073c2775c339d4f80779e3))
|
||||
* refactor(icons): general app icon changed; jupyter app icon changed to material icon ([`5d73fe4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5d73fe455a568ad40a9fadc5ce6e249d782ad20d))
|
||||
|
||||
### Test
|
||||
* refactor: add option to select scan and hide arg bundle buttons ([`7dadab1`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7dadab1f14aa41876ad39e8cdc7f7732248cc643))
|
||||
|
||||
* test: added test for device browser ([`e870e5b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e870e5ba083c61df581c9c0305adabe72967f997))
|
||||
|
||||
## v0.94.7 (2024-08-20)
|
||||
## v0.99.10 (2024-08-29)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: formatting of stdout, stderr captured text for logger ([`939f834`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/939f834a26ddbac0bdead0b60b1cdf52014f182f))
|
||||
* fix(stop_button): queue logic scan changed to halt instead of abort and reset ([`4a89028`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4a890281f7eaef02d0ec9f4c5bf080be11fe0fe3))
|
||||
|
||||
## v0.94.6 (2024-08-14)
|
||||
### Refactor
|
||||
|
||||
* refactor(stop_button): stop button changed to QWidget and adapted for toolbar ([`097946f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/097946fd688b8faf770e7cc0e689ea668206bc7a))
|
||||
|
||||
* refactor: added hide option for device selection button ([`cdd1752`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cdd175207e922904b2efbb2d9ecf7c556c617f2e))
|
||||
|
||||
## v0.99.9 (2024-08-28)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(server): emit heartbeat with state ([`bc2abe9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bc2abe945fb5adeec89ed5ac45e966db86ce6ffc))
|
||||
* fix: fixed build process and excluded docs and tests from tarballs and wheels ([`719254c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/719254cf0a48e1fc4bd541edba239570778bcfea))
|
||||
|
||||
## v0.94.5 (2024-08-14)
|
||||
## v0.99.8 (2024-08-28)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(website): fixed designer integration for website widget ([`5f37e86`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5f37e862c95ac7173b6918ad39bcaef938dad698))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(website): changed inheritance of website widget to simple qwidget; closes #325 ([`9925bbd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9925bbdb48b55eacbbce9fd6a1555a21b84221f9))
|
||||
|
||||
## v0.99.7 (2024-08-28)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(toolbar): material icons can accept color as kwarg ([`ffc871e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ffc871ebbd3b68abc3e151bb8f5849e6c50e775e))
|
||||
|
||||
## v0.99.6 (2024-08-28)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs: various bugs fixed ([`c31e9a3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c31e9a3aff3ee8e984674dee0965ee7f1b6e2b8f))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(toolbar): use of native qt separators ([`09c6c93`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/09c6c93c397ce4a21c293f6c79106c74b2db65ca))
|
||||
|
||||
## v0.99.5 (2024-08-28)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs(index): index page is centered ([`02239de`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/02239de0a36fcd6cbf97990b0dec1ddf7ecf6ba6))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(dock_area): dark button added ([`e6f204b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e6f204b6aa295747a68769f43af2e549149b401a))
|
||||
|
||||
## v0.99.4 (2024-08-28)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs(buttons): added missing buttons docs ([`4e5520a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4e5520aee2115d2fc0cebb3865433478a5ec8253))
|
||||
|
||||
* docs(developer): tutorial for BECWidget base class ([`ac2cb51`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ac2cb5197deef4d51e26ee5beb070eba3ffc210d))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(theme): apply theme to all pyqtgraph widgets on manual updates ([`c550186`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c5501860e8e07a53f4bce144d44ed39eda6290ef))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(buttons): changed grid and thumbnail fig in gallery ([`4591ba8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4591ba8f73e22aba7258cad93c073f1387cb74a0))
|
||||
|
||||
* refactor(icons): removed toolbar icons from assets ([`f335763`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f335763280adb1d83ba31f073ce206e4cb5d15ef))
|
||||
|
||||
* refactor(icons): moved widget icons to class attribute ICON_NAME ([`e890091`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e890091d862e42317c7a54fc414ba37c85f268b0))
|
||||
|
||||
## v0.99.3 (2024-08-27)
|
||||
|
||||
### Build
|
||||
|
||||
* build: increased min version of bec to 2.21.4
|
||||
|
||||
Since we now rely on reusing the BECClient singleton, we need the fix introduced with 2.21.4 in BEC. ([`4f96d0e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4f96d0e4a14edc4b2839c1dddeda384737dc7a8a))
|
||||
* build: updated min version of bec qthemes ([`d482434`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d48243483ef8228cc5eb85e40a6b8f5da3b45520))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(rpc): use client singleton instead of dispatcher ([`ea9240d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ea9240d2f71931082f33fb6b68231469875c3d63))
|
||||
* fix(cmaps): unified all defaults to magma cmap ([`1ca9499`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1ca9499edd334c19fe1e7aac71d3940a80a1ec95))
|
||||
|
||||
* fix: removed qcoreapplication for polling events ([`4d02b42`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4d02b42f11e9882b843317255a4975565c8a536f))
|
||||
* fix(color maps): color maps should take the background color into account; fixed min colors to 10 ([`060935f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/060935ffc5472a958c337bf60834c5291f104ece))
|
||||
|
||||
## v0.94.4 (2024-08-14)
|
||||
## v0.99.2 (2024-08-27)
|
||||
|
||||
### Documentation
|
||||
### Ci
|
||||
|
||||
* docs: review developer section; add introduction ([`2af5c94`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2af5c94913a3435c1839034df4f45f885b56d08b))
|
||||
* ci: additional tests are not allowed to fail ([`bb385f0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bb385f07ca18904461a541b5cadde05398c84438))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: do not shutdown client in "close"
|
||||
* fix(widgets): fixed default theme for widgets
|
||||
|
||||
Terminating client connections has to be done at the application level ([`198c1d1`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/198c1d1064cc2dae55de4b941929341faddacb28))
|
||||
If not theme is set, the init of the BECWidget base class sets the default theme to "dark" ([`cf28730`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cf28730515e3c2d5914e0205768734c578711e5c))
|
||||
|
||||
## v0.94.3 (2024-08-13)
|
||||
## v0.99.1 (2024-08-27)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(curve_dialog): async curves are shown in curve dialog after addition. ([`7aeb2b5`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7aeb2b5c26c7c2851e8d663d32521da8daec95ef))
|
||||
* fix(crosshair): emit all crosshair events, not just line coordinates ([`2265458`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2265458dcc57970db18c62619f5877d542d72e81))
|
||||
|
||||
* fix(waveform): async device entry is correctly passed, updated and with new scan the previous data are cleared ([`d56ea95`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d56ea95ef97bfdd0bc3eeddc4505d20b38e28559))
|
||||
|
||||
### Test
|
||||
|
||||
* test(waveform_widget): added tests for axis setting and curve dialog ([`f285b35`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f285b35b491660549e74349318119f7c2c44f619))
|
||||
|
||||
## v0.94.2 (2024-08-13)
|
||||
|
||||
### Fix
|
||||
|
||||
* 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: add PositionerControlLine ([`c80a7cd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c80a7cd1083baa9543a2cee2e3c3a51dfd209b19))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor: adjust dimensions ([`0273bf4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0273bf485694609325b5b556a3c69fb53c18446e))
|
||||
|
||||
## v0.93.5 (2024-08-08)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(positioner_box): icons fixed ([`281633d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/281633deff15b6879dac3a4f0770fa6949aaecdc))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor: add button for positioner selection ([`0d190c5`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0d190c5c5996e59fec4bdd44d2003e10e200b009))
|
||||
|
||||
### Test
|
||||
|
||||
* test(dap): wait for fit ([`6269009`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6269009e5451f830cdee58a514c7858483488a8d))
|
||||
|
||||
* test(auto-update): wait for rendering ([`6d2442d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6d2442d23c683fe92af13df982ce681c07e99cde))
|
||||
|
||||
## v0.93.4 (2024-08-07)
|
||||
|
||||
### 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)
|
||||
## v0.99.0 (2024-08-25)
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
bec_widgets/assets/app_icons/BEC-General-App.png
Normal file
|
After Width: | Height: | Size: 437 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 228 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 489 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 258 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 351 B |
@@ -1,4 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 341 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 492 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 470 B |
@@ -1,9 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 371 B |
@@ -1,11 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 366 B |
@@ -1,4 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 392 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 413 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 809 B |
@@ -1,9 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 377 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 450 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 319 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 487 B |
|
Before Width: | Height: | Size: 6.3 KiB |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 693 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 564 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 266 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 724 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 248 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 946 B |
@@ -1,5 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 357 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 733 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 455 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 811 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 815 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 621 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 354 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 609 B |
@@ -1,4 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 452 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 466 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 518 B |
@@ -1,3 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 231 B |
@@ -13,6 +13,7 @@ class Widgets(str, enum.Enum):
|
||||
Enum for the available widgets.
|
||||
"""
|
||||
|
||||
AbortButton = "AbortButton"
|
||||
BECDock = "BECDock"
|
||||
BECDockArea = "BECDockArea"
|
||||
BECFigure = "BECFigure"
|
||||
@@ -21,11 +22,14 @@ class Widgets(str, enum.Enum):
|
||||
BECQueue = "BECQueue"
|
||||
BECStatusBox = "BECStatusBox"
|
||||
BECWaveformWidget = "BECWaveformWidget"
|
||||
DarkModeButton = "DarkModeButton"
|
||||
DeviceBrowser = "DeviceBrowser"
|
||||
DeviceComboBox = "DeviceComboBox"
|
||||
DeviceLineEdit = "DeviceLineEdit"
|
||||
PositionerBox = "PositionerBox"
|
||||
PositionerControlLine = "PositionerControlLine"
|
||||
ResetButton = "ResetButton"
|
||||
ResumeButton = "ResumeButton"
|
||||
RingProgressBar = "RingProgressBar"
|
||||
ScanControl = "ScanControl"
|
||||
StopButton = "StopButton"
|
||||
@@ -34,6 +38,24 @@ class Widgets(str, enum.Enum):
|
||||
WebsiteWidget = "WebsiteWidget"
|
||||
|
||||
|
||||
class AbortButton(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
def _config_dict(self) -> "dict":
|
||||
"""
|
||||
Get the configuration of the widget.
|
||||
|
||||
Returns:
|
||||
dict: The configuration of the widget.
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
def _get_all_rpc(self) -> "dict":
|
||||
"""
|
||||
Get all registered RPC objects.
|
||||
"""
|
||||
|
||||
|
||||
class BECCurve(RPCBase):
|
||||
@rpc_call
|
||||
def remove(self):
|
||||
@@ -482,7 +504,7 @@ class BECFigure(RPCBase):
|
||||
y_entry: "str | None" = None,
|
||||
z_entry: "str | None" = None,
|
||||
color: "str | None" = None,
|
||||
color_map_z: "str | None" = "plasma",
|
||||
color_map_z: "str | None" = "magma",
|
||||
label: "str | None" = None,
|
||||
validate: "bool" = True,
|
||||
new: "bool" = False,
|
||||
@@ -1727,7 +1749,7 @@ class BECWaveform(RPCBase):
|
||||
y_entry: "str | None" = None,
|
||||
z_entry: "str | None" = None,
|
||||
color: "str | None" = None,
|
||||
color_map_z: "str | None" = "plasma",
|
||||
color_map_z: "str | None" = "magma",
|
||||
label: "str | None" = None,
|
||||
validate: "bool" = True,
|
||||
dap: "str | None" = None,
|
||||
@@ -2041,7 +2063,7 @@ class BECWaveformWidget(RPCBase):
|
||||
y_entry: "str | None" = None,
|
||||
z_entry: "str | None" = None,
|
||||
color: "str | None" = None,
|
||||
color_map_z: "str | None" = "plasma",
|
||||
color_map_z: "str | None" = "magma",
|
||||
label: "str | None" = None,
|
||||
validate: "bool" = True,
|
||||
dap: "str | None" = None,
|
||||
@@ -2289,6 +2311,15 @@ class BECWaveformWidget(RPCBase):
|
||||
"""
|
||||
|
||||
|
||||
class DarkModeButton(RPCBase):
|
||||
@rpc_call
|
||||
def toggle_dark_mode(self) -> None:
|
||||
"""
|
||||
Toggle the dark mode state. This will change the theme of the entire
|
||||
application to dark or light mode.
|
||||
"""
|
||||
|
||||
|
||||
class DeviceBrowser(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
@@ -2363,7 +2394,7 @@ class DeviceLineEdit(RPCBase):
|
||||
|
||||
class PositionerBox(RPCBase):
|
||||
@rpc_call
|
||||
def set_positioner(self, positioner: str):
|
||||
def set_positioner(self, positioner: "str | Positioner"):
|
||||
"""
|
||||
Set the device
|
||||
|
||||
@@ -2374,7 +2405,7 @@ class PositionerBox(RPCBase):
|
||||
|
||||
class PositionerControlLine(RPCBase):
|
||||
@rpc_call
|
||||
def set_positioner(self, positioner: str):
|
||||
def set_positioner(self, positioner: "str | Positioner"):
|
||||
"""
|
||||
Set the device
|
||||
|
||||
@@ -2383,6 +2414,42 @@ class PositionerControlLine(RPCBase):
|
||||
"""
|
||||
|
||||
|
||||
class ResetButton(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
def _config_dict(self) -> "dict":
|
||||
"""
|
||||
Get the configuration of the widget.
|
||||
|
||||
Returns:
|
||||
dict: The configuration of the widget.
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
def _get_all_rpc(self) -> "dict":
|
||||
"""
|
||||
Get all registered RPC objects.
|
||||
"""
|
||||
|
||||
|
||||
class ResumeButton(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
def _config_dict(self) -> "dict":
|
||||
"""
|
||||
Get the configuration of the widget.
|
||||
|
||||
Returns:
|
||||
dict: The configuration of the widget.
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
def _get_all_rpc(self) -> "dict":
|
||||
"""
|
||||
Get all registered RPC objects.
|
||||
"""
|
||||
|
||||
|
||||
class Ring(RPCBase):
|
||||
@rpc_call
|
||||
def _get_all_rpc(self) -> "dict":
|
||||
|
||||
@@ -80,7 +80,7 @@ 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)
|
||||
os.path.join(MODULE_PATH, "assets", "app_icons", "BEC-General-App.png"), size=QSize(48, 48)
|
||||
)
|
||||
app.setWindowIcon(icon)
|
||||
main_window = BECGeneralApp()
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from bec_qthemes import material_icon
|
||||
from qtpy.QtCore import QSize
|
||||
from qtpy.QtGui import QIcon
|
||||
from qtpy.QtWidgets import (
|
||||
@@ -200,10 +201,7 @@ if __name__ == "__main__": # pragma: no cover
|
||||
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)
|
||||
)
|
||||
icon = material_icon("terminal", color="#434343", filled=True)
|
||||
app.setWindowIcon(icon)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.examples.plugin_example_pyside.tictactoe import TicTacToe
|
||||
from bec_widgets.examples.plugin_example_pyside.tictactoetaskmenu import TicTacToeTaskMenuFactory
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
@@ -46,8 +46,7 @@ class TicTacToePlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
return "Games"
|
||||
|
||||
def icon(self):
|
||||
icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "games.png")
|
||||
return QIcon(icon_path)
|
||||
return designer_material_icon("sports_esports")
|
||||
|
||||
def includeFile(self):
|
||||
return "tictactoe"
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
from collections import defaultdict
|
||||
from typing import Literal
|
||||
|
||||
from bec_qthemes._icon.material_icons import material_icon
|
||||
from qtpy.QtCore import QSize
|
||||
from qtpy.QtGui import QAction, QIcon
|
||||
from qtpy.QtGui import QAction, QColor, QIcon
|
||||
from qtpy.QtWidgets import QHBoxLayout, QLabel, QMenu, QToolBar, QToolButton, QWidget
|
||||
|
||||
import bec_widgets
|
||||
@@ -44,9 +46,7 @@ class SeparatorAction(ToolBarAction):
|
||||
"""Separator action for the toolbar."""
|
||||
|
||||
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
||||
self.separator = QToolButton()
|
||||
self.separator.setFixedSize(2, 22)
|
||||
toolbar.addWidget(self.separator)
|
||||
toolbar.addSeparator()
|
||||
|
||||
|
||||
class IconAction(ToolBarAction):
|
||||
@@ -70,6 +70,50 @@ class IconAction(ToolBarAction):
|
||||
toolbar.addAction(self.action)
|
||||
|
||||
|
||||
class MaterialIconAction:
|
||||
"""
|
||||
Action with a Material icon for the toolbar.
|
||||
|
||||
Args:
|
||||
icon_path (str, optional): The name of the Material icon. Defaults to None.
|
||||
tooltip (bool, optional): The tooltip for the action. Defaults to None.
|
||||
checkable (bool, optional): Whether the action is checkable. Defaults to False.
|
||||
filled (bool, optional): Whether the icon is filled. Defaults to False.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
icon_name: str = None,
|
||||
tooltip: str = None,
|
||||
checkable: bool = False,
|
||||
filled: bool = False,
|
||||
color: str | tuple | QColor | dict[Literal["dark", "light"], str] | None = None,
|
||||
):
|
||||
self.icon_name = icon_name
|
||||
self.tooltip = tooltip
|
||||
self.checkable = checkable
|
||||
self.action = None
|
||||
self.filled = filled
|
||||
self.color = color
|
||||
|
||||
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
||||
icon = self.get_icon()
|
||||
self.action = QAction(icon, self.tooltip, target)
|
||||
self.action.setCheckable(self.checkable)
|
||||
toolbar.addAction(self.action)
|
||||
|
||||
def get_icon(self):
|
||||
|
||||
icon = material_icon(
|
||||
self.icon_name,
|
||||
size=(20, 20),
|
||||
convert_to_pixmap=False,
|
||||
filled=self.filled,
|
||||
color=self.color,
|
||||
)
|
||||
return icon
|
||||
|
||||
|
||||
class DeviceSelectionAction(ToolBarAction):
|
||||
"""
|
||||
Action for selecting a device in a combobox.
|
||||
@@ -98,6 +142,31 @@ class DeviceSelectionAction(ToolBarAction):
|
||||
self.device_combobox.setStyleSheet(f"QComboBox {{ background-color: {color}; }}")
|
||||
|
||||
|
||||
class WidgetAction(ToolBarAction):
|
||||
"""
|
||||
Action for adding any widget to the toolbar.
|
||||
|
||||
Args:
|
||||
label (str|None): The label for the widget.
|
||||
widget (QWidget): The widget to be added to the toolbar.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, label: str | None = None, widget: QWidget = None):
|
||||
super().__init__()
|
||||
self.label = label
|
||||
self.widget = widget
|
||||
|
||||
def add_to_toolbar(self, toolbar, target):
|
||||
widget = QWidget()
|
||||
layout = QHBoxLayout(widget)
|
||||
if self.label is not None:
|
||||
label = QLabel(f"{self.label}")
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(self.widget)
|
||||
toolbar.addWidget(widget)
|
||||
|
||||
|
||||
class ExpandableMenuAction(ToolBarAction):
|
||||
"""
|
||||
Action for an expandable menu in the toolbar.
|
||||
@@ -133,10 +202,12 @@ class ExpandableMenuAction(ToolBarAction):
|
||||
menu = QMenu(button)
|
||||
for action_id, action in self.actions.items():
|
||||
sub_action = QAction(action.tooltip, target)
|
||||
if action.icon_path:
|
||||
if hasattr(action, "icon_path"):
|
||||
icon = QIcon()
|
||||
icon.addFile(action.icon_path, size=QSize(20, 20))
|
||||
sub_action.setIcon(icon)
|
||||
elif hasattr(action, "get_icon"):
|
||||
sub_action.setIcon(action.get_icon())
|
||||
sub_action.setCheckable(action.checkable)
|
||||
menu.addAction(sub_action)
|
||||
self.widgets[action_id] = sub_action
|
||||
@@ -150,20 +221,13 @@ class ModularToolBar(QToolBar):
|
||||
parent (QWidget, optional): The parent widget of the toolbar. Defaults to None.
|
||||
actions (list[ToolBarAction], optional): A list of action creators to populate the toolbar. Defaults to None.
|
||||
target_widget (QWidget, optional): The widget that the actions will target. Defaults to None.
|
||||
color (str, optional): The background color of the toolbar. Defaults to "black".
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
actions: dict | None = None,
|
||||
target_widget=None,
|
||||
color: str = "rgba(255, 255, 255, 0)",
|
||||
):
|
||||
def __init__(self, parent=None, actions: dict | None = None, target_widget=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.widgets = defaultdict(dict)
|
||||
self.set_background_color(color)
|
||||
self.set_background_color()
|
||||
|
||||
if actions is not None and target_widget is not None:
|
||||
self.populate_toolbar(actions, target_widget)
|
||||
@@ -180,9 +244,9 @@ class ModularToolBar(QToolBar):
|
||||
action.add_to_toolbar(self, target_widget)
|
||||
self.widgets[action_id] = action
|
||||
|
||||
def set_background_color(self, color: str):
|
||||
self.setStyleSheet(f"QToolBar {{ background: {color}; }}")
|
||||
def set_background_color(self):
|
||||
self.setIconSize(QSize(20, 20))
|
||||
self.setMovable(False)
|
||||
self.setFloatable(False)
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setStyleSheet("QToolBar { background-color: rgba(0, 0, 0, 0); border: none; }")
|
||||
|
||||
@@ -6,7 +6,9 @@ import sys
|
||||
import sysconfig
|
||||
from pathlib import Path
|
||||
|
||||
from bec_qthemes import material_icon
|
||||
from qtpy import PYSIDE6
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
if PYSIDE6:
|
||||
from PySide6.scripts.pyside_tool import (
|
||||
@@ -21,6 +23,19 @@ if PYSIDE6:
|
||||
import bec_widgets
|
||||
|
||||
|
||||
def designer_material_icon(icon_name: str) -> QIcon:
|
||||
"""
|
||||
Create a QIcon for the BECDesigner with the given material icon name.
|
||||
|
||||
Args:
|
||||
icon_name (str): The name of the material icon.
|
||||
|
||||
Returns:
|
||||
QIcon: The QIcon for the material icon.
|
||||
"""
|
||||
return QIcon(material_icon(icon_name, filled=True, convert_to_pixmap=True))
|
||||
|
||||
|
||||
def list_editable_packages() -> set[str]:
|
||||
"""
|
||||
List all editable packages in the environment.
|
||||
|
||||
@@ -125,7 +125,7 @@ class BECDispatcher:
|
||||
topics: Union[EndpointInfo, str, list[Union[EndpointInfo, str]]],
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Connect widget's pyqt slot, so that it is called on new pub/sub topic message.
|
||||
"""Connect widget's qt slot, so that it is called on new pub/sub topic message.
|
||||
|
||||
Args:
|
||||
slot (Callable): A slot method/function that accepts two inputs: content and metadata of
|
||||
@@ -138,6 +138,13 @@ class BECDispatcher:
|
||||
self._slots[slot].update(set(topics_str))
|
||||
|
||||
def disconnect_slot(self, slot: Callable, topics: Union[str, list]):
|
||||
"""
|
||||
Disconnect a slot from a topic.
|
||||
|
||||
Args:
|
||||
slot(Callable): The slot to disconnect
|
||||
topics(Union[str, list]): The topic(s) to disconnect from
|
||||
"""
|
||||
# find the right slot to disconnect from ;
|
||||
# slot callbacks are wrapped in QtThreadSafeCallback objects,
|
||||
# but the slot we receive here is the original callable
|
||||
@@ -153,6 +160,12 @@ class BECDispatcher:
|
||||
del self._slots[connected_slot]
|
||||
|
||||
def disconnect_topics(self, topics: Union[str, list]):
|
||||
"""
|
||||
Disconnect all slots from a topic.
|
||||
|
||||
Args:
|
||||
topics(Union[str, list]): The topic(s) to disconnect from
|
||||
"""
|
||||
self.client.connector.unregister(topics)
|
||||
topics_str, _ = self.client.connector._convert_endpointinfo(topics)
|
||||
for slot in list(self._slots.keys()):
|
||||
@@ -162,4 +175,11 @@ class BECDispatcher:
|
||||
del self._slots[slot]
|
||||
|
||||
def disconnect_all(self, *args, **kwargs):
|
||||
"""
|
||||
Disconnect all slots from all topics.
|
||||
|
||||
Args:
|
||||
*args: Arbitrary positional arguments
|
||||
**kwargs: Arbitrary keyword arguments
|
||||
"""
|
||||
self.disconnect_topics(self.client.connector._topics_cb)
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
from qtpy.QtWidgets import QWidget
|
||||
from qtpy.QtWidgets import QApplication, QWidget
|
||||
|
||||
from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
|
||||
from bec_widgets.utils.colors import set_theme
|
||||
|
||||
|
||||
class BECWidget(BECConnector):
|
||||
"""Mixin class for all BEC widgets, to handle cleanup"""
|
||||
|
||||
# The icon name is the name of the icon in the icon theme, typically a name taken
|
||||
# from fonts.google.com/icons. Override this in subclasses to set the icon name.
|
||||
ICON_NAME = "widgets"
|
||||
|
||||
def __init__(self, client=None, config: ConnectionConfig = None, gui_id: str = None):
|
||||
if not isinstance(self, QWidget):
|
||||
raise RuntimeError(f"{repr(self)} is not a subclass of QWidget")
|
||||
super().__init__(client, config, gui_id)
|
||||
|
||||
# Set the theme to auto if it is not set yet
|
||||
app = QApplication.instance()
|
||||
if not hasattr(app, "theme"):
|
||||
set_theme("dark")
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup the widget."""
|
||||
pass
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.rpc_register.remove_rpc(self)
|
||||
|
||||
@@ -5,29 +5,71 @@ from typing import Literal
|
||||
import bec_qthemes
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from bec_qthemes._os_appearance.listener import OSThemeSwitchListener
|
||||
from pydantic_core import PydanticCustomError
|
||||
from qtpy.QtGui import QColor
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
CURRENT_THEME = "dark"
|
||||
from qtpy.QtWidgets import QApplication, QPushButton, QToolButton
|
||||
|
||||
|
||||
def get_theme_palette():
|
||||
return bec_qthemes.load_palette(CURRENT_THEME)
|
||||
if QApplication.instance() is None or not hasattr(QApplication.instance(), "theme"):
|
||||
theme = "dark"
|
||||
else:
|
||||
theme = QApplication.instance().theme["theme"]
|
||||
return bec_qthemes.load_palette(theme)
|
||||
|
||||
|
||||
def set_theme(theme: Literal["dark", "light", "auto"]):
|
||||
"""
|
||||
Set the theme for the application.
|
||||
|
||||
Args:
|
||||
theme (Literal["dark", "light", "auto"]): The theme to set. "auto" will automatically switch between dark and light themes based on the system theme.
|
||||
"""
|
||||
app = QApplication.instance()
|
||||
bec_qthemes.setup_theme(theme)
|
||||
pg.setConfigOption("background", "w" if app.theme["theme"] == "light" else "k")
|
||||
app.theme_signal.theme_updated.emit(theme)
|
||||
apply_theme(theme)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
if theme != "auto":
|
||||
return
|
||||
|
||||
def callback():
|
||||
app.theme["theme"] = listener._theme.lower()
|
||||
app.theme_signal.theme_updated.emit(app.theme["theme"])
|
||||
apply_theme(listener._theme.lower())
|
||||
|
||||
listener = OSThemeSwitchListener(callback)
|
||||
|
||||
app.installEventFilter(listener)
|
||||
|
||||
|
||||
def apply_theme(theme: Literal["dark", "light"]):
|
||||
global CURRENT_THEME
|
||||
CURRENT_THEME = theme
|
||||
|
||||
"""
|
||||
Apply the theme to all pyqtgraph widgets. Do not use this function directly. Use set_theme instead.
|
||||
"""
|
||||
app = QApplication.instance()
|
||||
# go through all pyqtgraph widgets and set background
|
||||
children = itertools.chain.from_iterable(
|
||||
top.findChildren(pg.GraphicsLayoutWidget) for top in app.topLevelWidgets()
|
||||
)
|
||||
pg.setConfigOptions(foreground="d" if theme == "dark" else "k")
|
||||
for pg_widget in children:
|
||||
pg_widget.setBackground("k" if theme == "dark" else "w")
|
||||
|
||||
dark_mode_buttons = [
|
||||
button
|
||||
for button in app.topLevelWidgets()
|
||||
if hasattr(button, "dark_mode_enabled")
|
||||
and hasattr(button, "mode_button")
|
||||
and isinstance(button.mode_button, (QPushButton, QToolButton))
|
||||
]
|
||||
|
||||
for button in dark_mode_buttons:
|
||||
button.dark_mode_enabled = theme == "dark"
|
||||
button.update_mode_button()
|
||||
# now define stylesheet according to theme and apply it
|
||||
style = bec_qthemes.load_stylesheet(theme)
|
||||
app.setStyleSheet(style)
|
||||
@@ -81,8 +123,19 @@ class Colors:
|
||||
angles = Colors.golden_ratio(len(cmap_colors))
|
||||
color_selection = np.round(np.interp(angles, (-np.pi, np.pi), (0, len(cmap_colors))))
|
||||
colors = []
|
||||
for ii in color_selection[:num]:
|
||||
color = cmap_colors[int(ii)]
|
||||
ii = 0
|
||||
while len(colors) < num:
|
||||
color_index = int(color_selection[ii])
|
||||
color = cmap_colors[color_index]
|
||||
app = QApplication.instance()
|
||||
if hasattr(app, "theme") and app.theme["theme"] == "light":
|
||||
background = 255
|
||||
else:
|
||||
background = 0
|
||||
if np.abs(np.mean(color[:3] * 255) - background) < 50:
|
||||
ii += 1
|
||||
continue
|
||||
|
||||
if format.upper() == "HEX":
|
||||
colors.append(QColor.fromRgbF(*color).name())
|
||||
elif format.upper() == "RGB":
|
||||
@@ -91,6 +144,7 @@ class Colors:
|
||||
colors.append(QColor.fromRgbF(*color))
|
||||
else:
|
||||
raise ValueError("Unsupported format. Please choose 'RGB', 'HEX', or 'QColor'.")
|
||||
ii += 1
|
||||
return colors
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
from typing import Type
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
from collections import defaultdict
|
||||
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
|
||||
# from qtpy.QtCore import QObject, pyqtSignal
|
||||
from qtpy.QtCore import QObject
|
||||
from qtpy.QtCore import QObject, Qt
|
||||
from qtpy.QtCore import Signal as pyqtSignal
|
||||
|
||||
|
||||
class Crosshair(QObject):
|
||||
positionChanged = pyqtSignal(tuple)
|
||||
positionClicked = pyqtSignal(tuple)
|
||||
# Signal for 1D plot
|
||||
coordinatesChanged1D = pyqtSignal(tuple)
|
||||
coordinatesClicked1D = pyqtSignal(tuple)
|
||||
@@ -26,10 +30,13 @@ class Crosshair(QObject):
|
||||
super().__init__(parent)
|
||||
self.is_log_y = None
|
||||
self.is_log_x = None
|
||||
self.is_derivative = None
|
||||
self.plot_item = plot_item
|
||||
self.precision = precision
|
||||
self.v_line = pg.InfiniteLine(angle=90, movable=False)
|
||||
self.v_line.skip_auto_range = True
|
||||
self.h_line = pg.InfiniteLine(angle=0, movable=False)
|
||||
self.h_line.skip_auto_range = True
|
||||
self.plot_item.addItem(self.v_line, ignoreBounds=True)
|
||||
self.plot_item.addItem(self.h_line, ignoreBounds=True)
|
||||
self.proxy = pg.SignalProxy(
|
||||
@@ -37,74 +44,75 @@ class Crosshair(QObject):
|
||||
)
|
||||
self.plot_item.scene().sigMouseClicked.connect(self.mouse_clicked)
|
||||
|
||||
self.plot_item.ctrl.derivativeCheck.checkStateChanged.connect(self.check_derivatives)
|
||||
self.plot_item.ctrl.logXCheck.checkStateChanged.connect(self.check_log)
|
||||
self.plot_item.ctrl.logYCheck.checkStateChanged.connect(self.check_log)
|
||||
|
||||
# Initialize markers
|
||||
self.marker_moved_1d = []
|
||||
self.marker_clicked_1d = []
|
||||
self.marker_moved_1d = {}
|
||||
self.marker_clicked_1d = {}
|
||||
self.marker_2d = None
|
||||
self.update_markers()
|
||||
|
||||
def update_markers(self):
|
||||
"""Update the markers for the crosshair, creating new ones if necessary."""
|
||||
|
||||
# Clear existing markers
|
||||
for marker in self.marker_moved_1d + self.marker_clicked_1d:
|
||||
self.plot_item.removeItem(marker)
|
||||
if self.marker_2d:
|
||||
self.plot_item.removeItem(self.marker_2d)
|
||||
|
||||
# Create new markers
|
||||
self.marker_moved_1d = []
|
||||
self.marker_clicked_1d = []
|
||||
self.marker_2d = None
|
||||
for item in self.plot_item.items:
|
||||
if isinstance(item, pg.PlotDataItem): # 1D plot
|
||||
if item.name() in self.marker_moved_1d:
|
||||
continue
|
||||
pen = item.opts["pen"]
|
||||
color = pen.color() if hasattr(pen, "color") else pg.mkColor(pen)
|
||||
marker_moved = pg.ScatterPlotItem(
|
||||
size=10, pen=pg.mkPen(color), brush=pg.mkBrush(None)
|
||||
)
|
||||
marker_clicked = pg.ScatterPlotItem(
|
||||
size=10, pen=pg.mkPen(None), brush=pg.mkBrush(color)
|
||||
)
|
||||
self.marker_moved_1d.append(marker_moved)
|
||||
marker_moved.skip_auto_range = True
|
||||
self.marker_moved_1d[item.name()] = marker_moved
|
||||
self.plot_item.addItem(marker_moved)
|
||||
|
||||
# Create glowing effect markers for clicked events
|
||||
marker_clicked_list = []
|
||||
for size, alpha in [(18, 64), (14, 128), (10, 255)]:
|
||||
marker_clicked = pg.ScatterPlotItem(
|
||||
size=size,
|
||||
pen=pg.mkPen(None),
|
||||
brush=pg.mkBrush(color.red(), color.green(), color.blue(), alpha),
|
||||
)
|
||||
marker_clicked_list.append(marker_clicked)
|
||||
marker_clicked.skip_auto_range = True
|
||||
self.marker_clicked_1d[item.name()] = marker_clicked
|
||||
self.plot_item.addItem(marker_clicked)
|
||||
|
||||
self.marker_clicked_1d.append(marker_clicked_list)
|
||||
elif isinstance(item, pg.ImageItem): # 2D plot
|
||||
if self.marker_2d is not None:
|
||||
continue
|
||||
self.marker_2d = pg.ROI(
|
||||
[0, 0], size=[1, 1], pen=pg.mkPen("r", width=2), movable=False
|
||||
)
|
||||
self.plot_item.addItem(self.marker_2d)
|
||||
|
||||
def snap_to_data(self, x, y) -> tuple:
|
||||
def snap_to_data(self, x, y) -> tuple[defaultdict[list], defaultdict[list]]:
|
||||
"""
|
||||
Finds the nearest data points to the given x and y coordinates.
|
||||
|
||||
Args:
|
||||
x: The x-coordinate
|
||||
y: The y-coordinate
|
||||
x: The x-coordinate of the mouse cursor
|
||||
y: The y-coordinate of the mouse cursor
|
||||
|
||||
Returns:
|
||||
tuple: The nearest x and y values
|
||||
tuple: x and y values snapped to the nearest data
|
||||
"""
|
||||
y_values_1d = []
|
||||
x_values_1d = []
|
||||
y_values = defaultdict(list)
|
||||
x_values = defaultdict(list)
|
||||
image_2d = None
|
||||
|
||||
# Iterate through items in the plot
|
||||
for item in self.plot_item.items:
|
||||
if isinstance(item, pg.PlotDataItem): # 1D plot
|
||||
x_data, y_data = item.xData, item.yData
|
||||
name = item.name()
|
||||
plot_data = item._getDisplayDataset()
|
||||
if plot_data is None:
|
||||
continue
|
||||
x_data, y_data = plot_data.x, plot_data.y
|
||||
if x_data is not None and y_data is not None:
|
||||
if self.is_log_x:
|
||||
min_x_data = np.min(x_data[x_data > 0])
|
||||
@@ -112,25 +120,25 @@ class Crosshair(QObject):
|
||||
min_x_data = np.min(x_data)
|
||||
max_x_data = np.max(x_data)
|
||||
if x < min_x_data or x > max_x_data:
|
||||
return None, None
|
||||
y_values[name] = None
|
||||
x_values[name] = None
|
||||
continue
|
||||
closest_x, closest_y = self.closest_x_y_value(x, x_data, y_data)
|
||||
y_values_1d.append(closest_y)
|
||||
x_values_1d.append(closest_x)
|
||||
y_values[name] = closest_y
|
||||
x_values[name] = closest_x
|
||||
elif isinstance(item, pg.ImageItem): # 2D plot
|
||||
name = item.config.monitor
|
||||
image_2d = item.image
|
||||
# clip the x and y values to the image dimensions to avoid out of bounds errors
|
||||
y_values[name] = int(np.clip(y, 0, image_2d.shape[1] - 1))
|
||||
x_values[name] = int(np.clip(x, 0, image_2d.shape[0] - 1))
|
||||
|
||||
# Handle 1D plot
|
||||
if y_values_1d:
|
||||
if all(v is None for v in x_values_1d) or all(v is None for v in y_values_1d):
|
||||
if x_values and y_values:
|
||||
if all(v is None for v in x_values.values()) or all(
|
||||
v is None for v in y_values.values()
|
||||
):
|
||||
return None, None
|
||||
closest_x = min(x_values_1d, key=lambda xi: abs(xi - x)) # Snap x to closest data point
|
||||
return closest_x, y_values_1d
|
||||
|
||||
# Handle 2D plot
|
||||
if image_2d is not None:
|
||||
x_idx = int(np.clip(x, 0, image_2d.shape[0] - 1))
|
||||
y_idx = int(np.clip(y, 0, image_2d.shape[1] - 1))
|
||||
return x_idx, y_idx
|
||||
return x_values, y_values
|
||||
|
||||
return None, None
|
||||
|
||||
@@ -156,8 +164,9 @@ class Crosshair(QObject):
|
||||
Args:
|
||||
event: The mouse moved event
|
||||
"""
|
||||
self.check_log()
|
||||
pos = event[0]
|
||||
self.update_markers()
|
||||
self.positionChanged.emit((pos.x(), pos.y()))
|
||||
if self.plot_item.vb.sceneBoundingRect().contains(pos):
|
||||
mouse_point = self.plot_item.vb.mapSceneToView(pos)
|
||||
self.v_line.setPos(mouse_point.x())
|
||||
@@ -168,27 +177,34 @@ class Crosshair(QObject):
|
||||
x = 10**x
|
||||
if self.is_log_y:
|
||||
y = 10**y
|
||||
x, y_values = self.snap_to_data(x, y)
|
||||
x_snap_values, y_snap_values = self.snap_to_data(x, y)
|
||||
if x_snap_values is None or y_snap_values is None:
|
||||
return
|
||||
if all(v is None for v in x_snap_values.values()) or all(
|
||||
v is None for v in y_snap_values.values()
|
||||
):
|
||||
# not sure how we got here, but just to be safe...
|
||||
return
|
||||
|
||||
for item in self.plot_item.items:
|
||||
if isinstance(item, pg.PlotDataItem):
|
||||
if x is None or all(v is None for v in y_values):
|
||||
return
|
||||
coordinate_to_emit = (
|
||||
round(x, self.precision),
|
||||
[round(y_val, self.precision) for y_val in y_values],
|
||||
)
|
||||
name = item.name()
|
||||
x, y = x_snap_values[name], y_snap_values[name]
|
||||
if x is None or y is None:
|
||||
continue
|
||||
self.marker_moved_1d[name].setData([x], [y])
|
||||
coordinate_to_emit = (name, round(x, self.precision), round(y, self.precision))
|
||||
self.coordinatesChanged1D.emit(coordinate_to_emit)
|
||||
for i, y_val in enumerate(y_values):
|
||||
self.marker_moved_1d[i].setData(
|
||||
[x if not self.is_log_x else np.log10(x)],
|
||||
[y_val if not self.is_log_y else np.log10(y_val)],
|
||||
)
|
||||
elif isinstance(item, pg.ImageItem):
|
||||
if x is None or y_values is None:
|
||||
return
|
||||
coordinate_to_emit = (x, y_values)
|
||||
name = item.config.monitor
|
||||
x, y = x_snap_values[name], y_snap_values[name]
|
||||
if x is None or y is None:
|
||||
continue
|
||||
self.marker_2d.setPos([x, y])
|
||||
coordinate_to_emit = (name, x, y)
|
||||
self.coordinatesChanged2D.emit(coordinate_to_emit)
|
||||
else:
|
||||
continue
|
||||
|
||||
def mouse_clicked(self, event):
|
||||
"""Handles the mouse clicked event, updating the crosshair position and emitting signals.
|
||||
@@ -196,40 +212,69 @@ class Crosshair(QObject):
|
||||
Args:
|
||||
event: The mouse clicked event
|
||||
"""
|
||||
self.check_log()
|
||||
|
||||
# we only accept left mouse clicks
|
||||
if event.button() != Qt.MouseButton.LeftButton:
|
||||
return
|
||||
self.update_markers()
|
||||
if self.plot_item.vb.sceneBoundingRect().contains(event._scenePos):
|
||||
mouse_point = self.plot_item.vb.mapSceneToView(event._scenePos)
|
||||
x, y = mouse_point.x(), mouse_point.y()
|
||||
self.positionClicked.emit((x, y))
|
||||
|
||||
if self.is_log_x:
|
||||
x = 10**x
|
||||
if self.is_log_y:
|
||||
y = 10**y
|
||||
x, y_values = self.snap_to_data(x, y)
|
||||
x_snap_values, y_snap_values = self.snap_to_data(x, y)
|
||||
|
||||
if x_snap_values is None or y_snap_values is None:
|
||||
return
|
||||
if all(v is None for v in x_snap_values.values()) or all(
|
||||
v is None for v in y_snap_values.values()
|
||||
):
|
||||
# not sure how we got here, but just to be safe...
|
||||
return
|
||||
|
||||
for item in self.plot_item.items:
|
||||
if isinstance(item, pg.PlotDataItem):
|
||||
if x is None or all(v is None for v in y_values):
|
||||
return
|
||||
coordinate_to_emit = (
|
||||
round(x, self.precision),
|
||||
[round(y_val, self.precision) for y_val in y_values],
|
||||
)
|
||||
name = item.name()
|
||||
x, y = x_snap_values[name], y_snap_values[name]
|
||||
if x is None or y is None:
|
||||
continue
|
||||
self.marker_clicked_1d[name].setData([x], [y])
|
||||
coordinate_to_emit = (name, round(x, self.precision), round(y, self.precision))
|
||||
self.coordinatesClicked1D.emit(coordinate_to_emit)
|
||||
for i, y_val in enumerate(y_values):
|
||||
for marker in self.marker_clicked_1d[i]:
|
||||
marker.setData(
|
||||
[x if not self.is_log_x else np.log10(x)],
|
||||
[y_val if not self.is_log_y else np.log10(y_val)],
|
||||
)
|
||||
elif isinstance(item, pg.ImageItem):
|
||||
if x is None or y_values is None:
|
||||
return
|
||||
coordinate_to_emit = (x, y_values)
|
||||
name = item.config.monitor
|
||||
x, y = x_snap_values[name], y_snap_values[name]
|
||||
if x is None or y is None:
|
||||
continue
|
||||
self.marker_2d.setPos([x, y])
|
||||
coordinate_to_emit = (name, x, y)
|
||||
self.coordinatesClicked2D.emit(coordinate_to_emit)
|
||||
self.marker_2d.setPos([x, y_values])
|
||||
else:
|
||||
continue
|
||||
|
||||
def clear_markers(self):
|
||||
"""Clears the markers from the plot."""
|
||||
for marker in self.marker_moved_1d.values():
|
||||
marker.clear()
|
||||
for marker in self.marker_clicked_1d.values():
|
||||
marker.clear()
|
||||
|
||||
def check_log(self):
|
||||
"""Checks if the x or y axis is in log scale and updates the internal state accordingly."""
|
||||
self.is_log_x = self.plot_item.ctrl.logXCheck.isChecked()
|
||||
self.is_log_y = self.plot_item.ctrl.logYCheck.isChecked()
|
||||
self.clear_markers()
|
||||
|
||||
def check_derivatives(self):
|
||||
"""Checks if the derivatives are enabled and updates the internal state accordingly."""
|
||||
self.is_derivative = self.plot_item.ctrl.derivativeCheck.isChecked()
|
||||
self.clear_markers()
|
||||
|
||||
def cleanup(self):
|
||||
self.v_line.deleteLater()
|
||||
self.h_line.deleteLater()
|
||||
self.clear_markers()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
{widget_import}
|
||||
|
||||
DOM_XML = """
|
||||
@@ -30,7 +30,7 @@ class {plugin_name_pascal}Plugin(QDesignerCustomWidgetInterface): # pragma: no
|
||||
return ""
|
||||
|
||||
def icon(self):
|
||||
return QIcon()
|
||||
return designer_material_icon({plugin_name_pascal}.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "{plugin_name_snake}"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from qtpy.QtCore import Qt, Slot
|
||||
from qtpy.QtWidgets import QHBoxLayout, QHeaderView, QTableWidget, QTableWidgetItem, QWidget
|
||||
@@ -11,6 +13,8 @@ class BECQueue(BECWidget, QWidget):
|
||||
Widget to display the BEC queue.
|
||||
"""
|
||||
|
||||
ICON_NAME = "edit_note"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: QWidget | None = None,
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.bec_queue.bec_queue import BECQueue
|
||||
|
||||
DOM_XML = """
|
||||
@@ -34,8 +34,7 @@ class BECQueuePlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
return "BEC Services"
|
||||
|
||||
def icon(self):
|
||||
icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "device_line_edit.png")
|
||||
return QIcon(icon_path)
|
||||
return designer_material_icon(BECQueue.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "bec_queue"
|
||||
|
||||
@@ -43,6 +43,8 @@ class BECServiceStatusMixin(QObject):
|
||||
|
||||
services_update = Signal(dict, dict)
|
||||
|
||||
ICON_NAME = "dns"
|
||||
|
||||
def __init__(self, parent, client: BECClient):
|
||||
super().__init__(parent)
|
||||
self.client = client
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.bec_status_box.bec_status_box import BECStatusBox
|
||||
|
||||
DOM_XML = """
|
||||
@@ -34,8 +34,7 @@ class BECStatusBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
return "BEC Services"
|
||||
|
||||
def icon(self):
|
||||
icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "status.png")
|
||||
return QIcon(icon_path)
|
||||
return designer_material_icon(BECStatusBox.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "bec_status_box"
|
||||
|
||||
0
bec_widgets/widgets/button_abort/__init__.py
Normal file
1
bec_widgets/widgets/button_abort/abort_button.pyproject
Normal file
@@ -0,0 +1 @@
|
||||
{'files': ['button_abort.py']}
|
||||
54
bec_widgets/widgets/button_abort/abort_button_plugin.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.button_abort.button_abort import AbortButton
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='AbortButton' name='abort_button'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
|
||||
class AbortButtonPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = AbortButton(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return "BEC Buttons"
|
||||
|
||||
def icon(self):
|
||||
return designer_material_icon(AbortButton.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "abort_button"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "AbortButton"
|
||||
|
||||
def toolTip(self):
|
||||
return "A button that abort the scan."
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
||||
49
bec_widgets/widgets/button_abort/button_abort.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from bec_qthemes import material_icon
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QHBoxLayout, QPushButton, QToolButton, QWidget
|
||||
|
||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
|
||||
|
||||
class AbortButton(BECWidget, QWidget):
|
||||
"""A button that abort the scan."""
|
||||
|
||||
ICON_NAME = "cancel"
|
||||
|
||||
def __init__(self, parent=None, client=None, config=None, gui_id=None, toolbar=False):
|
||||
super().__init__(client=client, config=config, gui_id=gui_id)
|
||||
QWidget.__init__(self, parent=parent)
|
||||
|
||||
self.get_bec_shortcuts()
|
||||
|
||||
self.layout = QHBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
if toolbar:
|
||||
icon = material_icon("cancel", color="#666666", filled=True)
|
||||
self.button = QToolButton(icon=icon)
|
||||
self.button.triggered.connect(self.abort_scan)
|
||||
else:
|
||||
self.button = QPushButton()
|
||||
self.button.setText("Abort")
|
||||
self.button.setStyleSheet(
|
||||
"background-color: #666666; color: white; font-weight: bold; font-size: 12px;"
|
||||
)
|
||||
self.button.clicked.connect(self.abort_scan)
|
||||
|
||||
self.layout.addWidget(self.button)
|
||||
|
||||
@SafeSlot()
|
||||
def abort_scan(
|
||||
self,
|
||||
): # , scan_id: str | None = None): #FIXME scan_id will be added when combining with Queue widget
|
||||
"""
|
||||
Abort the scan.
|
||||
|
||||
Args:
|
||||
scan_id(str|None): The scan id to abort. If None, the current scan will be aborted.
|
||||
"""
|
||||
self.queue.request_scan_abortion()
|
||||
15
bec_widgets/widgets/button_abort/register_abort_button.py
Normal file
@@ -0,0 +1,15 @@
|
||||
def main(): # pragma: no cover
|
||||
from qtpy import PYSIDE6
|
||||
|
||||
if not PYSIDE6:
|
||||
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from bec_widgets.widgets.button_abort.abort_button_plugin import AbortButtonPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(AbortButtonPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
0
bec_widgets/widgets/button_reset/__init__.py
Normal file
42
bec_widgets/widgets/button_reset/button_reset.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from bec_qthemes import material_icon
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QHBoxLayout, QPushButton, QToolButton, QWidget
|
||||
|
||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
|
||||
|
||||
class ResetButton(BECWidget, QWidget):
|
||||
"""A button that reset the scan queue."""
|
||||
|
||||
ICON_NAME = "restart_alt"
|
||||
|
||||
def __init__(self, parent=None, client=None, config=None, gui_id=None, toolbar=False):
|
||||
super().__init__(client=client, config=config, gui_id=gui_id)
|
||||
QWidget.__init__(self, parent=parent)
|
||||
|
||||
self.get_bec_shortcuts()
|
||||
|
||||
self.layout = QHBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
if toolbar:
|
||||
icon = material_icon("restart_alt", color="#F19E39", filled=True)
|
||||
self.button = QToolButton(icon=icon)
|
||||
self.button.triggered.connect(self.reset_queue)
|
||||
else:
|
||||
self.button = QPushButton()
|
||||
self.button.setText("Reset Queue")
|
||||
self.button.setStyleSheet(
|
||||
"background-color: #F19E39; color: white; font-weight: bold; font-size: 12px;"
|
||||
)
|
||||
self.button.clicked.connect(self.reset_queue)
|
||||
|
||||
self.layout.addWidget(self.button)
|
||||
|
||||
@SafeSlot()
|
||||
def reset_queue(self):
|
||||
"""Stop the scan."""
|
||||
self.queue.request_queue_reset()
|
||||
15
bec_widgets/widgets/button_reset/register_reset_button.py
Normal file
@@ -0,0 +1,15 @@
|
||||
def main(): # pragma: no cover
|
||||
from qtpy import PYSIDE6
|
||||
|
||||
if not PYSIDE6:
|
||||
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from bec_widgets.widgets.button_reset.reset_button_plugin import ResetButtonPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(ResetButtonPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
1
bec_widgets/widgets/button_reset/reset_button.pyproject
Normal file
@@ -0,0 +1 @@
|
||||
{'files': ['button_reset.py']}
|
||||
54
bec_widgets/widgets/button_reset/reset_button_plugin.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.button_reset.button_reset import ResetButton
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='ResetButton' name='reset_button'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
|
||||
class ResetButtonPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = ResetButton(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return "BEC Buttons"
|
||||
|
||||
def icon(self):
|
||||
return designer_material_icon(ResetButton.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "reset_button"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "ResetButton"
|
||||
|
||||
def toolTip(self):
|
||||
return "A button that reset the scan queue."
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
||||
0
bec_widgets/widgets/button_resume/__init__.py
Normal file
42
bec_widgets/widgets/button_resume/button_resume.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from bec_qthemes import material_icon
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QHBoxLayout, QPushButton, QToolButton, QWidget
|
||||
|
||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
|
||||
|
||||
class ResumeButton(BECWidget, QWidget):
|
||||
"""A button that continue scan queue."""
|
||||
|
||||
ICON_NAME = "resume"
|
||||
|
||||
def __init__(self, parent=None, client=None, config=None, gui_id=None, toolbar=False):
|
||||
super().__init__(client=client, config=config, gui_id=gui_id)
|
||||
QWidget.__init__(self, parent=parent)
|
||||
|
||||
self.get_bec_shortcuts()
|
||||
|
||||
self.layout = QHBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
if toolbar:
|
||||
icon = material_icon("resume", color="#2793e8", filled=True)
|
||||
self.button = QToolButton(icon=icon)
|
||||
self.button.triggered.connect(self.continue_scan)
|
||||
else:
|
||||
self.button = QPushButton()
|
||||
self.button.setText("Resume")
|
||||
self.button.setStyleSheet(
|
||||
"background-color: #2793e8; color: white; font-weight: bold; font-size: 12px;"
|
||||
)
|
||||
self.button.clicked.connect(self.continue_scan)
|
||||
|
||||
self.layout.addWidget(self.button)
|
||||
|
||||
@SafeSlot()
|
||||
def continue_scan(self):
|
||||
"""Stop the scan."""
|
||||
self.queue.request_scan_continuation()
|
||||
15
bec_widgets/widgets/button_resume/register_resume_button.py
Normal file
@@ -0,0 +1,15 @@
|
||||
def main(): # pragma: no cover
|
||||
from qtpy import PYSIDE6
|
||||
|
||||
if not PYSIDE6:
|
||||
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from bec_widgets.widgets.button_resume.resume_button_plugin import ResumeButtonPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(ResumeButtonPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
{'files': ['button_resume.py']}
|
||||
54
bec_widgets/widgets/button_resume/resume_button_plugin.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.button_resume.button_resume import ResumeButton
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='ResumeButton' name='resume_button'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
|
||||
class ResumeButtonPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = ResumeButton(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return "BEC Buttons"
|
||||
|
||||
def icon(self):
|
||||
return designer_material_icon(ResumeButton.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "resume_button"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
|
||||
def isContainer(self):
|
||||
return False
|
||||
|
||||
def isInitialized(self):
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "ResumeButton"
|
||||
|
||||
def toolTip(self):
|
||||
return "A button that continue scan queue."
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
||||
@@ -3,22 +3,52 @@ from __future__ import annotations
|
||||
from typing import Literal
|
||||
|
||||
import pyqtgraph as pg
|
||||
from qtpy.QtCore import Qt, Signal
|
||||
from qtpy.QtWidgets import QHBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
||||
|
||||
|
||||
class ColorButton(pg.ColorButton):
|
||||
class ColorButton(QWidget):
|
||||
"""
|
||||
A ColorButton that opens a dialog to select a color. Inherits from pyqtgraph.ColorButton.
|
||||
Patches event loop of the ColorDialog, if opened in another QDialog.
|
||||
"""
|
||||
|
||||
color_selected = Signal(str)
|
||||
|
||||
ICON_NAME = "colors"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def selectColor(self):
|
||||
self.origColor = self.color()
|
||||
self.colorDialog.setCurrentColor(self.color())
|
||||
self.colorDialog.open()
|
||||
self.colorDialog.exec()
|
||||
self.layout = QHBoxLayout(self)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.button = pg.ColorButton()
|
||||
self.button.setFlat(True)
|
||||
self.button.clicked.connect(self.select_color)
|
||||
self.layout.addWidget(self.button)
|
||||
|
||||
@SafeSlot()
|
||||
def select_color(self):
|
||||
self.origColor = self.button.color()
|
||||
self.button.colorDialog.setCurrentColor(self.button.color())
|
||||
self.button.colorDialog.open()
|
||||
self.button.colorDialog.exec()
|
||||
self.color_selected.emit(self.button.color().name())
|
||||
|
||||
@SafeSlot(str)
|
||||
def set_color(self, color: tuple | str):
|
||||
"""
|
||||
Set the color of the button.
|
||||
|
||||
Args:
|
||||
color(tuple|str): The color to set.
|
||||
"""
|
||||
self.button.setColor(color)
|
||||
|
||||
def get_color(self, format: Literal["RGBA", "HEX"] = "RGBA") -> tuple | str:
|
||||
"""
|
||||
@@ -31,13 +61,13 @@ class ColorButton(pg.ColorButton):
|
||||
tuple|str: The color in the specified format.
|
||||
"""
|
||||
if format == "RGBA":
|
||||
return self.color().getRgb()
|
||||
return self.button.color().getRgb()
|
||||
if format == "HEX":
|
||||
return self.color().name()
|
||||
return self.button.color().name()
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Clean up the ColorButton.
|
||||
"""
|
||||
self.colorDialog.close()
|
||||
self.colorDialog.deleteLater()
|
||||
self.button.colorDialog.close()
|
||||
self.button.colorDialog.deleteLater()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.color_button.color_button import ColorButton
|
||||
|
||||
DOM_XML = """
|
||||
@@ -31,8 +31,7 @@ class ColorButtonPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
return "BEC Buttons"
|
||||
|
||||
def icon(self):
|
||||
icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "color_button.png")
|
||||
return QIcon(icon_path)
|
||||
return designer_material_icon(ColorButton.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "color_button"
|
||||
|
||||
@@ -46,6 +46,7 @@ class ColormapSelector(QWidget):
|
||||
"""
|
||||
|
||||
colormap_changed_signal = Signal(str)
|
||||
ICON_NAME = "palette"
|
||||
|
||||
def __init__(self, parent=None, default_colormaps=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.utils.bec_designer import designer_material_icon
|
||||
from bec_widgets.widgets.colormap_selector.colormap_selector import ColormapSelector
|
||||
|
||||
DOM_XML = """
|
||||
@@ -34,8 +34,7 @@ class ColormapSelectorPlugin(QDesignerCustomWidgetInterface): # pragma: no cove
|
||||
return "BEC Buttons"
|
||||
|
||||
def icon(self):
|
||||
icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "colormap_selector.png")
|
||||
return QIcon(icon_path)
|
||||
return designer_material_icon(ColormapSelector.ICON_NAME)
|
||||
|
||||
def includeFile(self):
|
||||
return "colormap_selector"
|
||||
|
||||