orGUI 1.1.2__tar.gz → 1.2.0__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 (110) hide show
  1. {orgui-1.1.2 → orgui-1.2.0}/PKG-INFO +2 -1
  2. {orgui-1.1.2 → orgui-1.2.0}/orGUI.egg-info/PKG-INFO +2 -1
  3. {orgui-1.1.2 → orgui-1.2.0}/orGUI.egg-info/SOURCES.txt +6 -5
  4. {orgui-1.1.2 → orgui-1.2.0}/orGUI.egg-info/requires.txt +1 -0
  5. {orgui-1.1.2 → orgui-1.2.0}/orgui/__init__.py +1 -1
  6. orgui-1.2.0/orgui/app/QHKLDialog.py +83 -0
  7. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/QScanSelector.py +356 -21
  8. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/QUBCalculator.py +73 -14
  9. orgui-1.2.0/orgui/app/bgroi.py +339 -0
  10. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/orGUI.py +617 -285
  11. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/backends.py +12 -45
  12. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/beamline/P212_tools.py +25 -4
  13. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/beamline/id31_tools.py +48 -5
  14. orgui-1.2.0/orgui/backend/scans.py +159 -0
  15. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/universalScanLoader.py +8 -1
  16. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/HKLVlieg.py +114 -15
  17. {orgui-1.1.2 → orgui-1.2.0}/orgui/main.py +24 -0
  18. orgui-1.2.0/orgui/resources/icons/intersect_s1.png +0 -0
  19. orgui-1.2.0/orgui/resources/icons/intersect_s1.svg +88 -0
  20. orgui-1.2.0/orgui/resources/icons/intersect_s2.png +0 -0
  21. orgui-1.2.0/orgui/resources/icons/intersect_s2.svg +88 -0
  22. {orgui-1.1.2 → orgui-1.2.0}/pyproject.toml +1 -1
  23. orgui-1.1.2/orgui/backend/scans.py +0 -95
  24. orgui-1.1.2/orgui/resources/icons/diffractometer_v2.png +0 -0
  25. orgui-1.1.2/orgui/resources/icons/diffractometer_v2.svg +0 -1212
  26. orgui-1.1.2/orgui/resources/icons/diffractometer_v3.svg +0 -1226
  27. orgui-1.1.2/orgui/resources/icons/diffractometer_v3_norm.svg +0 -968
  28. orgui-1.1.2/orgui/resources/icons/diffractometer_v3_opt.svg +0 -5627
  29. {orgui-1.1.2 → orgui-1.2.0}/LICENSE +0 -0
  30. {orgui-1.1.2 → orgui-1.2.0}/README.rst +0 -0
  31. {orgui-1.1.2 → orgui-1.2.0}/orGUI.egg-info/dependency_links.txt +0 -0
  32. {orgui-1.1.2 → orgui-1.2.0}/orGUI.egg-info/entry_points.txt +0 -0
  33. {orgui-1.1.2 → orgui-1.2.0}/orGUI.egg-info/top_level.txt +0 -0
  34. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/ArrayTableDialog.py +0 -0
  35. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/QReflectionSelector.py +0 -0
  36. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/__init__.py +0 -0
  37. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/database.py +0 -0
  38. {orgui-1.1.2 → orgui-1.2.0}/orgui/app/qutils.py +0 -0
  39. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/__init__.py +0 -0
  40. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/beamline/ID31DiffractLinTilt.py +0 -0
  41. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/beamline/__init__.py +0 -0
  42. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/beamline/fio_reader.py +0 -0
  43. {orgui-1.1.2 → orgui-1.2.0}/orgui/backend/udefaults.py +0 -0
  44. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/__init__.py +0 -0
  45. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/util.py +0 -0
  46. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/CTRcalc.py +0 -0
  47. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/CTRopt.py +0 -0
  48. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/CTRplotutil.py +0 -0
  49. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/DetectorCalibration.py +0 -0
  50. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/ReciprocalNavigation.py +0 -0
  51. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/_CTRcalc_accel.py +0 -0
  52. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/__init__.py +0 -0
  53. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/element_data.py +0 -0
  54. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/test/__init__.py +0 -0
  55. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/test/test_CTRcalc.py +0 -0
  56. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/test/test_DetectorCalibration.py +0 -0
  57. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/test/test_HKLcalc.py +0 -0
  58. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Fe3O4(100).bul +0 -0
  59. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Pt100.bul +0 -0
  60. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Pt100_small.bul +0 -0
  61. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Pt110.bul +0 -0
  62. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Pt111.bul +0 -0
  63. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Pt310.bul +0 -0
  64. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/Pt3O4(100).bul +0 -0
  65. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/PtO(001).bul +0 -0
  66. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/PtO(010).bul +0 -0
  67. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/PtO(100).bul +0 -0
  68. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/__init__.py +0 -0
  69. {orgui-1.1.2 → orgui-1.2.0}/orgui/datautils/xrayutils/unitcells/a-PtO2(0001).bul +0 -0
  70. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/__init__.py +0 -0
  71. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/alpha.png +0 -0
  72. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/alpha.svg +0 -0
  73. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/diffractometer_v3.png +0 -0
  74. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/disable-image.png +0 -0
  75. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/disable-image.svg +0 -0
  76. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/document-nx-open.png +0 -0
  77. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/document-nx-open.svg +0 -0
  78. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/document-nx-save.png +0 -0
  79. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/document-nx-save.svg +0 -0
  80. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-all-link.png +0 -0
  81. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-all-link.svg +0 -0
  82. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-horizontal-link.png +0 -0
  83. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-horizontal-link.svg +0 -0
  84. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-no-link.png +0 -0
  85. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-no-link.svg +0 -0
  86. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-view.png +0 -0
  87. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/lattice-view.svg +0 -0
  88. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/logo.png +0 -0
  89. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/logo.svg +0 -0
  90. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/max_image.png +0 -0
  91. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/max_image.svg +0 -0
  92. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/max_image2.png +0 -0
  93. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/max_image2.svg +0 -0
  94. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/orguiicon.png +0 -0
  95. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/orguiicon.svg +0 -0
  96. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/search-image.png +0 -0
  97. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/search-image.svg +0 -0
  98. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/search-reflection.png +0 -0
  99. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/search-reflection.svg +0 -0
  100. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/search.png +0 -0
  101. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/search.svg +0 -0
  102. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/select-image.png +0 -0
  103. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/select-image.svg +0 -0
  104. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/set-reflection.png +0 -0
  105. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/set-reflection.svg +0 -0
  106. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/sum_image.png +0 -0
  107. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/sum_image.svg +0 -0
  108. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/sum_image2.png +0 -0
  109. {orgui-1.1.2 → orgui-1.2.0}/orgui/resources/icons/sum_image2.svg +0 -0
  110. {orgui-1.1.2 → orgui-1.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: orGUI
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: orGUI: Orientation and Integration with 2D detectors
5
5
  Author-email: Timo Fuchs <tfuchs@cornell.edu>
6
6
  License: MIT License
@@ -43,6 +43,7 @@ Provides-Extra: full
43
43
  Requires-Dist: qtconsole; extra == "full"
44
44
  Requires-Dist: ase; extra == "full"
45
45
  Requires-Dist: numba; extra == "full"
46
+ Requires-Dist: PyOpenGL; extra == "full"
46
47
 
47
48
 
48
49
  orGUI: Orientation and Integration with 2D detectors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: orGUI
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: orGUI: Orientation and Integration with 2D detectors
5
5
  Author-email: Timo Fuchs <tfuchs@cornell.edu>
6
6
  License: MIT License
@@ -43,6 +43,7 @@ Provides-Extra: full
43
43
  Requires-Dist: qtconsole; extra == "full"
44
44
  Requires-Dist: ase; extra == "full"
45
45
  Requires-Dist: numba; extra == "full"
46
+ Requires-Dist: PyOpenGL; extra == "full"
46
47
 
47
48
 
48
49
  orGUI: Orientation and Integration with 2D detectors
@@ -16,10 +16,12 @@ orgui.egg-info/entry_points.txt
16
16
  orgui.egg-info/requires.txt
17
17
  orgui.egg-info/top_level.txt
18
18
  orgui/app/ArrayTableDialog.py
19
+ orgui/app/QHKLDialog.py
19
20
  orgui/app/QReflectionSelector.py
20
21
  orgui/app/QScanSelector.py
21
22
  orgui/app/QUBCalculator.py
22
23
  orgui/app/__init__.py
24
+ orgui/app/bgroi.py
23
25
  orgui/app/database.py
24
26
  orgui/app/orGUI.py
25
27
  orgui/app/qutils.py
@@ -63,18 +65,17 @@ orgui/datautils/xrayutils/unitcells/a-PtO2(0001).bul
63
65
  orgui/resources/__init__.py
64
66
  orgui/resources/icons/alpha.png
65
67
  orgui/resources/icons/alpha.svg
66
- orgui/resources/icons/diffractometer_v2.png
67
- orgui/resources/icons/diffractometer_v2.svg
68
68
  orgui/resources/icons/diffractometer_v3.png
69
- orgui/resources/icons/diffractometer_v3.svg
70
- orgui/resources/icons/diffractometer_v3_norm.svg
71
- orgui/resources/icons/diffractometer_v3_opt.svg
72
69
  orgui/resources/icons/disable-image.png
73
70
  orgui/resources/icons/disable-image.svg
74
71
  orgui/resources/icons/document-nx-open.png
75
72
  orgui/resources/icons/document-nx-open.svg
76
73
  orgui/resources/icons/document-nx-save.png
77
74
  orgui/resources/icons/document-nx-save.svg
75
+ orgui/resources/icons/intersect_s1.png
76
+ orgui/resources/icons/intersect_s1.svg
77
+ orgui/resources/icons/intersect_s2.png
78
+ orgui/resources/icons/intersect_s2.svg
78
79
  orgui/resources/icons/lattice-all-link.png
79
80
  orgui/resources/icons/lattice-all-link.svg
80
81
  orgui/resources/icons/lattice-horizontal-link.png
@@ -18,6 +18,7 @@ ase
18
18
  qtconsole
19
19
  ase
20
20
  numba
21
+ PyOpenGL
21
22
 
22
23
  [speedup]
23
24
  numba
@@ -29,7 +29,7 @@ __author__ = "Timo Fuchs"
29
29
  __copyright__ = "Copyright 2020-2024 Timo Fuchs"
30
30
  __credits__ = []
31
31
  __license__ = "MIT License"
32
- __version__ = "1.1.2"
32
+ __version__ = "1.2.0"
33
33
  __maintainer__ = "Timo Fuchs"
34
34
  __email__ = "tfuchs@cornell.edu"
35
35
 
@@ -0,0 +1,83 @@
1
+ from silx.gui import qt
2
+ from . import qutils
3
+ import numpy as np
4
+ from contextlib import contextmanager
5
+
6
+ @contextmanager
7
+ def blockSignals(qobjects):
8
+ try:
9
+ for obj in qobjects:
10
+ obj.blockSignals(True)
11
+ yield
12
+ for obj in qobjects:
13
+ obj.blockSignals(False)
14
+ except TypeError:
15
+ qobject.blockSignals(True)
16
+ yield
17
+ qobject.blockSignals(False)
18
+
19
+ class HKLDialog(qt.QDialog):
20
+ sigHKLchanged = qt.pyqtSignal(np.ndarray)
21
+
22
+ def __init__(self, msg='', title='' ,parent=None):
23
+ qt.QDialog.__init__(self, parent)
24
+ self.savedParams = np.array([0.,0.,0.])
25
+ layout = qt.QVBoxLayout()
26
+ self.setWindowTitle(title)
27
+
28
+ hkl_layout = qt.QHBoxLayout()
29
+
30
+ self.hkl_editors = [qt.QDoubleSpinBox() for i in range(3)]
31
+ [h.setRange(-20000,20000) for h in self.hkl_editors]
32
+ [h.setDecimals(3) for h in self.hkl_editors]
33
+ [h.setValue(0.) for h in self.hkl_editors]
34
+ for editor, lbll in zip(self.hkl_editors, ["H:", "K:", "L:"]):
35
+ hkl_layout.addWidget(qt.QLabel(lbll))
36
+ hkl_layout.addWidget(editor)
37
+ editor.valueChanged.connect(self._onAnyHKLChanged)
38
+
39
+
40
+ self.label = qt.QLabel()
41
+ self.label.setText(msg)
42
+
43
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel | qt.QDialogButtonBox.Reset)
44
+ buttons.button(qt.QDialogButtonBox.Ok).clicked.connect(self.accept)
45
+ buttons.button(qt.QDialogButtonBox.Cancel).clicked.connect(self.onCancel)
46
+ buttons.button(qt.QDialogButtonBox.Reset).clicked.connect(self.resetParameters)
47
+
48
+ layout.addWidget(self.label)
49
+ layout.addLayout(hkl_layout)
50
+ layout.addWidget(buttons)
51
+ self.setLayout(layout)
52
+
53
+
54
+ def _onAnyHKLChanged(self):
55
+ self.sigHKLchanged.emit(self.get_hkl())
56
+
57
+ def get_hkl(self):
58
+ return np.array([h.value() for h in self.hkl_editors])
59
+
60
+ def set_hkl(self, hkl):
61
+ assert len(hkl) == 3
62
+ with blockSignals(self.hkl_editors):
63
+ for h, e in zip(hkl, self.hkl_editors):
64
+ e.setValue(h)
65
+ self.sigHKLchanged.emit(self.get_hkl())
66
+
67
+ def showEvent(self, event):
68
+ if event.spontaneous():
69
+ super().showEvent(event)
70
+ else:
71
+ self.savedParams = self.get_hkl()
72
+ super().showEvent(event)
73
+
74
+ #def hideEvent(self, event):
75
+ # self.sigHide.emit()
76
+ # super().hideEvent(event)
77
+
78
+ def resetParameters(self):
79
+ self.set_hkl(self.savedParams)
80
+
81
+ def onCancel(self):
82
+ self.resetParameters()
83
+ self.reject()
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # /*##########################################################################
3
3
  #
4
- # Copyright (c) 2020-2024 Timo Fuchs
4
+ # Copyright (c) 2020-2024 Timo Fuchs, Finn Schroeter
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  # of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +23,9 @@
23
23
  #
24
24
  # ###########################################################################*/
25
25
  __author__ = "Timo Fuchs"
26
- __copyright__ = "Copyright 2020-2024 Timo Fuchs"
26
+ __copyright__ = "Copyright 2020-2024 Timo Fuchs, Finn Schroeter"
27
27
  __license__ = "MIT License"
28
- __version__ = "1.0.0"
28
+ __version__ = "1.2.0"
29
29
  __maintainer__ = "Timo Fuchs"
30
30
  __email__ = "fuchs@physik.uni-kiel.de"
31
31
 
@@ -51,8 +51,12 @@ import traceback
51
51
 
52
52
  import warnings
53
53
  from .. import resources
54
- from ..backend import backends
54
+ from ..backend import backends, scans
55
+ from . import qutils
55
56
  from .QReflectionSelector import QReflectionAnglesDialog
57
+ from .QHKLDialog import HKLDialog
58
+ import runpy
59
+
56
60
 
57
61
  class QScanSelector(qt.QMainWindow):
58
62
  sigScanChanged = qt.pyqtSignal(object)
@@ -79,6 +83,8 @@ class QScanSelector(qt.QMainWindow):
79
83
  self.closeFileAction = qt.QAction(icons.getQIcon('close'),"Close file",self)
80
84
  self.closeFileAction.triggered.connect(self._onCloseFile)
81
85
 
86
+ self.loadBackendAction = qt.QAction("Load backend file",self)
87
+ self.loadBackendAction.triggered.connect(self._onLoadBackend)
82
88
 
83
89
  self.hdfTreeView = silx.gui.hdf5.Hdf5TreeView(self)
84
90
  self.hdfTreeView.setSortingEnabled(True)
@@ -87,6 +93,11 @@ class QScanSelector(qt.QMainWindow):
87
93
  self.hdfTreeView.setModel(self.hdf5model)
88
94
  self.hdfTreeView.setExpandsOnDoubleClick(False)
89
95
  self.hdf5model.setFileMoveEnabled(True)
96
+
97
+ #self.hdf5model.sigH5pyObjectLoaded.connect(self.__h5FileLoaded)
98
+ self.hdf5model.sigH5pyObjectRemoved.connect(self.__h5FileRemoved)
99
+ self.hdf5model.sigH5pyObjectSynchronized.connect(self.__h5FileSynchonized)
100
+
90
101
  self.__treeModelSorted = silx.gui.hdf5.NexusSortFilterProxyModel(self.hdfTreeView)
91
102
  self.__treeModelSorted.setSourceModel(self.hdf5model)
92
103
  self.__treeModelSorted.sort(0, qt.Qt.AscendingOrder)
@@ -132,11 +143,18 @@ class QScanSelector(qt.QMainWindow):
132
143
  openScanButton.clicked.connect(self._onLoadScan)
133
144
 
134
145
  btidsplit = qt.QSplitter(self)
135
- qt.QLabel("Beamtime id:",btidsplit)
146
+ qt.QLabel("Backend:",btidsplit)
136
147
  self.btid = qt.QComboBox(btidsplit)
137
- [self.btid.addItem(bt) for bt in backends.beamtimes]
148
+ [self.btid.addItem(bt) for bt in backends.fscans]
138
149
  self.btid.setCurrentText("id31_default")
139
150
 
151
+ self._selectBackendBtn = qt.QPushButton("...", btidsplit)
152
+ width = self._selectBackendBtn.fontMetrics().boundingRect(" ... ").width() + 7
153
+ height = self._selectBackendBtn.fontMetrics().boundingRect(" M ").height() + 7
154
+ self._selectBackendBtn.setMaximumWidth(width)
155
+ self._selectBackendBtn.setMaximumHeight(height)
156
+ self._selectBackendBtn.clicked.connect(self.loadBackendAction.trigger)
157
+
140
158
  self.bt_autodetect_enable = qt.QCheckBox("auto detect", btidsplit)
141
159
  self.bt_autodetect_enable.toggled.connect(lambda s : self.btid.setEnabled(not s))
142
160
  self.bt_autodetect_enable.setChecked(True)
@@ -397,9 +415,6 @@ class QScanSelector(qt.QMainWindow):
397
415
  #setroi_btn.setToolTip("Select roi location by double clicking")
398
416
  setroi_btn.setDefaultAction(self.select_roi_action)
399
417
 
400
-
401
-
402
-
403
418
  static_loc_Group = qt.QGroupBox(u"Static ROI location")
404
419
  static_loc_GroupMainVLayout = qt.QVBoxLayout()
405
420
 
@@ -428,13 +443,135 @@ class QScanSelector(qt.QMainWindow):
428
443
  static_loc_GroupMainVLayout.addWidget(static_hkl_box)
429
444
 
430
445
  static_loc_Group.setLayout(static_loc_GroupMainVLayout)
446
+
447
+
448
+
449
+ # rocking scan
450
+
451
+ rocking_integration_group = qt.QGroupBox("Rocking scan integration")
452
+
453
+ self._selectH_0_btn = qt.QPushButton("sel H_0")
454
+ #width = self._selectH_0_btn.fontMetrics().boundingRect(" ... ").width() + 7
455
+ height = self._selectH_0_btn.fontMetrics().boundingRect(" M ").height() + 7
456
+ #self._selectH_0_btn.setMaximumWidth(width)
457
+ self._selectH_0_btn.setMaximumHeight(height)
431
458
 
432
459
 
460
+ self._selectH_1_btn = qt.QPushButton("sel H_1")
461
+ #width = self._selectH_1_btn.fontMetrics().boundingRect(" ... ").width() + 7
462
+ height = self._selectH_1_btn.fontMetrics().boundingRect(" M ").height() + 7
463
+ #self._selectH_1_btn.setMaximumWidth(width)
464
+ self._selectH_1_btn.setMaximumHeight(height)
465
+
466
+
467
+ self._H_0_label = qt.QLabel("")
468
+ self._H_1_label = qt.QLabel("")
469
+
470
+
471
+ ro_panel_layout = qt.QGridLayout()
472
+ ro_panel_layout.addWidget(qt.QLabel(u"Rocking points along H(s) = H₁ 🞄 s + H₀"),0,0, 1, -1)
473
+
474
+ ro_panel_layout.addWidget(qt.QLabel("Start H_0:"),1,0)
475
+ ro_panel_layout.addWidget(self._H_0_label,1, 1, 1, 2)
476
+ ro_panel_layout.addWidget(self._selectH_0_btn, 1, 3)
477
+
478
+ ro_panel_layout.addWidget(qt.QLabel("Direction H_1:"),2,0)
479
+ ro_panel_layout.addWidget(self._H_1_label, 2, 1, 1, 2)
480
+ ro_panel_layout.addWidget(self._selectH_1_btn,2,3)
481
+
482
+ self._H_max_label = qt.QLabel("")
483
+ self.roscanMaxS = qt.QDoubleSpinBox()
484
+ self.roscanMaxS.setRange(-20000,20000)
485
+ self.roscanMaxS.setDecimals(3)
486
+ self.roscanMaxS.setValue(6.)
487
+ self.roscanMaxS.valueChanged.connect(lambda : self.sigROIChanged.emit())
488
+ self.roscanDeltaS = qt.QDoubleSpinBox()
489
+ self.roscanDeltaS.setRange(0.00000001,20000)
490
+ self.roscanDeltaS.setDecimals(5)
491
+ self.roscanDeltaS.setValue(0.1)
492
+ self.roscanDeltaS.setSingleStep(0.1)
493
+ self.roscanDeltaS.valueChanged.connect(lambda : self.sigROIChanged.emit())
494
+
495
+ maxSlayout = qt.QHBoxLayout()
496
+ maxSlayout.addWidget(qt.QLabel("Max S:"))
497
+ maxSlayout.addWidget(self.roscanMaxS)
498
+ #ro_panel_layout.addWidget(qt.QLabel("Max S:"),4,0)
499
+ #ro_panel_layout.addWidget(self.roscanMaxS, 4, 1)
500
+ #ro_panel_layout.addLayout(maxSlayout,4,0, 1, 2)
501
+
502
+ #delSlayout = qt.QHBoxLayout()
503
+ maxSlayout.addWidget(qt.QLabel("ΔS:"))
504
+ maxSlayout.addWidget(self.roscanDeltaS)
505
+ ro_panel_layout.addLayout(maxSlayout,4,0, 1, -1)
506
+ #ro_panel_layout.addWidget(qt.QLabel("ΔS:"),4,2)
507
+ #ro_panel_layout.addWidget(self.roscanDeltaS,4,3)
508
+
509
+ self.intersectgrp = qt.QActionGroup(self)
510
+ self.intersectgrp.setExclusive(True)
511
+ self.intersS1Act = self.intersectgrp.addAction(resources.getQicon("intersect_s1"), "use Ewald intersect s1")
512
+ self.intersS2Act = self.intersectgrp.addAction(resources.getQicon("intersect_s2"), "use Ewald intersect s2")
513
+ self.intersS1Act.setCheckable(True)
514
+ self.intersS2Act.setCheckable(True)
515
+
516
+ self.intersect_menu = qt.QMenu()
517
+ self.intersect_menu.addAction(self.intersS1Act)
518
+ self.intersect_menu.addAction(self.intersS2Act)
519
+
520
+ self.intersect_btn = qt.QToolButton()
521
+ self.intersect_btn.setIcon(resources.getQicon("alpha"))
522
+ self.intersect_btn.setToolTip("Set the intersect point with Ewald sphere")
523
+ self.intersect_btn.setPopupMode(qt.QToolButton.InstantPopup)
524
+ self.intersect_btn.setMenu(self.intersect_menu)
525
+
526
+ self.intersect_label = qt.QLabel("")
527
+ self.intersS1Act.triggered.connect(self._onIntersectChanged)
528
+ self.intersS2Act.triggered.connect(self._onIntersectChanged)
529
+ self.intersS1Act.trigger()
530
+
531
+ calc_HKL_roi_btn2 = qt.QToolButton()
532
+ self.roi_fromHKL_action2 = qt.QAction(resources.getQicon("search"), "Search and select correct intersect poisition", self)
533
+ self.roi_fromHKL_action2.triggered.connect(self.search_intersect_pos)
534
+ calc_HKL_roi_btn2.setDefaultAction(self.roi_fromHKL_action2)
535
+
536
+
537
+ ro_panel_layout.addWidget(qt.QLabel("Intersect:"), 3, 0)
538
+ #ro_panel_layout.addWidget(qt.QLabel("Max S:"),3,0)
539
+ ro_panel_layout.addWidget(self.intersect_label, 3, 1)
540
+ ro_panel_layout.addWidget(self.intersect_btn,3,2)
541
+ ro_panel_layout.addWidget(calc_HKL_roi_btn2,3,3)
542
+
543
+ self.autoSize_label = qt.QLabel("")
544
+ self.autoROIHsize = qt.QCheckBox("auto h")
545
+ self.autoROIVsize = qt.QCheckBox("auto v")
546
+
547
+ self.autoROIVsize.toggled.connect(lambda : self.sigROIChanged.emit())
548
+ self.autoROIHsize.toggled.connect(lambda : self.sigROIChanged.emit())
549
+
550
+ ro_panel_layout.addWidget(qt.QLabel("ROI size (hxv):"), 5, 0)
551
+ ro_panel_layout.addWidget(self.autoSize_label,5,1)
552
+ ro_panel_layout.addWidget(self.autoROIHsize,5,2)
553
+ ro_panel_layout.addWidget(self.autoROIVsize,5,3)
554
+
555
+ rocking_integration_group.setLayout(ro_panel_layout)
556
+
557
+ self.ro_H_0_dialog = HKLDialog("Select H_0: the rocking integration start HKL value", "Start HKL", self)
558
+ self.ro_H_0 = self.ro_H_0_dialog.hkl_editors
559
+ self.ro_H_0_dialog.sigHKLchanged.connect(self._on_ro_H_0_changed)
560
+ self._selectH_0_btn.clicked.connect(self.ro_H_0_dialog.exec)
561
+ self.ro_H_0_dialog.set_hkl([1.,0.,0.])
562
+
563
+ self.ro_H_1_dialog = HKLDialog("Select H_1: the rocking integration direction", "Direction HKL", self)
564
+ self.ro_H_1 = self.ro_H_1_dialog.hkl_editors
565
+ self.ro_H_1_dialog.sigHKLchanged.connect(self._on_ro_H_1_changed)
566
+ self._selectH_1_btn.clicked.connect(self.ro_H_1_dialog.exec)
567
+ self.ro_H_1_dialog.set_hkl([0.,0.,1.])
568
+
433
569
  # roi scan tab
434
570
 
435
571
  self.scanstab = qt.QTabWidget()
436
572
  self.scanstab.addTab(hklscanwidget, "hklscan")
437
573
  self.scanstab.addTab(static_loc_Group, "fixed roi loc")
574
+ self.scanstab.addTab(rocking_integration_group, "rocking scan integration")
438
575
  self.scanstab.currentChanged.connect(lambda : self.sigROIChanged.emit())
439
576
 
440
577
 
@@ -471,7 +608,33 @@ class QScanSelector(qt.QMainWindow):
471
608
 
472
609
 
473
610
  maintab.addTab(self.roiIntegrateTab,"ROI integration")
611
+
612
+ def _on_ro_H_0_changed(self, hkl):
613
+ label = "H: %s K: %s L: %s" % tuple(hkl)
614
+ self._H_0_label.setText(label)
615
+ self.sigROIChanged.emit()
474
616
 
617
+ def _on_ro_H_1_changed(self, hkl):
618
+ label = "H: %s K: %s L: %s" % tuple(hkl)
619
+ self._H_1_label.setText(label)
620
+ self.sigROIChanged.emit()
621
+
622
+ def __h5FileLoaded(self, loadedH5, filename):
623
+ return
624
+
625
+
626
+ def __h5FileRemoved(self, removedH5):
627
+ try:
628
+ removedH5.close()
629
+ except:
630
+ pass # some supported files are not open
631
+
632
+ def __h5FileSynchonized(self, removedH5, loadedH5):
633
+ try:
634
+ removedH5.close()
635
+ except:
636
+ pass # some supported files are not open
637
+
475
638
  def set_xy_static_loc(self, x, y):
476
639
  [h.blockSignals(True) for h in self.xy_static]
477
640
  self.xy_static[0].setValue(x)
@@ -480,9 +643,37 @@ class QScanSelector(qt.QMainWindow):
480
643
  self.sigROIChanged.emit()
481
644
 
482
645
  def search_hkl_static_loc(self):
483
- hkl = [h.value() for h in self.hkl_static]
484
- self.sigSearchHKL.emit(hkl)
485
-
646
+ if self.scanstab.currentIndex() == 2:
647
+ hkl = [h.value() for h in self.hkl_static1]
648
+ self.sigSearchHKL.emit(hkl)
649
+ else:
650
+ hkl = [h.value() for h in self.hkl_static]
651
+ self.sigSearchHKL.emit(hkl)
652
+
653
+ def _onIntersectChanged(self, checked):
654
+ self.intersect_btn.setIcon(self.intersectgrp.checkedAction().icon())
655
+ if self.intersS1Act.isChecked():
656
+ self.intersect_label.setText("s_1")
657
+ elif self.intersS2Act.isChecked():
658
+ self.intersect_label.setText("s_2")
659
+ else:
660
+ self.intersect_label.setText("error")
661
+ self.sigROIChanged.emit()
662
+
663
+ def search_intersect_pos(self):
664
+ hkl = [h.value() for h in self.ro_H_0]
665
+ try:
666
+ refldict = self.parentmainwindow.searchPixelCoordHKL(hkl)
667
+ except Exception as e:
668
+ qutils.warning_detailed_message(self, "Cannot calculate location of reflection", "Cannot calculate position of reflection:\n%s" % e, traceback.format_exc())
669
+ return
670
+ refl_dialog = QReflectionAnglesDialog(refldict,"Select reflection with desired intersect", self)
671
+ if qt.QDialog.Accepted == refl_dialog.exec():
672
+ for i, (cb, act) in enumerate(zip(refl_dialog.checkboxes, [self.intersS1Act, self.intersS2Act]),1):
673
+ if cb.isChecked():
674
+ act.trigger()
675
+ return
676
+
486
677
  def view_data_callback(self,obj):
487
678
  self.dataviewer.setData(obj)
488
679
  self.dataviewerDialog.open()
@@ -500,6 +691,43 @@ class QScanSelector(qt.QMainWindow):
500
691
  ddict['scanno'] = self.scannoBox.value()
501
692
  self.sigScanChanged.emit(ddict)
502
693
 
694
+ def _onLoadBackend(self):
695
+ fileTypeDict = {'Python backend files (*.py)': '.py', 'All files (*)': '' }
696
+ fileTypeFilter = ""
697
+ for f in fileTypeDict:
698
+ fileTypeFilter += f + ";;"
699
+ filename, filetype = qt.QFileDialog.getOpenFileName(self,"Open Backend file",
700
+ self.parentmainwindow.filedialogdir,
701
+ fileTypeFilter[:-2])
702
+ if filename == '':
703
+ return
704
+ self.parentmainwindow.filedialogdir = os.path.splitext(filename)[0]
705
+
706
+ try:
707
+ self.loadBackendFile(filename)
708
+ except:
709
+ qutils.warning_detailed_message(self, "Cannot load backend", "Cannot load backend", traceback.format_exc())
710
+
711
+ def loadBackendFile(self, filename):
712
+ backend_file = runpy.run_path(filename)
713
+ found_backends = []
714
+ for e in backend_file:
715
+ try:
716
+ if issubclass(backend_file[e], scans.Scan) and backend_file[e] != scans.Scan:
717
+ found_backends.append((e, backend_file[e]))
718
+ except:
719
+ pass
720
+ #traceback.print_exc()
721
+ if not found_backends:
722
+ raise ValueError("Found no backend in file %s" % filename)
723
+ if len(found_backends) > 1:
724
+ raise ValueError("Found more than one Scan class in backend file %s. Only one is permitted" % filename)
725
+ name, scancls = found_backends[0]
726
+ self.btid.addItem(name)
727
+ backends.fscans[name] = scancls
728
+ self.btid.setCurrentText(name)
729
+ self.bt_autodetect_enable.setChecked(False)
730
+
503
731
  def _onOpenFile(self):
504
732
  fileTypeDict = {'NEXUS files (*.h5 *.hdf5)': '.h5', "SPEC files (*.spec *.spc)": '.spec', 'All files (*)': '' }
505
733
  fileTypeFilter = ""
@@ -548,7 +776,7 @@ class QScanSelector(qt.QMainWindow):
548
776
  menu = event.menu()
549
777
  action = qt.QAction("Refresh", menu)
550
778
  action.triggered.connect(lambda: self.hdf5model.synchronizeH5pyObject(obj))
551
- menu.addAction(action)
779
+ #menu.addAction(action)
552
780
  #if obj.ntype is h5py.Dataset:
553
781
  action = qt.QAction("display data", menu)
554
782
  action.triggered.connect(lambda: self.view_data_callback(obj))
@@ -559,17 +787,124 @@ class QScanSelector(qt.QMainWindow):
559
787
  menu.addAction(action)
560
788
 
561
789
 
562
- def _onRefreshFile(self):
790
+ def _onRefreshFileOld(self):
563
791
  objects = list(self.hdfTreeView.selectedH5Nodes())
564
792
  if len(objects) > 0:
565
793
  obj = objects[0]
566
794
  self.hdf5model.synchronizeH5pyObject(obj)
795
+
796
+
797
+
798
+ def __getRelativePath(self, model, rootIndex, index):
799
+ """Returns a relative path from an index to his rootIndex.
800
+
801
+ If the path is empty the index is also the rootIndex.
802
+ """
803
+ path = ""
804
+ while index.isValid():
805
+ if index == rootIndex:
806
+ return path
807
+ name = model.data(index)
808
+ if path == "":
809
+ path = name
810
+ else:
811
+ path = name + "/" + path
812
+ index = index.parent()
813
+
814
+ # index is not a children of rootIndex
815
+ raise ValueError("index is not a children of the rootIndex")
816
+
817
+
818
+ def _onRefreshFile(self):
819
+ qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
820
+
821
+ selection = self.hdfTreeView.selectionModel()
822
+ indexes = selection.selectedIndexes()
823
+ if indexes == []:
824
+ qt.QApplication.restoreOverrideCursor()
825
+ qt.QMessageBox.warning(self, "No file selected", "Cannot refresh file: No file selected.")
826
+ return
827
+
828
+
829
+ model = self.hdfTreeView.model()
830
+ selectedItems = []
831
+ h5files = []
832
+ while len(indexes) > 0:
833
+ index = indexes.pop(0)
834
+ if index.column() != 0:
835
+ continue
836
+ rootIndex = index
837
+ # Reach the root of the tree
838
+ while rootIndex.parent().isValid():
839
+ rootIndex = rootIndex.parent()
840
+ rootRow = rootIndex.row()
841
+ relativePath = self.__getRelativePath(model, rootIndex, index)
842
+ selectedItems.append((rootRow, relativePath))
843
+
844
+ h5 = model.data(
845
+ rootIndex, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE
846
+ )
847
+
848
+ item = model.data(
849
+ rootIndex, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_ITEM_ROLE
850
+ )
851
+
852
+ h5files.append((h5, item._openedPath))
853
+
854
+ model = self.hdfTreeView.findHdf5TreeModel()
855
+ model.clear()
856
+ '''
857
+ import gc
858
+ for obj in gc.get_objects(): # Browse through ALL objects
859
+ if isinstance(obj, Hdf5TreeModel):
860
+ try:
861
+ obj.close()
862
+ except:
863
+ pass # Was already closed
864
+
865
+ elif isinstance(obj, silx.gui.hdf5.Hdf5TreeView):
866
+ try:
867
+ obj.close()
868
+ except:
869
+ pass # Was already closed
870
+ '''
871
+
872
+ self.createTreeView()
873
+
874
+ maintab = self.mainwidget.findChildren(qt.QTabWidget)[0]
875
+ maintab.removeTab(0)
876
+ maintab.insertTab(0,self.hdfTreeView,"NEXUS")
877
+ maintab.setCurrentIndex(0)
878
+
879
+ modelnew = self.hdfTreeView.findHdf5TreeModel()
880
+ for h5, filename in h5files:
881
+ modelnew.insertFile(filename, 0)
882
+
883
+ #self.__expandNodesFromPaths(self.hdfTreeView, index, paths)
884
+ #self.hdf5model.appendFile(filename)
885
+ qt.QApplication.restoreOverrideCursor()
886
+
887
+ def createTreeView(self):
888
+ self.hdfTreeView = silx.gui.hdf5.Hdf5TreeView(self)
889
+ self.hdfTreeView.setSortingEnabled(True)
890
+ self.hdfTreeView.addContextMenuCallback(self.nexus_treeview_callback)
891
+ self.hdf5model = Hdf5TreeModel(self.hdfTreeView,ownFiles=True)
892
+ self.hdfTreeView.setModel(self.hdf5model)
893
+ self.hdfTreeView.setExpandsOnDoubleClick(False)
894
+ self.hdf5model.setFileMoveEnabled(True)
895
+
896
+ self.hdf5model.sigH5pyObjectLoaded.connect(self.__h5FileLoaded)
897
+ self.hdf5model.sigH5pyObjectRemoved.connect(self.__h5FileRemoved)
898
+ self.hdf5model.sigH5pyObjectSynchronized.connect(self.__h5FileSynchonized)
899
+
900
+ self.__treeModelSorted = silx.gui.hdf5.NexusSortFilterProxyModel(self.hdfTreeView)
901
+ self.__treeModelSorted.setSourceModel(self.hdf5model)
902
+ self.__treeModelSorted.sort(0, qt.Qt.AscendingOrder)
903
+ self.__treeModelSorted.setSortCaseSensitivity(qt.Qt.CaseInsensitive)
904
+
905
+ self.hdfTreeView.setModel(self.__treeModelSorted)
567
906
 
568
-
569
- #if 'NX_class' in obj.ntype.attrs:
570
- # if obj.ntype.attrs['NX_class'] == 'NX_':
571
-
572
-
907
+ self.hdfTreeView.doubleClicked.connect(self._onNEXUSDoubleClicked)
573
908
 
574
909
  def getScanToolbar(self):
575
910
  return self.toolbar
@@ -647,7 +982,7 @@ class QScanSelector(qt.QMainWindow):
647
982
  dt = dateparser.parse(obj.h5py_target['start_time'][()])
648
983
  except Exception as e:
649
984
  msgbox = qt.QMessageBox(qt.QMessageBox.Critical,'Cannot open scan',
650
- 'Cannot parse start time of the scan.', qt.QMessageBox.Ok, self)
985
+ 'Cannot parse start time of the scan. Please manually select the beamtime id', qt.QMessageBox.Ok, self)
651
986
  msgbox.setDetailedText(traceback.format_exc())
652
987
  clickedbutton = msgbox.exec()
653
988
  return
@@ -664,7 +999,7 @@ class QScanSelector(qt.QMainWindow):
664
999
  else:
665
1000
  btid = self.btid.currentText()
666
1001
  try:
667
- ddict = backends.scannoConverter[btid](obj)
1002
+ ddict = backends.fscans[btid].parse_h5_node(obj)
668
1003
  except Exception as e:
669
1004
  msgbox = qt.QMessageBox(qt.QMessageBox.Critical,'Cannot open scan',
670
1005
  'Cannot parse scan number: %s' % str(e), qt.QMessageBox.Ok, self)