first objects added
This commit is contained in:
parent
8e2fdcef4c
commit
793786fda8
249
src/gui_qt/graphs/draw_inputs.py
Normal file
249
src/gui_qt/graphs/draw_inputs.py
Normal file
@ -0,0 +1,249 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from gui_qt.lib.delegates import ColorListEditor
|
||||
|
||||
|
||||
class ObjectWidget(QtWidgets.QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.layout = QtWidgets.QGridLayout()
|
||||
self.layout.setContentsMargins(3, 3, 3, 3)
|
||||
|
||||
self.color_label = QtWidgets.QLabel('Color')
|
||||
self.layout.addWidget(self.color_label, 0, 0, 1, 1)
|
||||
self.color_box = ColorListEditor(self)
|
||||
self.layout.addWidget(self.color_box, 0, 1, 1, 2)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def collect_args(self) -> dict:
|
||||
return {'color': self.color_box.currentData(QtCore.Qt.UserRole)}
|
||||
|
||||
@staticmethod
|
||||
def parse_point(x_widget: QtWidgets.QLineEdit, y_widget: QtWidgets.QLineEdit) -> None | tuple[float, float]:
|
||||
x = x_widget.text()
|
||||
if not x:
|
||||
return
|
||||
y = y_widget.text()
|
||||
if not y:
|
||||
return
|
||||
|
||||
try:
|
||||
return float(x), float(y)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
|
||||
class LineWidget(ObjectWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.pos_label = QtWidgets.QLabel('Position')
|
||||
self.layout.addWidget(self.pos_label, 1, 0, 1, 1)
|
||||
self.pos_lineedit = QtWidgets.QLineEdit()
|
||||
self.pos_lineedit.setValidator(QtGui.QDoubleValidator())
|
||||
self.layout.addWidget(self.pos_lineedit, 1, 1, 1, 2)
|
||||
|
||||
self.orientation_label = QtWidgets.QLabel('Orientation')
|
||||
self.layout.addWidget(self.orientation_label, 2, 0, 1, 1)
|
||||
self.orient_combobox = QtWidgets.QComboBox()
|
||||
self.orient_combobox.addItems(['Horizontal', 'Vertical'])
|
||||
self.layout.addWidget(self.orient_combobox, 2, 1, 1, 2)
|
||||
self.layout.setRowStretch(3, 1)
|
||||
|
||||
def collect_args(self):
|
||||
dic = super().collect_args()
|
||||
pos = self.pos_lineedit.text()
|
||||
if not pos:
|
||||
return
|
||||
|
||||
try:
|
||||
dic['pos'] = float(pos)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
dic['angle'] = self.orient_combobox.currentIndex() * 90
|
||||
|
||||
return dic
|
||||
|
||||
|
||||
class MultiPointWidget(ObjectWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.loop_checkbox = QtWidgets.QCheckBox('Close loop')
|
||||
self.layout.addWidget(self.loop_checkbox, 1, 0, 1, 3)
|
||||
|
||||
self.table_widget = QtWidgets.QTableWidget()
|
||||
self.table_widget.setColumnCount(2)
|
||||
self.table_widget.setHorizontalHeaderLabels(['x', 'y'])
|
||||
header = self.table_widget.horizontalHeader()
|
||||
header.setStretchLastSection(True)
|
||||
self.layout.addWidget(self.table_widget, 2, 0, 1, 3)
|
||||
|
||||
self.addButton = QtWidgets.QPushButton('Add point')
|
||||
self.layout.addWidget(self.addButton, 3, 1, 1, 1)
|
||||
self.layout.setRowStretch(3, 1)
|
||||
self.addButton.clicked.connect(self.new_point)
|
||||
|
||||
self.removeButton = QtWidgets.QPushButton('Remove point')
|
||||
self.layout.addWidget(self.removeButton, 3, 2, 1, 1)
|
||||
self.layout.setRowStretch(3, 1)
|
||||
self.removeButton.clicked.connect(self.less_point)
|
||||
|
||||
def new_point(self, _):
|
||||
row = self.table_widget.rowCount()
|
||||
self.table_widget.setRowCount(row+1)
|
||||
placeholder = ['x', 'y']
|
||||
for column in range(2):
|
||||
line_edit = QtWidgets.QLineEdit()
|
||||
line_edit.setFrame(False)
|
||||
line_edit.setPlaceholderText(placeholder[column])
|
||||
line_edit.setValidator(QtGui.QDoubleValidator())
|
||||
|
||||
self.table_widget.setCellWidget(row, column, line_edit)
|
||||
|
||||
def less_point(self, _):
|
||||
self.table_widget.removeRow(self.table_widget.rowCount()-1)
|
||||
|
||||
def collect_args(self):
|
||||
dic = super().collect_args()
|
||||
|
||||
pts = []
|
||||
if self.table_widget.rowCount() <= 1:
|
||||
return
|
||||
|
||||
for row in range(self.table_widget.rowCount()):
|
||||
next_pt = self.parse_point(self.table_widget.cellWidget(row, 0), self.table_widget.cellWidget(row, 1))
|
||||
if next_pt is None:
|
||||
return
|
||||
pts.append(next_pt)
|
||||
|
||||
if pts:
|
||||
dic['pts'] = pts
|
||||
dic['closed'] = self.loop_checkbox.isChecked()
|
||||
return dic
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
class RectangleWidget(ObjectWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.leftbottom_label = QtWidgets.QLabel('Lower left')
|
||||
self.layout.addWidget(self.leftbottom_label, 1, 0, 1, 1)
|
||||
self.left_x = QtWidgets.QLineEdit()
|
||||
self.left_x.setPlaceholderText('x')
|
||||
self.layout.addWidget(self.left_x, 1, 1, 1, 1)
|
||||
self.left_y = QtWidgets.QLineEdit()
|
||||
self.left_y.setPlaceholderText('y')
|
||||
self.left_x.setValidator(QtGui.QDoubleValidator())
|
||||
self.left_y.setValidator(QtGui.QDoubleValidator())
|
||||
self.layout.addWidget(self.left_y, 1, 2, 1, 1)
|
||||
|
||||
self.righttop_label = QtWidgets.QLabel('Upper right')
|
||||
self.layout.addWidget(self.righttop_label, 2, 0, 1, 1)
|
||||
self.right_x = QtWidgets.QLineEdit()
|
||||
self.right_x.setPlaceholderText('x')
|
||||
self.layout.addWidget(self.right_x, 2, 1, 1, 1)
|
||||
self.right_y = QtWidgets.QLineEdit()
|
||||
self.right_y.setPlaceholderText('y')
|
||||
self.right_x.setValidator(QtGui.QDoubleValidator())
|
||||
self.right_y.setValidator(QtGui.QDoubleValidator())
|
||||
self.layout.addWidget(self.right_y, 2, 2, 1, 1)
|
||||
|
||||
self.layout.setRowStretch(3, 1)
|
||||
|
||||
def collect_args(self):
|
||||
dic = super().collect_args()
|
||||
left = self.parse_point(self.left_x, self.left_y)
|
||||
if left is None:
|
||||
return
|
||||
dic['left'] = left
|
||||
|
||||
right = self.parse_point(self.right_x, self.right_y)
|
||||
if right is None:
|
||||
return
|
||||
dic['right'] = right
|
||||
|
||||
return dic
|
||||
|
||||
|
||||
class EllipseWidget(ObjectWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.centre_label = QtWidgets.QLabel('Centre')
|
||||
self.layout.addWidget(self.centre_label, 1, 0, 1, 1)
|
||||
self.centre_x = QtWidgets.QLineEdit()
|
||||
self.centre_x.setPlaceholderText('x')
|
||||
self.layout.addWidget(self.centre_x, 1, 1, 1, 1)
|
||||
self.centre_y = QtWidgets.QLineEdit()
|
||||
self.centre_y.setPlaceholderText('y')
|
||||
self.centre_x.setValidator(QtGui.QDoubleValidator())
|
||||
self.centre_y.setValidator(QtGui.QDoubleValidator())
|
||||
self.layout.addWidget(self.centre_y, 1, 2, 1, 1)
|
||||
|
||||
self.axes_label = QtWidgets.QLabel('Axes')
|
||||
self.layout.addWidget(self.axes_label, 2, 0, 1, 1)
|
||||
self.width = QtWidgets.QLineEdit()
|
||||
self.width.setPlaceholderText('width')
|
||||
self.layout.addWidget(self.width, 2, 1, 1, 1)
|
||||
self.height = QtWidgets.QLineEdit()
|
||||
self.height.setPlaceholderText('Height')
|
||||
self.width.setValidator(QtGui.QDoubleValidator())
|
||||
self.width.setValidator(QtGui.QDoubleValidator())
|
||||
self.layout.addWidget(self.height, 2, 2, 1, 1)
|
||||
|
||||
self.layout.setRowStretch(3, 1)
|
||||
|
||||
def collect_args(self):
|
||||
dic = super().collect_args()
|
||||
centre = self.parse_point(self.centre_x, self.centre_y)
|
||||
if centre is None:
|
||||
return
|
||||
dic['centre'] = centre
|
||||
|
||||
axes = self.parse_point(self.width, self.height)
|
||||
if axes is None:
|
||||
return
|
||||
dic['axes'] = axes
|
||||
|
||||
return dic
|
||||
|
||||
|
||||
class TextWidget(ObjectWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.centre_label = QtWidgets.QLabel('Centre')
|
||||
self.layout.addWidget(self.centre_label, 1, 0, 1, 1)
|
||||
self.centre_x = QtWidgets.QLineEdit()
|
||||
self.centre_x.setPlaceholderText('x')
|
||||
self.layout.addWidget(self.centre_x, 1, 1, 1, 1)
|
||||
self.centre_y = QtWidgets.QLineEdit()
|
||||
self.centre_y.setPlaceholderText('y')
|
||||
self.centre_x.setValidator(QtGui.QDoubleValidator())
|
||||
self.centre_y.setValidator(QtGui.QDoubleValidator())
|
||||
self.layout.addWidget(self.centre_y, 1, 2, 1, 1)
|
||||
|
||||
self.text_label = QtWidgets.QLabel('Text')
|
||||
self.layout.addWidget(self.text_label, 2, 0, 1, 1)
|
||||
self.text_lineedit =QtWidgets.QLineEdit()
|
||||
self.layout.addWidget(self.text_lineedit, 2, 1, 1, 2)
|
||||
|
||||
self.layout.setRowStretch(3, 1)
|
||||
|
||||
def collect_args(self):
|
||||
dic = super().collect_args()
|
||||
centre = self.parse_point(self.centre_x, self.centre_y)
|
||||
if centre is None:
|
||||
return
|
||||
dic['centre'] = centre
|
||||
|
||||
dic['text'] = self.text_lineedit.text()
|
||||
|
||||
return dic
|
41
src/gui_qt/graphs/draw_objects.py
Normal file
41
src/gui_qt/graphs/draw_objects.py
Normal file
@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from pyqtgraph import mkPen
|
||||
|
||||
from gui_qt.lib.pg_objects import LogInfiniteLine, PlotItem
|
||||
|
||||
|
||||
class LineObject:
|
||||
def __init__(self, **kwargs):
|
||||
self.id = str(uuid.uuid4())
|
||||
|
||||
self.pos = kwargs['pos']
|
||||
self.angle = kwargs['angle']
|
||||
self.color = kwargs['color']
|
||||
|
||||
self.drawing = LogInfiniteLine(pos=self.pos, angle=self.angle, pen=mkPen(color=self.color.rgb()))
|
||||
|
||||
def __str__(self):
|
||||
return f'{"x" if self.angle==90 else "y"}={self.pos}'
|
||||
|
||||
|
||||
class MultipointObject:
|
||||
def __init__(self, **kwargs):
|
||||
self.id = str(uuid.uuid4())
|
||||
|
||||
self.color = kwargs['color']
|
||||
x, y = zip(*kwargs['pts'])
|
||||
self.closed = kwargs['closed']
|
||||
|
||||
if self.closed:
|
||||
x += (x[0],)
|
||||
y += (y[0],)
|
||||
self._x = x
|
||||
self._y = y
|
||||
|
||||
self.drawing = PlotItem(x=self._x, y=self._y, pen=mkPen(color=self.color.rgb()))
|
||||
|
||||
def __str__(self):
|
||||
return f'{len(self._y)-int(self.closed)}-pts'
|
@ -1,5 +1,9 @@
|
||||
from ..Qt import QtWidgets, QtCore
|
||||
from .._py.guidelinewidget import Ui_Form
|
||||
from __future__ import annotations
|
||||
|
||||
from gui_qt.Qt import QtWidgets, QtCore
|
||||
from gui_qt._py.guidelinewidget import Ui_Form
|
||||
from gui_qt.graphs.draw_inputs import EllipseWidget, LineWidget, MultiPointWidget, RectangleWidget, TextWidget
|
||||
from gui_qt.graphs.draw_objects import LineObject, MultipointObject
|
||||
|
||||
|
||||
class DrawingsWidget(QtWidgets.QWidget, Ui_Form):
|
||||
@ -7,13 +11,25 @@ class DrawingsWidget(QtWidgets.QWidget, Ui_Form):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.connected_figure=None
|
||||
|
||||
self.setupUi(self)
|
||||
|
||||
def __call__(self, graphs):
|
||||
for gid, name in graphs:
|
||||
self.graph_comboBox.addItem(name, userData=gid)
|
||||
self.widgets = [LineWidget(self), MultiPointWidget(self), TextWidget(self), RectangleWidget(self), EllipseWidget(self)]
|
||||
for w in self.widgets:
|
||||
self.stackedWidget.addWidget(w)
|
||||
|
||||
self.graphs = None
|
||||
|
||||
def update_tree(self):
|
||||
for gid, windows in self.graphs.items():
|
||||
item = QtWidgets.QTreeWidgetItem([windows.title])
|
||||
item.setData(0, QtCore.Qt.UserRole, gid)
|
||||
|
||||
for d in windows.drawings.values():
|
||||
child = QtWidgets.QTreeWidgetItem([d])
|
||||
item.addChild(child)
|
||||
|
||||
self.treeWidget_2.addTopLevelItem(item)
|
||||
# self.graph_comboBox.addItem(name, userData=gid)
|
||||
|
||||
def clear(self):
|
||||
self.graph_comboBox.clear()
|
||||
@ -22,140 +38,33 @@ class DrawingsWidget(QtWidgets.QWidget, Ui_Form):
|
||||
def change_draw_type(self, idx: int):
|
||||
self.stackedWidget.setCurrentIndex(idx)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
self.lines = {}
|
||||
self.comments = {}
|
||||
|
||||
self.vh_pos_lineEdit.setValidator(QtGui.QDoubleValidator())
|
||||
|
||||
self.tableWidget.installEventFilter(self)
|
||||
|
||||
@QtCore.pyqtSlot(name='on_pushButton_clicked')
|
||||
def make_line(self):
|
||||
invalid = True
|
||||
|
||||
idx = self.mode_comboBox.currentIndex()
|
||||
try:
|
||||
pos = float(self.vh_pos_lineEdit.text())
|
||||
# Vertical: idx=0; horizontal: idx = 1
|
||||
angle = 90*abs(1-idx)
|
||||
invalid = False
|
||||
except ValueError:
|
||||
pos = None
|
||||
angle = None
|
||||
pass
|
||||
|
||||
if invalid:
|
||||
QtWidgets.QMessageBox().information(self, 'Invalid input', 'Input is not a valid number')
|
||||
@QtCore.pyqtSlot(name='on_pushButton_3_clicked')
|
||||
def make_drawing(self):
|
||||
dic = self.stackedWidget.currentWidget().collect_args()
|
||||
if dic is None:
|
||||
QtWidgets.QMessageBox.information(self, 'Not working', 'Something is missing to create this object')
|
||||
return
|
||||
idx = self.treeWidget_2.selectedIndexes()
|
||||
if idx:
|
||||
item = self.treeWidget_2.itemFromIndex(idx[0])
|
||||
graph_id = item.data(0, QtCore.Qt.UserRole)
|
||||
if self.mode_comboBox.currentIndex() == 0:
|
||||
new_obj = LineObject(**dic)
|
||||
elif self.mode_comboBox.currentIndex() == 1:
|
||||
new_obj = MultipointObject(**dic)
|
||||
child = QtWidgets.QTreeWidgetItem([str(new_obj)])
|
||||
child.setData(0, QtCore.Qt.UserRole, new_obj.id)
|
||||
item.addChild(child)
|
||||
|
||||
qcolor = QtGui.QColor.fromRgb(*self.color_comboBox.value.rgb())
|
||||
comment = self.comment_lineEdit.text()
|
||||
line = LogInfiniteLine(pos=pos, angle=angle, movable=self.drag_checkBox.isChecked(), pen=qcolor)
|
||||
line.sigPositionChanged.connect(self.move_line)
|
||||
|
||||
self.make_table_row(pos, angle, qcolor, comment)
|
||||
|
||||
graph_id = self.graph_comboBox.currentData()
|
||||
try:
|
||||
self.lines[graph_id].append(line)
|
||||
self.comments[graph_id].append(comment)
|
||||
except KeyError:
|
||||
self.lines[graph_id] = [line]
|
||||
self.comments[graph_id] = [comment]
|
||||
|
||||
self.line_created.emit(line, graph_id)
|
||||
|
||||
def set_graphs(self, graphs: list):
|
||||
for graph_id, name in graphs:
|
||||
self.graph_comboBox.addItem(name, userData=graph_id)
|
||||
|
||||
def remove_graph(self, graph_id: str):
|
||||
idx = self.graph_comboBox.findData(graph_id)
|
||||
if idx != -1:
|
||||
self.graph_comboBox.removeItem(idx)
|
||||
|
||||
if graph_id in self.lines:
|
||||
del self.lines[graph_id]
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_graph_comboBox_currentIndexChanged')
|
||||
def change_graph(self, idx: int):
|
||||
self.tableWidget.clear()
|
||||
self.tableWidget.setRowCount(0)
|
||||
|
||||
graph_id = self.graph_comboBox.itemData(idx)
|
||||
if graph_id in self.lines:
|
||||
lines = self.lines[graph_id]
|
||||
comments = self.comments[graph_id]
|
||||
for i, line in enumerate(lines):
|
||||
self.make_table_row(line.pos(), line.angle, line.pen.color(), comments[i])
|
||||
|
||||
def make_table_row(self, position, angle, color, comment):
|
||||
if angle == 0:
|
||||
try:
|
||||
pos_label = 'x = ' + str(position.y())
|
||||
except AttributeError:
|
||||
pos_label = 'x = {position}'
|
||||
|
||||
elif angle == 90:
|
||||
try:
|
||||
pos_label = f'y = {position.x()}'
|
||||
except AttributeError:
|
||||
pos_label = f'y = {position}'
|
||||
|
||||
self.graphs[graph_id].addDrawing(new_obj)
|
||||
else:
|
||||
raise ValueError('Only horizontal or vertical lines are supported')
|
||||
QtWidgets.QMessageBox.information(self, 'Not working', 'No graph is selected to add this object.')
|
||||
|
||||
item = QtWidgets.QTableWidgetItem(pos_label)
|
||||
item.setFlags(QtCore.Qt.ItemIsSelectable)
|
||||
item.setForeground(QtGui.QBrush(QtGui.QColor('black')))
|
||||
self.treeWidget_2.expandAll()
|
||||
|
||||
row_count = self.tableWidget.rowCount()
|
||||
self.tableWidget.setRowCount(row_count+1)
|
||||
self.tableWidget.setItem(row_count, 0, item)
|
||||
|
||||
item2 = QtWidgets.QTableWidgetItem(comment)
|
||||
self.tableWidget.setItem(row_count, 1, item2)
|
||||
|
||||
colitem = QtWidgets.QTableWidgetItem(' ')
|
||||
colitem.setBackground(QtGui.QBrush(color))
|
||||
colitem.setFlags(QtCore.Qt.ItemIsSelectable)
|
||||
self.tableWidget.setVerticalHeaderItem(row_count, colitem)
|
||||
|
||||
def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent) -> bool:
|
||||
if evt.type() == QtCore.QEvent.KeyPress:
|
||||
if evt.key() == QtCore.Qt.Key_Delete:
|
||||
self.delete_line()
|
||||
return True
|
||||
|
||||
return super().eventFilter(src, evt)
|
||||
|
||||
def delete_line(self):
|
||||
remove_rows = sorted([item.row() for item in self.tableWidget.selectedItems()])
|
||||
graph_id = self.graph_comboBox.currentData()
|
||||
current_lines = self.lines[graph_id]
|
||||
|
||||
print(remove_rows)
|
||||
for i in reversed(remove_rows):
|
||||
print(i)
|
||||
self.tableWidget.removeRow(i)
|
||||
self.line_deleted.emit(current_lines[i], graph_id)
|
||||
|
||||
current_lines.pop(i)
|
||||
self.comments[graph_id].pop(i)
|
||||
|
||||
@QtCore.pyqtSlot(object)
|
||||
def move_line(self, line: InfiniteLine):
|
||||
current_idx = self.graph_comboBox.currentData()
|
||||
graphs = self.lines[current_idx]
|
||||
i = -1
|
||||
for i, line_i in enumerate(graphs):
|
||||
if line == line_i:
|
||||
break
|
||||
pos = line.value()
|
||||
text_item = self.tableWidget.item(i, 0)
|
||||
text_item.setText(text_item.text()[:4]+f'{pos:.4g}')
|
||||
"""
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication([])
|
||||
w = DrawingsWidget()
|
||||
w.show()
|
||||
app.exec()
|
||||
|
0
src/gui_qt/graphs/objects.py
Normal file
0
src/gui_qt/graphs/objects.py
Normal file
Loading…
Reference in New Issue
Block a user