pyobs-gui 2.0.0.dev2__tar.gz → 2.0.0.dev4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/PKG-INFO +2 -2
  2. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/camerawidget.py +121 -41
  3. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/camerawidget.ui +28 -43
  4. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/camerawidget_ui.py +61 -128
  5. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/videowidget.py +5 -2
  6. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyproject.toml +2 -3
  7. pyobs_gui-2.0.0.dev4/specs/README.md +11 -0
  8. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/uv.lock +95 -116
  9. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.claude/skills/verify/SKILL.md +0 -0
  10. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.github/dependabot.yml +0 -0
  11. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.github/workflows/pypi.yml +0 -0
  12. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.github/workflows/pyrefly.yml +0 -0
  13. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.github/workflows/ruff.yml +0 -0
  14. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.pre-commit-config.yaml +0 -0
  15. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/.readthedocs.yml +0 -0
  16. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/CHANGELOG.rst +0 -0
  17. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEVELOPMENT.md +0 -0
  18. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEV_IAcquisition.md +0 -0
  19. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEV_IAutoFocus.md +0 -0
  20. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEV_IAutoGuiding.md +0 -0
  21. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEV_NavbarShortcuts.md +0 -0
  22. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEV_qml_evaluation.md +0 -0
  23. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/DEV_telescopewidget_layout.md +0 -0
  24. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/LICENSE +0 -0
  25. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/README.md +0 -0
  26. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/bin/mypyuic5 +0 -0
  27. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/docs/Makefile +0 -0
  28. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/docs/make.bat +0 -0
  29. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/docs/requirements.txt +0 -0
  30. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/docs/source/_static/pyobs.gif +0 -0
  31. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/docs/source/conf.py +0 -0
  32. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/docs/source/index.rst +0 -0
  33. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/mypy.ini +0 -0
  34. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/__init__.py +0 -0
  35. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/acquisitionwidget.py +0 -0
  36. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/autofocuswidget.py +0 -0
  37. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/autoguidingwidget.py +0 -0
  38. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/base.py +0 -0
  39. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/commandinputwidget.py +0 -0
  40. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/compassmovewidget.py +0 -0
  41. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/coolingwidget.py +0 -0
  42. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/datadisplaywidget.py +0 -0
  43. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/eventswidget.py +0 -0
  44. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/filterwidget.py +0 -0
  45. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/fitsheaderswidget.py +0 -0
  46. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/focuswidget.py +0 -0
  47. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/gui.py +0 -0
  48. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/logmodel.py +0 -0
  49. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/mainwindow.py +0 -0
  50. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/modewidget.py +0 -0
  51. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/modifiedmixin.py +0 -0
  52. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/modulegui.py +0 -0
  53. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/__init__.py +0 -0
  54. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/acquisitionwidget.ui +0 -0
  55. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/acquisitionwidget_ui.py +0 -0
  56. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/autofocuswidget.ui +0 -0
  57. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/autofocuswidget_ui.py +0 -0
  58. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/autoguidingwidget.ui +0 -0
  59. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/autoguidingwidget_ui.py +0 -0
  60. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/compassmoveplugin.py +0 -0
  61. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/compassmovewidget.py +0 -0
  62. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/compassmovewidget.ui +0 -0
  63. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/compassmovewidget_ui.py +0 -0
  64. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/compile.sh +0 -0
  65. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/coolingwidget.ui +0 -0
  66. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/coolingwidget_ui.py +0 -0
  67. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/datadisplayplugin.py +0 -0
  68. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/datadisplaywidget.ui +0 -0
  69. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/datadisplaywidget_ui.py +0 -0
  70. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/designer.sh +0 -0
  71. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/eventswidget.ui +0 -0
  72. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/eventswidget_ui.py +0 -0
  73. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/filterwidget.ui +0 -0
  74. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/filterwidget_ui.py +0 -0
  75. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/fitsheaderswidget.ui +0 -0
  76. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/fitsheaderswidget_ui.py +0 -0
  77. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/focuswidget.ui +0 -0
  78. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/focuswidget_ui.py +0 -0
  79. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/mainwindow.ui +0 -0
  80. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/mainwindow_ui.py +0 -0
  81. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/modewidget.ui +0 -0
  82. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/modewidget_ui.py +0 -0
  83. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/arrow-alt-circle-down-solid.svg +0 -0
  84. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/arrow-alt-circle-left-solid.svg +0 -0
  85. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/arrow-alt-circle-right-solid.svg +0 -0
  86. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/arrow-alt-circle-up-solid.svg +0 -0
  87. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/arrow-up-right-from-square-solid.svg +0 -0
  88. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/arrows-to-eye-solid.svg +0 -0
  89. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/chart-line-solid.svg +0 -0
  90. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/circle-question-solid.svg +0 -0
  91. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/cloud-sun-solid.svg +0 -0
  92. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/edit-solid.svg +0 -0
  93. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/search-solid.svg +0 -0
  94. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources/undo-solid.svg +0 -0
  95. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources.qrc +0 -0
  96. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/resources_rc.py +0 -0
  97. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/roofwidget.ui +0 -0
  98. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/roofwidget_ui.py +0 -0
  99. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/shellwidget.ui +0 -0
  100. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/shellwidget_ui.py +0 -0
  101. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/spectrographwidget.ui +0 -0
  102. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/spectrographwidget_ui.py +0 -0
  103. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/telescopewidget.ui +0 -0
  104. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/telescopewidget_ui.py +0 -0
  105. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/temperaturesplotwidget.ui +0 -0
  106. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/temperaturesplotwidget_ui.py +0 -0
  107. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/temperatureswidget.ui +0 -0
  108. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/temperatureswidget_ui.py +0 -0
  109. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/videowidget.ui +0 -0
  110. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/videowidget_ui.py +0 -0
  111. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/weatherwidget.ui +0 -0
  112. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/qt/weatherwidget_ui.py +0 -0
  113. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/roofwidget.py +0 -0
  114. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/shellwidget.py +0 -0
  115. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/spectrographwidget.py +0 -0
  116. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/statuswidget.py +0 -0
  117. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/telescopewidget.py +0 -0
  118. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/temperaturesplotwidget.py +0 -0
  119. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/temperatureswidget.py +0 -0
  120. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/utils.py +0 -0
  121. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/watchedlabel.py +0 -0
  122. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/pyobs_gui/weatherwidget.py +0 -0
  123. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/acquisition.yaml +0 -0
  124. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/autofocus.yaml +0 -0
  125. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/camera.yaml +0 -0
  126. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/full.yaml +0 -0
  127. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/guiding.yaml +0 -0
  128. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/mode.yaml +0 -0
  129. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/roof.yaml +0 -0
  130. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/spectrograph.yaml +0 -0
  131. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/telescope.yaml +0 -0
  132. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/telescope_acl.yaml +0 -0
  133. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/telescope_acl_denied.yaml +0 -0
  134. {pyobs_gui-2.0.0.dev2 → pyobs_gui-2.0.0.dev4}/test/video.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyobs-gui
3
- Version: 2.0.0.dev2
3
+ Version: 2.0.0.dev4
4
4
  Summary: A remote GUI for pyobs
5
5
  Author-email: Tim-Oliver Husser <thusser@uni-goettingen.de>
6
6
  License-Expression: MIT
@@ -12,7 +12,7 @@ Requires-Dist: colour<0.2,>=0.1.5
12
12
  Requires-Dist: matplotlib<4,>=3.10.1
13
13
  Requires-Dist: pyobs-core<3,>=2.0.0.dev28
14
14
  Requires-Dist: pyside6>=6.10.1
15
- Requires-Dist: qasync<0.28,>=0.27.1
15
+ Requires-Dist: qasync<0.29,>=0.27.1
16
16
  Requires-Dist: qfitswidget>=0.13.1
17
17
  Requires-Dist: qtawesome<2,>=1.4.0
18
18
  Requires-Dist: sunpy[all]>=7.0.1
@@ -17,7 +17,6 @@ from pyobs.interfaces import (
17
17
  IBinning,
18
18
  BinningState,
19
19
  IWindow,
20
- WindowState,
21
20
  IFilters,
22
21
  ICooling,
23
22
  ITemperatures,
@@ -58,13 +57,6 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
58
57
  self.exposure_time_left = 0.0
59
58
  self.exposure_progress = 0.0
60
59
 
61
- self.spinWindowLeft.init_modified(self.labelWindowLeft).committed.connect(self._window_changed)
62
- self.spinWindowTop.init_modified(self.labelWindowTop).committed.connect(self._window_changed)
63
- self.spinWindowWidth.init_modified(self.labelWindowWidth).committed.connect(self._window_changed)
64
- self.spinWindowHeight.init_modified(self.labelWindowHeight).committed.connect(self._window_changed)
65
- self.spinGain.init_modified(self.labelGain).committed.connect(self._gain_changed)
66
- self.spinGainOffset.init_modified(self.labelGain).committed.connect(self._gain_changed)
67
-
68
60
  async def open(
69
61
  self,
70
62
  modules: list[str] | None = None,
@@ -80,7 +72,7 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
80
72
  image_types = sorted([it.name for it in ImageType])
81
73
  self.comboImageType.addItems(image_types)
82
74
 
83
- # before first update, disable mys
75
+ # before first update, disable myself
84
76
  self.setEnabled(False)
85
77
 
86
78
  # hide groups, if necessary
@@ -118,10 +110,25 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
118
110
 
119
111
  async def _init(self) -> None:
120
112
  # window
113
+ window_caps = await self.comm.get_capabilities(self.module, IWindow)
114
+ if window_caps is not None:
115
+ self.spinWindowLeft.setMaximum(int(window_caps.full_frame_width))
116
+ self.spinWindowTop.setMaximum(int(window_caps.full_frame_height))
117
+ self.spinWindowWidth.setMaximum(int(window_caps.full_frame_width))
118
+ self.spinWindowHeight.setMaximum(int(window_caps.full_frame_height))
121
119
  async with self.comm.safe_proxy(self.module, IWindow) as proxy:
122
120
  if proxy is not None:
123
- await self.comm.subscribe_state(self.module, IWindow, self._update_window)
124
- await self.set_full_frame()
121
+ state = await proxy.wait_for_state(IWindow)
122
+ if state is not None:
123
+ self.spinWindowLeft.setValue(state.x)
124
+ self.spinWindowTop.setValue(state.y)
125
+ self.spinWindowWidth.setValue(state.width)
126
+ self.spinWindowHeight.setValue(state.height)
127
+ elif window_caps is not None:
128
+ self.spinWindowLeft.setValue(window_caps.full_frame_x)
129
+ self.spinWindowTop.setValue(window_caps.full_frame_y)
130
+ self.spinWindowWidth.setValue(window_caps.full_frame_width)
131
+ self.spinWindowHeight.setValue(window_caps.full_frame_height)
125
132
 
126
133
  # binning
127
134
  binning_caps = await self.comm.get_capabilities(self.module, IBinning)
@@ -129,11 +136,21 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
129
136
  binnings = [f"{b.x}x{b.y}" for b in binning_caps.binnings]
130
137
  self.comboBinning.clear()
131
138
  self.comboBinning.addItems(binnings)
132
- await self.comm.subscribe_state(self.module, IBinning, self._update_binning)
139
+ async with self.comm.safe_proxy(self.module, IBinning) as proxy:
140
+ if proxy is not None:
141
+ state = await proxy.wait_for_state(IBinning)
142
+ if state is not None:
143
+ self.comboBinning.setCurrentText(f"{state.x}x{state.y}")
144
+ await self.comm.subscribe_state(self.module, IBinning, self._update_binning)
133
145
 
134
- # gain — initial values delivered by subscription callback
135
- if await self.comm.has_proxy(self.module, IGain):
136
- await self.comm.subscribe_state(self.module, IGain, self._update_gain)
146
+ # gain
147
+ async with self.comm.safe_proxy(self.module, IGain) as proxy:
148
+ if proxy is not None:
149
+ state = await proxy.wait_for_state(IGain)
150
+ if state is not None:
151
+ self.spinGain.setValue(state.gain)
152
+ self.spinGainOffset.setValue(state.offset)
153
+ await self.comm.subscribe_state(self.module, IGain, self._update_gain)
137
154
 
138
155
  # image format
139
156
  image_format_caps = await self.comm.get_capabilities(self.module, IImageFormat)
@@ -141,38 +158,52 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
141
158
  image_formats = [ImageFormat(f) for f in image_format_caps.image_formats]
142
159
  self.comboImageFormat.clear()
143
160
  self.comboImageFormat.addItems([f.name for f in image_formats])
144
- await self.comm.subscribe_state(self.module, IImageFormat, self._update_image_format)
161
+ async with self.comm.safe_proxy(self.module, IImageFormat) as proxy:
162
+ if proxy is not None:
163
+ state = await proxy.wait_for_state(IImageFormat)
164
+ if state is not None:
165
+ self.comboImageFormat.setCurrentText(state.image_format.name)
166
+ await self.comm.subscribe_state(self.module, IImageFormat, self._update_image_format)
145
167
 
168
+ # image type
146
169
  async with self.comm.safe_proxy(self.module, IImageType) as proxy:
147
170
  if proxy is not None:
148
- await self.comm.subscribe_state(self.module, IImageType, self._update_image_type)
171
+ state = await proxy.wait_for_state(IImageType)
172
+ if state is not None:
173
+ self.comboImageType.setCurrentText(state.image_type.name)
174
+ await self.comm.subscribe_state(self.module, IImageType, self._update_image_type)
149
175
 
176
+ # exposure (status, progress, time left)
150
177
  async with self.comm.safe_proxy(self.module, IExposure) as proxy:
151
178
  if proxy is not None:
152
- await self.comm.subscribe_state(self.module, IExposure, self._update_exposure)
153
-
179
+ state = await proxy.wait_for_state(IExposure)
180
+ if state is not None:
181
+ self.exposure_status = state.status
182
+ self.exposure_progress = state.progress
183
+ self.exposure_time_left = state.exposure_time_left
184
+ await self.comm.subscribe_state(self.module, IExposure, self._update_exposure)
185
+
186
+ # exposure time
154
187
  async with self.comm.safe_proxy(self.module, IExposureTime) as proxy:
155
188
  if proxy is not None:
156
- await self.comm.subscribe_state(self.module, IExposureTime, self._update_exposure_time)
189
+ state = await proxy.wait_for_state(IExposureTime)
190
+ if state is not None:
191
+ self.spinExpTime.setValue(state.exposure_time)
192
+ await self.comm.subscribe_state(self.module, IExposureTime, self._update_exposure_time)
157
193
 
194
+ # data sequence
158
195
  if await self.comm.has_proxy(self.module, IDataSequence):
159
196
  await self.comm.subscribe_state(self.module, IDataSequence, self._update_sequence)
160
197
 
161
198
  # update GUI
162
199
  self.signal_update_gui.emit()
163
200
 
164
- def _update_window(self, state: WindowState):
165
- self.labelWindowLeft.setText(str(state.x))
166
- self.labelWindowTop.setText(str(state.y))
167
- self.labelWindowWidth.setText(str(state.width))
168
- self.labelWindowHeight.setText(str(state.height))
169
-
170
201
  def _update_binning(self, state: BinningState):
171
202
  self.comboBinning.setCurrentText(f"{state.x}x{state.y}")
172
203
 
173
204
  def _update_gain(self, state: GainState):
174
- self.labelGain.setText(str(state.gain))
175
- self.labelGainOffset.setText(str(state.offset))
205
+ self.spinGain.setValue(state.gain)
206
+ self.spinGainOffset.setValue(state.offset)
176
207
 
177
208
  def _update_image_format(self, state: ImageFormatState):
178
209
  self.comboImageFormat.setCurrentText(state.image_format.name)
@@ -194,14 +225,6 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
194
225
  self.exposures_left = state.count_left
195
226
  self.update_gui()
196
227
 
197
- @qasync.asyncSlot()
198
- async def _window_changed(self):
199
- print("ok")
200
-
201
- @qasync.asyncSlot()
202
- async def _gain_changed(self):
203
- print("ok")
204
-
205
228
  @qasync.asyncSlot() # type: ignore
206
229
  async def set_full_frame(self) -> None:
207
230
  caps = await self.comm.get_capabilities(self.module, IWindow)
@@ -247,18 +270,75 @@ class CameraWidget(BaseWidget, Ui_CameraWidget):
247
270
 
248
271
  @qasync.asyncSlot() # type: ignore
249
272
  async def expose(self) -> None:
273
+ # set binning
274
+ async with self.comm.safe_proxy(self.module, IBinning) as proxy:
275
+ if proxy is not None:
276
+ binning = int(self.comboBinning.currentText()[0])
277
+ try:
278
+ await proxy.set_binning(binning, binning)
279
+ except Exception:
280
+ log.exception("bla")
281
+ QtWidgets.QMessageBox.information(self, "Error", "Could not set binning.")
282
+ return
283
+ else:
284
+ binning = 1
285
+
286
+ # set window
287
+ async with self.comm.safe_proxy(self.module, IWindow) as proxy:
288
+ if proxy is not None:
289
+ left, top = self.spinWindowLeft.value(), self.spinWindowTop.value()
290
+ width, height = self.spinWindowWidth.value(), self.spinWindowHeight.value()
291
+ try:
292
+ await proxy.set_window(left, top, width * binning, height * binning)
293
+ except Exception:
294
+ QtWidgets.QMessageBox.information(self, "Error", "Could not set window.")
295
+ return
296
+
297
+ # set image format
298
+ async with self.comm.safe_proxy(self.module, IImageFormat) as proxy:
299
+ if proxy is not None:
300
+ image_format = ImageFormat[self.comboImageFormat.currentText()]
301
+ await proxy.set_image_format(image_format)
302
+
303
+ # set exposure time
304
+ async with self.comm.safe_proxy(self.module, IExposureTime) as proxy:
305
+ if proxy is not None:
306
+ # get exp_time
307
+ exp_time = self.spinExpTime.value()
308
+
309
+ # unit
310
+ if self.comboExpTimeUnit.currentText() == "ms":
311
+ exp_time /= 1e3
312
+ elif self.comboExpTimeUnit.currentText() == "µs":
313
+ exp_time /= 1e6
314
+
315
+ # set it
316
+ await proxy.set_exposure_time(exp_time)
317
+
318
+ # set gain and offset
319
+ async with self.comm.safe_proxy(self.module, IGain) as proxy:
320
+ if proxy is not None:
321
+ await proxy.set_gain(self.spinGain.value())
322
+ await proxy.set_offset(self.spinGainOffset.value())
323
+
324
+ # set image type
325
+ image_type = ImageType.OBJECT
326
+ async with self.comm.safe_proxy(self.module, IImageType) as proxy:
327
+ if proxy is not None:
328
+ image_type = ImageType(self.comboImageType.currentText().lower())
329
+ await proxy.set_image_type(image_type)
330
+
331
+ # set initial image count
332
+ self.exposures_left = self.spinCount.value()
250
333
  broadcast = self.checkBroadcast.isChecked()
251
- count = self.spinCount.value()
252
334
 
253
- # if the module can grab a counted sequence server-side, let it -- progress comes
254
- # back via the DataSequenceState subscription
335
+ # if the module can grab a counted sequence server-side, let it
255
336
  async with self.comm.safe_proxy(self.module, IDataSequence) as proxy:
256
337
  if proxy is not None:
257
- await proxy.grab_sequence(count, broadcast)
338
+ await proxy.grab_sequence(self.exposures_left, broadcast)
258
339
  return
259
340
 
260
341
  # fall back to a client-side loop for modules that don't support IDataSequence
261
- self.exposures_left = count
262
342
  while self.exposures_left > 0:
263
343
  await self.datadisplay.grab_data(broadcast)
264
344
  self.exposures_left -= 1
@@ -33,7 +33,7 @@
33
33
  <rect>
34
34
  <x>0</x>
35
35
  <y>0</y>
36
- <width>238</width>
36
+ <width>239</width>
37
37
  <height>748</height>
38
38
  </rect>
39
39
  </property>
@@ -64,7 +64,7 @@
64
64
  </widget>
65
65
  </item>
66
66
  <item row="2" column="2">
67
- <widget class="ModifiedSpinBox" name="spinWindowWidth">
67
+ <widget class="QSpinBox" name="spinWindowWidth">
68
68
  <property name="minimum">
69
69
  <number>1</number>
70
70
  </property>
@@ -74,7 +74,7 @@
74
74
  </widget>
75
75
  </item>
76
76
  <item row="0" column="2">
77
- <widget class="ModifiedSpinBox" name="spinWindowLeft">
77
+ <widget class="QSpinBox" name="spinWindowLeft">
78
78
  <property name="maximum">
79
79
  <number>9999</number>
80
80
  </property>
@@ -109,14 +109,14 @@
109
109
  </widget>
110
110
  </item>
111
111
  <item row="1" column="2">
112
- <widget class="ModifiedSpinBox" name="spinWindowTop">
112
+ <widget class="QSpinBox" name="spinWindowTop">
113
113
  <property name="maximum">
114
114
  <number>9999</number>
115
115
  </property>
116
116
  </widget>
117
117
  </item>
118
118
  <item row="3" column="2">
119
- <widget class="ModifiedSpinBox" name="spinWindowHeight">
119
+ <widget class="QSpinBox" name="spinWindowHeight">
120
120
  <property name="minimum">
121
121
  <number>1</number>
122
122
  </property>
@@ -126,54 +126,54 @@
126
126
  </widget>
127
127
  </item>
128
128
  <item row="0" column="1">
129
- <widget class="WatchedLabel" name="labelWindowLeft">
129
+ <widget class="QLabel" name="labelWindowLeft">
130
130
  <property name="frameShape">
131
- <enum>QFrame::Shape::NoFrame</enum>
131
+ <enum>QFrame::Shape::Box</enum>
132
132
  </property>
133
133
  <property name="text">
134
134
  <string>-</string>
135
135
  </property>
136
136
  <property name="alignment">
137
- <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
137
+ <set>Qt::AlignmentFlag::AlignCenter</set>
138
138
  </property>
139
139
  </widget>
140
140
  </item>
141
141
  <item row="1" column="1">
142
- <widget class="WatchedLabel" name="labelWindowTop">
142
+ <widget class="QLabel" name="labelWindowTop">
143
143
  <property name="frameShape">
144
- <enum>QFrame::Shape::NoFrame</enum>
144
+ <enum>QFrame::Shape::Box</enum>
145
145
  </property>
146
146
  <property name="text">
147
147
  <string>-</string>
148
148
  </property>
149
149
  <property name="alignment">
150
- <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
150
+ <set>Qt::AlignmentFlag::AlignCenter</set>
151
151
  </property>
152
152
  </widget>
153
153
  </item>
154
154
  <item row="2" column="1">
155
- <widget class="WatchedLabel" name="labelWindowWidth">
155
+ <widget class="QLabel" name="labelWindowWidth">
156
156
  <property name="frameShape">
157
- <enum>QFrame::Shape::NoFrame</enum>
157
+ <enum>QFrame::Shape::Box</enum>
158
158
  </property>
159
159
  <property name="text">
160
160
  <string>-</string>
161
161
  </property>
162
162
  <property name="alignment">
163
- <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
163
+ <set>Qt::AlignmentFlag::AlignCenter</set>
164
164
  </property>
165
165
  </widget>
166
166
  </item>
167
167
  <item row="3" column="1">
168
- <widget class="WatchedLabel" name="labelWindowHeight">
168
+ <widget class="QLabel" name="labelWindowHeight">
169
169
  <property name="frameShape">
170
- <enum>QFrame::Shape::NoFrame</enum>
170
+ <enum>QFrame::Shape::Box</enum>
171
171
  </property>
172
172
  <property name="text">
173
173
  <string>-</string>
174
174
  </property>
175
175
  <property name="alignment">
176
- <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
176
+ <set>Qt::AlignmentFlag::AlignCenter</set>
177
177
  </property>
178
178
  </widget>
179
179
  </item>
@@ -248,7 +248,7 @@
248
248
  </widget>
249
249
  </item>
250
250
  <item row="0" column="2">
251
- <widget class="ModifiedSpinBox" name="spinGain">
251
+ <widget class="QSpinBox" name="spinGain">
252
252
  <property name="minimum">
253
253
  <number>1</number>
254
254
  </property>
@@ -258,9 +258,9 @@
258
258
  </widget>
259
259
  </item>
260
260
  <item row="1" column="2">
261
- <widget class="ModifiedSpinBox" name="spinGainOffset">
261
+ <widget class="QSpinBox" name="spinGainOffset">
262
262
  <property name="minimum">
263
- <number>0</number>
263
+ <number>1</number>
264
264
  </property>
265
265
  <property name="maximum">
266
266
  <number>9999</number>
@@ -268,28 +268,28 @@
268
268
  </widget>
269
269
  </item>
270
270
  <item row="0" column="1">
271
- <widget class="WatchedLabel" name="labelGain">
271
+ <widget class="QLabel" name="labelGain">
272
272
  <property name="frameShape">
273
- <enum>QFrame::Shape::NoFrame</enum>
273
+ <enum>QFrame::Shape::Box</enum>
274
274
  </property>
275
275
  <property name="text">
276
276
  <string>-</string>
277
277
  </property>
278
278
  <property name="alignment">
279
- <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
279
+ <set>Qt::AlignmentFlag::AlignCenter</set>
280
280
  </property>
281
281
  </widget>
282
282
  </item>
283
283
  <item row="1" column="1">
284
- <widget class="WatchedLabel" name="labelGainOffset">
284
+ <widget class="QLabel" name="labelGainOffset">
285
285
  <property name="frameShape">
286
- <enum>QFrame::Shape::NoFrame</enum>
286
+ <enum>QFrame::Shape::Box</enum>
287
287
  </property>
288
288
  <property name="text">
289
289
  <string>-</string>
290
290
  </property>
291
291
  <property name="alignment">
292
- <set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
292
+ <set>Qt::AlignmentFlag::AlignCenter</set>
293
293
  </property>
294
294
  </widget>
295
295
  </item>
@@ -312,7 +312,7 @@
312
312
  <item row="0" column="2">
313
313
  <layout class="QHBoxLayout" name="layoutExpTime" stretch="1,0">
314
314
  <item>
315
- <widget class="ModifiedDoubleSpinBox" name="spinExpTime">
315
+ <widget class="QDoubleSpinBox" name="spinExpTime">
316
316
  <property name="suffix">
317
317
  <string/>
318
318
  </property>
@@ -352,7 +352,7 @@
352
352
  </layout>
353
353
  </item>
354
354
  <item row="0" column="1">
355
- <widget class="WatchedLabel" name="labelExpTime">
355
+ <widget class="QLabel" name="labelExpTime">
356
356
  <property name="frameShape">
357
357
  <enum>QFrame::Shape::Box</enum>
358
358
  </property>
@@ -1378,21 +1378,6 @@
1378
1378
  <extends>QWidget</extends>
1379
1379
  <header>..datadisplaywidget</header>
1380
1380
  </customwidget>
1381
- <customwidget>
1382
- <class>WatchedLabel</class>
1383
- <extends>QLabel</extends>
1384
- <header>..watchedlabel</header>
1385
- </customwidget>
1386
- <customwidget>
1387
- <class>ModifiedSpinBox</class>
1388
- <extends>QSpinBox</extends>
1389
- <header>..modifiedmixin</header>
1390
- </customwidget>
1391
- <customwidget>
1392
- <class>ModifiedDoubleSpinBox</class>
1393
- <extends>QDoubleSpinBox</extends>
1394
- <header>..modifiedmixin</header>
1395
- </customwidget>
1396
1381
  </customwidgets>
1397
1382
  <tabstops>
1398
1383
  <tabstop>scrollArea</tabstop>