From 533ad467cba0a95908a057aff460d292969ce33e Mon Sep 17 00:00:00 2001 From: david Date: Wed, 1 Mar 2023 21:30:18 +0000 Subject: [PATCH] #187 - Prototype track scaling with a few example dots --- src/prototype_ui/actions.py | 2 + src/prototype_ui/canvas.py | 18 ++-- src/prototype_ui/main.py | 10 +- src/prototype_ui/menubar.py | 1 + src/prototype_ui/track_analysis_canvas.py | 117 ++++++++++++++++++++++ 5 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 src/prototype_ui/track_analysis_canvas.py diff --git a/src/prototype_ui/actions.py b/src/prototype_ui/actions.py index efb5f1d..f736607 100644 --- a/src/prototype_ui/actions.py +++ b/src/prototype_ui/actions.py @@ -28,6 +28,8 @@ def __init__(self, style: QStyle): self.file_save_as.setShortcut("Ctrl+A") self.file_save_as.setIcon(style.standardIcon(QStyle.StandardPixmap.SP_DialogOpenButton)) + self.file_save_as.setCheckable(True) + @staticmethod def get_custom_icon(icon_name: str): file_path = os.path.join(ICON_DIRECTORY, icon_name + ".png") diff --git a/src/prototype_ui/canvas.py b/src/prototype_ui/canvas.py index 16d96e5..1684ed1 100644 --- a/src/prototype_ui/canvas.py +++ b/src/prototype_ui/canvas.py @@ -1,3 +1,5 @@ +from abc import abstractmethod + from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QGraphicsPixmapItem, \ QAbstractGraphicsShapeItem from PyQt6.QtGui import QBrush, QPen, QPixmap, QPainter @@ -37,18 +39,10 @@ def _recreate_scene(self): scene.addItem(i) self.setScene(scene) - # Hardcoded examples for now - these will be abstract shortly + @abstractmethod def _paint(self, painter: QPainter): - painter.fillRect(0, 0, round(self._width / 2), round(self._height / 2), Qt.GlobalColor.darkYellow) + pass - # Hardcoded examples for now - these will be abstract shortly + @abstractmethod def _get_scene_items(self) -> list[QAbstractGraphicsShapeItem]: - rect = QGraphicsRectItem(0, 0, self._width / 3, self._height / 3) - rect.setPos(self._width / 10, self._height / 10) - brush = QBrush(Qt.GlobalColor.red) - rect.setBrush(brush) - pen = QPen(Qt.GlobalColor.cyan) - pen.setWidth(10) - rect.setPen(pen) - - return [rect] + pass diff --git a/src/prototype_ui/main.py b/src/prototype_ui/main.py index a93af08..158d80b 100644 --- a/src/prototype_ui/main.py +++ b/src/prototype_ui/main.py @@ -4,9 +4,9 @@ from PyQt6.QtWidgets import QMainWindow, QApplication, QLabel, QProgressBar from prototype_ui.actions import Actions -from prototype_ui.canvas import Canvas from prototype_ui.menubar import MenuBarManager from prototype_ui.toolbar import ToolBarManager +from prototype_ui.track_analysis_canvas import TrackAnalysisCanvas, SolidCircle, TrackArea class MainWindow(QMainWindow): @@ -36,11 +36,17 @@ def __init__(self): self._actions.file_new.triggered.connect(self._new_file) self._actions.file_open.triggered.connect(self._open_file) - self.canvas = Canvas(Qt.GlobalColor.gray) + self.canvas = TrackAnalysisCanvas() self.setCentralWidget(self.canvas) self.show() + # Example of drawing stuff in the track canvas until I integrate with Tracks etc. + self.canvas.set_track_area(TrackArea(0, 0, 100, 100)) + self.canvas.add_fixed_shape(SolidCircle((90, 90), 20, Qt.GlobalColor.red)) + self.canvas.add_fixed_shape(SolidCircle((50, 50), 20, Qt.GlobalColor.white)) + self.canvas.add_fixed_shape(SolidCircle((10, 10), 20, Qt.GlobalColor.blue)) + def _new_file(self): print("New File") self.statusBar().showMessage("Hello Briefly", 5000) # 5 secs diff --git a/src/prototype_ui/menubar.py b/src/prototype_ui/menubar.py index 86c814a..1624b3b 100644 --- a/src/prototype_ui/menubar.py +++ b/src/prototype_ui/menubar.py @@ -16,5 +16,6 @@ def _create_file_menu(self): menu = self._menu_bar.addMenu("File") menu.addAction(self._actions.file_new) menu.addAction(self._actions.file_open) + menu.addSeparator() menu.addAction(self._actions.file_save) menu.addAction(self._actions.file_save_as) diff --git a/src/prototype_ui/track_analysis_canvas.py b/src/prototype_ui/track_analysis_canvas.py new file mode 100644 index 0000000..b5a4051 --- /dev/null +++ b/src/prototype_ui/track_analysis_canvas.py @@ -0,0 +1,117 @@ +from abc import ABC + +from PyQt6.uic.properties import QtGui + +from prototype_ui.canvas import Canvas +from PyQt6.QtWidgets import QGraphicsRectItem, QAbstractGraphicsShapeItem +from PyQt6.QtGui import QBrush, QPen, QPainter, QColor +from PyQt6.QtCore import Qt, QPointF, QPoint + + +class CanvasItem(ABC): + pass + + +class FixedShape(CanvasItem): + pass + + +class FloatingShape(CanvasItem): + pass + + +class TrackArea: + def __init__(self, min_x, min_y, max_x, max_y): + assert max_x > min_x + assert max_y > min_y + + self.min_x = min_x + self.min_y = min_y + self.max_x = max_x + self.max_y = max_y + + +class Scale: + def __init__(self, min_x, max_y, scale): + self.min_x = min_x + self.max_y = max_y + self.scale = scale + + +class TrackAnalysisCanvas(Canvas): + def __init__(self): + self._track_area = TrackArea(0, 0, 100, 100) + + self._fixed_shapes = [] + + # self._ring_highlight_widgets = [] + # self._angle_line_highlight_widgets = [] + # self._car_widgets = [] + # self._old_car_widgets = [] + + super().__init__(Qt.GlobalColor.black) + + def reset_to_blank(self): + self._fixed_shapes = [] + + def set_track_area(self, track_area: TrackArea): + self._track_area = track_area + + def _get_current_scale(self): + min_x = self._track_area.min_x + min_y = self._track_area.min_y + max_x = self._track_area.max_x + max_y = self._track_area.max_y + + x_size = max_x - min_x + y_size = max_y - min_y + + x_scale = self.geometry().width() / x_size + y_scale = self.geometry().height() / y_size + + scale = min(x_scale, y_scale) + + x_border = (1 - scale / x_scale) / 2 * x_size + y_border = (1 - scale / y_scale) / 2 * y_size + + return Scale(min_x - x_border, max_y + y_border, scale) + + def _paint(self, painter: QPainter): + scale = self._get_current_scale() + for f in self._fixed_shapes: + f.paint(painter, scale) + + def _get_scene_items(self) -> list[QAbstractGraphicsShapeItem]: + rect = QGraphicsRectItem(0, 0, self._width / 20, self._height / 20) + rect.setPos(self._width / 10, self._height / 10) + brush = QBrush(Qt.GlobalColor.red) + rect.setBrush(brush) + pen = QPen(Qt.GlobalColor.cyan) + pen.setWidth(10) + rect.setPen(pen) + + return [rect] + + def add_fixed_shape(self, item: FixedShape): + self._fixed_shapes.append(item) + + +# plot_dot() in v3 + +class SolidCircle(FixedShape): + def __init__(self, point: (float | int, float | int), radius: float | int, colour: Qt.GlobalColor): + self._point = point + self._pen = QPen(colour) + self._pen.setWidth(radius) + + def paint(self, painter: QPainter, scale: Scale): + (x, y) = self._point + + x = (x - scale.min_x) * scale.scale + y = (scale.max_y - y) * scale.scale + + painter.setPen(self._pen) + painter.drawPoint(int(x), int(y)) + + +