203 lines
6.8 KiB
Python
203 lines
6.8 KiB
Python
import re
|
|
|
|
from ..Qt import QtCore, QtWidgets
|
|
from .._py.ptstab import Ui_Form
|
|
from ..lib.pg_objects import LogInfiniteLine, RegionItem
|
|
|
|
__all__ = ['PointSelectWidget']
|
|
|
|
|
|
REGION_RE = re.compile(r'(?P<first>[+-]*\d+(?:\.\d*)*(?:[eE][+-]*\d+)*)'
|
|
r'(?: ?- ?(?P<second>[+-]*\d+(?:\.\d*)*(?:[eE][+-]*\d+)*))*')
|
|
|
|
|
|
class PointSelectWidget(QtWidgets.QWidget, Ui_Form):
|
|
widget_closed = QtCore.pyqtSignal()
|
|
points_selected = QtCore.pyqtSignal(dict, str)
|
|
point_removed = QtCore.pyqtSignal(LogInfiniteLine)
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent=parent)
|
|
self.setupUi(self)
|
|
|
|
self.pts = []
|
|
self.pts_lines = []
|
|
self.nop = 0
|
|
self._prev_pos = ''
|
|
self._last_item = None
|
|
self.connected_figure = ''
|
|
|
|
self.okButton.clicked.connect(self.apply)
|
|
self.deleteButton.clicked.connect(self.remove_points)
|
|
self.peaktable.itemChanged.connect(self.editing_finished)
|
|
self.peaktable.itemDoubleClicked.connect(self.editing_started)
|
|
|
|
def keyPressEvent(self, e):
|
|
if e.key() == QtCore.Qt.Key_Delete:
|
|
self.remove_points()
|
|
elif e.key() == QtCore.Qt.Key_F2:
|
|
self.editing_started()
|
|
else:
|
|
super().keyPressEvent(e)
|
|
|
|
def clear(self):
|
|
self.pts = []
|
|
self.nop = 0
|
|
self.peaktable.clear()
|
|
self.pts_lines = []
|
|
|
|
@QtCore.pyqtSlot(tuple, bool)
|
|
def add(self, pos: tuple, double: bool):
|
|
x = pos[0]
|
|
if double:
|
|
self.removepoint(-1)
|
|
|
|
self.pts.append((x, x*1.1))
|
|
item = RegionItem(values=[x, x*1.1], mode='mid')
|
|
item.sigRegionChanged.connect(self._update_region)
|
|
else:
|
|
self.pts.append(x)
|
|
item = LogInfiniteLine(pos=x, movable=True)
|
|
item.sigPositionChanged.connect(self._update_line)
|
|
|
|
self.pts_lines.append(item)
|
|
self.nop += 1
|
|
self._makerow()
|
|
|
|
return item
|
|
|
|
def remove_points(self):
|
|
for i in sorted(self.peaktable.selectedIndexes(), key=lambda x: x.row(), reverse=True):
|
|
self.removepoint(pos=i.row())
|
|
|
|
def removepoint(self, pos=0):
|
|
if pos == -1:
|
|
pos = len(self.pts) - 1
|
|
|
|
try:
|
|
self.pts.pop(pos)
|
|
self.nop -= 1
|
|
item = self.peaktable.takeItem(pos)
|
|
del item
|
|
|
|
del_line = self.pts_lines.pop(pos)
|
|
self.point_removed.emit(del_line)
|
|
del del_line
|
|
except IndexError:
|
|
pass
|
|
|
|
def _makerow(self):
|
|
if isinstance(self.pts[-1], tuple):
|
|
item = QtWidgets.QListWidgetItem(f'{self.pts[-1][0]:.5g} - {self.pts[-1][1]:.5g}')
|
|
else:
|
|
item = QtWidgets.QListWidgetItem(f'{self.pts[-1]:.5g}')
|
|
item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable)
|
|
self.peaktable.blockSignals(True)
|
|
self.peaktable.addItem(item)
|
|
self.peaktable.blockSignals(False)
|
|
|
|
def closeEvent(self, evt):
|
|
self.widget_closed.emit()
|
|
super().closeEvent(evt)
|
|
|
|
@QtCore.pyqtSlot()
|
|
def apply(self) -> dict:
|
|
ret_dic = {'avg_range': [self.left_pt.value(), self.right_pt.value()],
|
|
'avg_mode': {0: 'mean', 1: 'sum', 2: 'integral'}[self.average_combobox.currentIndex()],
|
|
'special': None, 'idx': None,
|
|
'xy': (self.xbutton.isChecked(), self.ybutton.isChecked())}
|
|
|
|
if self.groupBox_2.isChecked():
|
|
ret_dic['special'] = {0: 'max', 1: 'absmax', 2: 'min', 3: 'absmin'}[self.special_comboBox.currentIndex()]
|
|
|
|
if len(self.pts) != 0:
|
|
ret_dic['idx'] = self.pts
|
|
|
|
if self.graph_checkbox.isChecked():
|
|
gid = ''
|
|
else:
|
|
gid = self.graph_combobox.currentData()
|
|
|
|
self.points_selected.emit(ret_dic, gid)
|
|
|
|
return ret_dic
|
|
|
|
def _update_region(self):
|
|
try:
|
|
idx = self.pts_lines.index(self.sender())
|
|
except ValueError:
|
|
return
|
|
|
|
self.pts[idx] = self.sender().getRegion()
|
|
self.peaktable.blockSignals(True)
|
|
self.peaktable.item(idx).setText('{:.5g} - {:.5g}'.format(*self.pts[idx]))
|
|
self.peaktable.blockSignals(False)
|
|
|
|
def _update_line(self):
|
|
try:
|
|
idx = self.pts_lines.index(self.sender())
|
|
except ValueError:
|
|
return
|
|
|
|
self.pts[idx] = self.sender().value()
|
|
self.peaktable.blockSignals(True)
|
|
self.peaktable.item(idx).setText(f'{self.pts[idx]:.5g}')
|
|
self.peaktable.blockSignals(False)
|
|
|
|
@QtCore.pyqtSlot(QtWidgets.QListWidgetItem)
|
|
def editing_started(self, item=None):
|
|
if item is None:
|
|
item = self.peaktable.selectedItems()[0]
|
|
self._prev_pos = item.text()
|
|
self.peaktable.editItem(item)
|
|
|
|
@QtCore.pyqtSlot(QtWidgets.QListWidgetItem)
|
|
def editing_finished(self, it: QtWidgets.QListWidgetItem):
|
|
m = re.match(REGION_RE, it.text()).groupdict()
|
|
undo = True
|
|
if m:
|
|
start, stop = m['first'], m['second']
|
|
row = self.peaktable.row(it)
|
|
it_pts = self.pts_lines[row]
|
|
if ((stop is None) and isinstance(it_pts, RegionItem)) or \
|
|
((stop is not None) and isinstance(it_pts, LogInfiniteLine)):
|
|
QtWidgets.QMessageBox().information(self, 'Invalid type',
|
|
'Conversion between point and region is not possible.')
|
|
else:
|
|
if stop is None:
|
|
it_pts.blockSignals(True)
|
|
it_pts.setValue(float(start))
|
|
it_pts.blockSignals(False)
|
|
self.pts[row] = float(start)
|
|
else:
|
|
start, stop = float(start), float(stop)
|
|
pos = (min(start, stop), max(start, stop))
|
|
self.pts[row] = pos
|
|
self.peaktable.blockSignals(True)
|
|
it.setText(f'{pos[0]:.5g} - {pos[1]:.5g}')
|
|
self.peaktable.blockSignals(False)
|
|
it_pts.blockSignals(True)
|
|
it_pts.setRegion(pos)
|
|
it_pts.blockSignals(False)
|
|
undo = False
|
|
|
|
if undo:
|
|
self.peaktable.blockSignals(True)
|
|
it.setText(self._prev_pos)
|
|
self.peaktable.blockSignals(False)
|
|
|
|
def set_graphs(self, graphs: list):
|
|
last_graph = self.graph_combobox.currentData()
|
|
self.graph_combobox.clear()
|
|
idx = 0
|
|
for i, g in enumerate(graphs):
|
|
self.graph_combobox.addItem(g[1], userData=g[0])
|
|
if g[0] == last_graph:
|
|
idx = i
|
|
|
|
self.graph_combobox.setCurrentIndex(idx)
|
|
|
|
@QtCore.pyqtSlot(int, name='on_graph_checkbox_stateChanged')
|
|
def changed_state(self, checked):
|
|
self.graph_combobox.setEnabled(checked!=QtCore.Qt.Checked)
|