Преглед изворни кода

gridviewer: fitinview, labels on cells

olivier.massot пре 8 година
родитељ
комит
92bf8d24e7

+ 2 - 0
.settings/org.eclipse.core.resources.prefs

@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding//tools/gridviewer/qt_new_grid.py=utf-8

+ 18 - 3
pypog/grid_objects.py

@@ -4,7 +4,8 @@
     ** By Cro-Ki l@b, 2017 **
 '''
 from pypog.geometry_objects import BaseGeometry, FHexGeometry, SquareGeometry, \
-    BoundingRect
+    BoundingRect, HexGeometry
+
 
 class BaseGrid(object):
     """ Base class for grids
@@ -81,6 +82,16 @@ class BaseGrid(object):
         for item in ((x, y) for x in range(self.width) for y in range(self.height)):
             yield item
 
+    def __getitem__(self, index):
+        """ get the coordinates at the given index """
+        if not (-1 * len(self)) < index < len(self):
+            raise IndexError("index is out of the grid's range (given: {})".format(index))
+        if index < 0:
+            index += len(self)
+        y = index // self.width
+        x = index % self.width
+        return x, y
+
     # geometrical algorithms
     def neighbors(self, *args):
         return self.geometry.neighbors(*args, br=self.br)
@@ -115,8 +126,12 @@ class SquareGrid(BaseGrid):
     def __init__(self, *args, **kwargs):
         BaseGrid.__init__(self, *args, **kwargs)
 
-class FHexGrid(BaseGrid):
+class HexGrid(BaseGrid):
+    """ Base class for hexagonal grid objects """
+    geometry = HexGeometry
+
+class FHexGrid(HexGrid):
     """ Flat-hexagonal grid object """
     geometry = FHexGeometry
     def __init__(self, *args, **kwargs):
-        BaseGrid.__init__(self, *args, **kwargs)
+        HexGrid.__init__(self, *args, **kwargs)

+ 2 - 2
tools/gridviewer/GridDialogBox.py

@@ -5,8 +5,8 @@ Created on 8 mars 2017
 '''
 from PyQt5.Qt import QDialog
 
-from qt_new_grid import Ui_window
 from pypog.grid_objects import FHexGrid, SquareGrid
+from qt_new_grid import Ui_window
 
 class GridDialogBox(QDialog):
     def __init__(self, parent=None):
@@ -23,7 +23,7 @@ class GridDialogBox(QDialog):
         self.ui.btn_create.clicked.connect(self.ok)
 
     def ok(self):
-        cls = FHexGrid if self.ui.opt_hex else SquareGrid
+        cls = FHexGrid if self.ui.opt_hex.isChecked() else SquareGrid
         self._obj = cls(self.ui.spb_width.value(), self.ui.spb_height.value())
         self.done(1)
 

+ 78 - 63
tools/gridviewer/GridViewer.py

@@ -5,8 +5,9 @@
 
 from timeit import timeit
 
-from PyQt5.Qt import Qt, QEvent
+from PyQt5.Qt import Qt, QEvent, QRectF
 from PyQt5.QtCore import QPointF
+from PyQt5.QtGui import QPolygonF
 from PyQt5.QtWidgets import QMainWindow, \
     QApplication, QGraphicsScene, QGraphicsView
 import yaml
@@ -14,7 +15,7 @@ import yaml
 from GridDialogBox import GridDialogBox
 from GridViewerCell import GridViewerCell
 from ListViewDialog import ListViewDialog
-from pypog.grid_objects import SquareGrid, FHexGrid
+from pypog.grid_objects import SquareGrid, FHexGrid, HexGrid, BaseGrid
 from qt_viewer import Ui_window
 
 
@@ -26,44 +27,34 @@ class GridViewer(QMainWindow):
         self.selection = []
         self.job_index = 0
         self.job_results = []
+        self.grid = BaseGrid(1, 1)
         self.createWidgets()
 
+    # ## GUI related methods
     def createWidgets(self):
         self.ui = Ui_window()
         self.ui.setupUi(self)
 
-        self._init_scene()
+        self.ui.btn_new_grid.clicked.connect(self.show_new_grid_dialog)
 
-        self.ui.btn_new_grid.clicked.connect(self.new_grid_dialog)
-
-        self.ui.btn_list_view.clicked.connect(self.list_view_dialog)
+        self.ui.btn_list_view.clicked.connect(self.show_list_view_dialog)
         self.ui.btn_zoom_plus.clicked.connect(self.zoom_plus)
         self.ui.btn_zoom_minus.clicked.connect(self.zoom_minus)
+        self.ui.btn_zoom_view.clicked.connect(self.fit_in_view)
         self.ui.chk_displayCoords.toggled.connect(self.update_cell_labels)
-
-        self.ui.cb_jobs.insertItems(0, self.job_names())
-        self.update_stack_job()
-        self.ui.btn_run_job.clicked.connect(self.run_selected_job)
-        self.ui.btn_job_next.clicked.connect(self.job_next)
-        self.ui.btn_job_previous.clicked.connect(self.job_previous)
-        self.ui.btn_job_validate.clicked.connect(self.job_validate)
-
-        self.make_grid(SquareGrid(30, 30))
-
-    def _init_scene(self):
-        self._scene = QGraphicsScene()
-        self._scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
-
-        self.ui.view.setScene(self._scene)
-        self.ui.view.scale(0.5, 0.5)
-        self.ui.view.centerOn(QPointF(0, 0))
+        self.ui.btn_run_job.clicked.connect(self.run_selected_job_clicked)
+        self.ui.btn_job_next.clicked.connect(self.job_next_clicked)
+        self.ui.btn_job_previous.clicked.connect(self.job_previous_clicked)
+        self.ui.btn_job_validate.clicked.connect(self.job_validate_clicked)
 
         self.ui.view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
         self.ui.view.setDragMode(QGraphicsView.NoDrag)
         self.ui.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
-
         self.ui.view.viewport().installEventFilter(self)
 
+        self.ui.cb_jobs.insertItems(0, self.get_job_names())
+        self._update_stack_job()
+
     def eventFilter(self, obj, event):
         if event.type() == QEvent.Wheel:
             if event.angleDelta().y() > 0:
@@ -73,17 +64,34 @@ class GridViewer(QMainWindow):
             return True
         return False
 
+    def fit_in_view(self):
+        self.ui.view.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio)
+
+    def zoom_plus(self):
+        self.ui.view.scale(1.2, 1.2)
+
+    def zoom_minus(self):
+        self.ui.view.scale(0.8, 0.8)
+
+    # ## Grid and selection
     def make_grid(self, grid):
         QApplication.setOverrideCursor(Qt.WaitCursor)
+
         self.grid = grid
         self.cells = {}
         self.selection = []
 
-        self._scene.clear()
+        self._scene = QGraphicsScene()
+        self._scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
 
         if len(grid) > 10000:
             self.ui.chk_displayCoords.setChecked(False)
 
+        scale = 120
+        margin = 2 * scale
+        ratio = 0.866 if isinstance(grid, HexGrid) else 1
+        self._scene.setSceneRect(0 - margin, 0 - margin, (ratio * scale * (grid.width + 2)) + margin, (scale * (grid.height + 2)) + margin)
+
         for x, y in grid:
             cell = GridViewerCell(self, x, y)
             cell.generate(grid.geometry.graphicsitem(x, y), show_label=self.ui.chk_displayCoords.isChecked())
@@ -91,7 +99,10 @@ class GridViewer(QMainWindow):
             self._scene.addItem(cell)
             self.cells[(x, y)] = cell
 
+        self.ui.view.setScene(self._scene)
+
         self.ui.view.centerOn(QPointF(0, 0))
+        self.fit_in_view()
 
         self.grid = grid
         QApplication.restoreOverrideCursor()
@@ -119,31 +130,37 @@ class GridViewer(QMainWindow):
         for cell in self.cells.values():
             cell.show_label(bool(self.ui.chk_displayCoords.isChecked()))
 
-    def zoom_plus(self):
-        self.ui.view.scale(1.1, 1.1)
-
-    def zoom_minus(self):
-        self.ui.view.scale(0.9, 0.9)
-
-    def new_grid_dialog(self):
+    # ## Dialogs
+    def show_new_grid_dialog(self):
         grid = GridDialogBox.get()
-        self.make_grid(grid)
+        if grid:
+            self.make_grid(grid)
 
-    def list_view_dialog(self):
+    def show_list_view_dialog(self):
         new_lst = ListViewDialog(self.selection).exec_()
         self.update_selected_cells(new_lst)
 
-    def job_names(self):
-        with open("jobs.yml", "r") as f:
-            jobs = yaml.load(f)
-        return jobs.keys()
-
-    def run_selected_job(self):
+    # ## IT Jobs
+    def run_selected_job_clicked(self):
         self.job_index = 0
         self.job_results = self.run_job(self.ui.cb_jobs.currentText())
-        self.update_stack_job()
+        self._update_stack_job()
+
+    def job_next_clicked(self):
+        if self.job_index < (len(self.job_results) - 1):
+            self.job_index += 1
+            self._update_stack_job()
+
+    def job_previous_clicked(self):
+        if self.job_index > 0:
+            self.job_index -= 1
+            self._update_stack_job()
+
+    def job_validate_clicked(self):
+        self.save_result_for(*self.job_results[self.job_index])
+        self._update_stack_job()
 
-    def update_stack_job(self):
+    def _update_stack_job(self):
         if not self.job_results:
             self.ui.stack_job.setCurrentIndex(0)
             return
@@ -168,23 +185,21 @@ class GridViewer(QMainWindow):
         else:
             self.ui.lbl_job_exectime.setText("Exec. in {0:.2f} ms.".format(ittime))
 
-    def job_next(self):
-        if self.job_index < (len(self.job_results) - 1):
-            self.job_index += 1
-            self.update_stack_job()
-
-    def job_previous(self):
-        if self.job_index > 0:
-            self.job_index -= 1
-            self.update_stack_job()
+    @staticmethod
+    def get_job_names():
+        with open("jobs.yml", "r") as f:
+            jobs = yaml.load(f)
+        return jobs.keys()
 
-    def run_job(self, job_name):
+    @staticmethod
+    def run_job(job_name):
         with open("jobs.yml", "r") as f:
             jobs = yaml.load(f)
         callstrings = [(gridstr, "{}.{}".format(gridstr, funcstr)) for gridstr, calls in jobs[job_name].items() for funcstr in calls]
-        return [(gridstr, callstr, eval(callstr), self.ittime(callstr)) for gridstr, callstr in callstrings]
+        return [(gridstr, callstr, eval(callstr), GridViewer.ittime(callstr)) for gridstr, callstr in callstrings]
 
-    def ittime(self, callstr):
+    @staticmethod
+    def ittime(callstr):
         """ returns the execution time in milli-seconds
             callstr has to be a string
             (ex: 'time.sleep(1)', which will return 1000)
@@ -198,7 +213,8 @@ class GridViewer(QMainWindow):
         else:
             return -1
 
-    def saved_results(self):
+    @staticmethod
+    def saved_results():
         try:
             with open("results.yml", "r") as f:
                 data = yaml.load(f)
@@ -206,18 +222,17 @@ class GridViewer(QMainWindow):
         except (FileNotFoundError, TypeError):
             return {}
 
-    def saved_result_for(self, callstr):
+    @staticmethod
+    def saved_result_for(callstr):
         try:
-            return tuple(self.saved_results()[callstr])
+            return tuple(GridViewer.saved_results()[callstr])
         except (TypeError, KeyError):
             return None
 
-    def job_validate(self):
-        gridstr, callstr, result, ittime = self.job_results[self.job_index]
-        data = self.saved_results()
-
+    @staticmethod
+    def save_result(gridstr, callstr, result, ittime):
+        data = GridViewer.saved_results()
         data[callstr] = [gridstr, callstr, str(result), ittime]
-
         with open("results.yml", "w+") as f:
             yaml.dump(data, f)
-        self.update_stack_job()
+

+ 5 - 7
tools/gridviewer/GridViewerCell.py

@@ -31,13 +31,11 @@ class GridViewerCell(QGraphicsPolygonItem):
         self.label = QGraphicsSimpleTextItem("{}-{}".format(self.x, self.y), parent=self)
         self.label.setVisible(show_label)
 
-#         k = 0
-#         if (self.x % 2) != 0:
-#             k = 0.5
-#         if shape == geometry.FLAT_HEX:
-#             self.label.setPos(QPointF(((self.x * 0.866) + 0.2886) * scale, (self.y + k + 0.5) * scale))
-#         else:
-#             self.label.setPos(QPointF(self.x * scale, self.y * scale))
+        if len(points) == 6:
+            k = 0.5 if (self.x % 2) != 0 else 0
+            self.label.setPos(QPointF(((self.x * 0.866) + 0.2886) * 120, (self.y + k + 0.5) * 120))
+        else:
+            self.label.setPos(QPointF(self.x * 120, self.y * 120))
 
         font = QFont()
         font.setPointSize(20)

+ 8 - 2
tools/gridviewer/qt_viewer.py

@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'qt_viewer.ui'
 #
-# Created by: PyQt5 UI code generator 5.7.1
+# Created by: PyQt5 UI code generator 5.4.2
 #
 # WARNING! All changes made in this file will be lost!
 
@@ -102,6 +102,8 @@ class Ui_window(object):
         font = QtGui.QFont()
         font.setStyleStrategy(QtGui.QFont.PreferAntialias)
         self.view.setFont(font)
+        self.view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
+        self.view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
         self.view.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
         self.view.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
         self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.BoundingRectViewportUpdate)
@@ -116,6 +118,9 @@ class Ui_window(object):
         self.btn_zoom_plus = QtWidgets.QToolButton(self.centralwidget)
         self.btn_zoom_plus.setObjectName("btn_zoom_plus")
         self.horizontalLayout_4.addWidget(self.btn_zoom_plus)
+        self.btn_zoom_view = QtWidgets.QToolButton(self.centralwidget)
+        self.btn_zoom_view.setObjectName("btn_zoom_view")
+        self.horizontalLayout_4.addWidget(self.btn_zoom_view)
         self.btn_zoom_minus = QtWidgets.QToolButton(self.centralwidget)
         self.btn_zoom_minus.setObjectName("btn_zoom_minus")
         self.horizontalLayout_4.addWidget(self.btn_zoom_minus)
@@ -141,7 +146,7 @@ class Ui_window(object):
         self.actionQuitter.setObjectName("actionQuitter")
 
         self.retranslateUi(window)
-        self.stack_job.setCurrentIndex(1)
+        self.stack_job.setCurrentIndex(0)
         QtCore.QMetaObject.connectSlotsByName(window)
         window.setTabOrder(self.view, self.btn_new_grid)
         window.setTabOrder(self.btn_new_grid, self.cb_jobs)
@@ -165,6 +170,7 @@ class Ui_window(object):
         self.btn_job_validate.setText(_translate("window", "Validate"))
         self.label_3.setText(_translate("window", "Zoom"))
         self.btn_zoom_plus.setText(_translate("window", "+"))
+        self.btn_zoom_view.setText(_translate("window", "X"))
         self.btn_zoom_minus.setText(_translate("window", "-"))
         self.chk_displayCoords.setText(_translate("window", "Display coordinates"))
         self.actionQuitter.setText(_translate("window", "Quitter"))

+ 7 - 0
tools/gridviewer/qt_viewer.ui

@@ -295,6 +295,13 @@
           </property>
          </widget>
         </item>
+        <item>
+         <widget class="QToolButton" name="btn_zoom_view">
+          <property name="text">
+           <string>X</string>
+          </property>
+         </widget>
+        </item>
         <item>
          <widget class="QToolButton" name="btn_zoom_minus">
           <property name="text">