GridViewer.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. '''
  2. ** By Cro-Ki l@b, 2017 **
  3. '''
  4. from timeit import timeit
  5. from PyQt5.Qt import Qt
  6. from PyQt5.QtCore import QPointF
  7. from PyQt5.QtWidgets import QMainWindow, \
  8. QApplication, QGraphicsScene, QGraphicsView
  9. import ipdb # until I find another way to print traceback with pyqt5
  10. import yaml
  11. from GridDialogBox import GridDialogBox
  12. from GridViewerCell import GridViewerCell
  13. from ListViewDialog import ListViewDialog
  14. from pypog.grid_objects import SquareGrid
  15. from pypog.grid_objects import SquareGrid, FHexGrid
  16. from qt_viewer import Ui_window
  17. class GridViewer(QMainWindow):
  18. def __init__(self):
  19. super (GridViewer, self).__init__()
  20. self.cells = {}
  21. self.selection = []
  22. self.job_index = 0
  23. self.job_results = []
  24. self.createWidgets()
  25. def createWidgets(self):
  26. self.ui = Ui_window()
  27. self.ui.setupUi(self)
  28. self._init_scene()
  29. self.ui.btn_new_grid.clicked.connect(self.new_grid_dialog)
  30. self.ui.btn_run.clicked.connect(self.run_f)
  31. self.ui.btn_list_view.clicked.connect(self.list_view_dialog)
  32. self.ui.btn_zoom_plus.clicked.connect(self.zoom_plus)
  33. self.ui.btn_zoom_minus.clicked.connect(self.zoom_minus)
  34. self.ui.chk_displayCoords.toggled.connect(self.update_cell_labels)
  35. self.make_grid(SquareGrid(30, 30))
  36. def _init_scene(self):
  37. self._scene = QGraphicsScene()
  38. self._scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
  39. self.ui.view.setScene(self._scene)
  40. self.ui.view.scale(0.5, 0.5)
  41. self.ui.view.centerOn(QPointF(0, 0))
  42. self.ui.view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
  43. self.ui.view.setDragMode(QGraphicsView.NoDrag)
  44. self.ui.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
  45. self.ui.cb_jobs.insertItems(0, self.job_names())
  46. self.update_stack_job()
  47. self.ui.btn_run_job.clicked.connect(self.run_selected_job)
  48. self.ui.btn_job_next.clicked.connect(self.job_next)
  49. self.ui.btn_job_previous.clicked.connect(self.job_previous)
  50. self.ui.btn_job_validate.clicked.connect(self.job_validate)
  51. def make_grid(self, grid):
  52. QApplication.setOverrideCursor(Qt.WaitCursor)
  53. self.grid = grid
  54. self.cells = {}
  55. self.selection = []
  56. self._scene.clear()
  57. if len(grid) > 10000:
  58. self.ui.chk_displayCoords.setChecked(False)
  59. for x, y in grid:
  60. cell = GridViewerCell(self, x, y)
  61. cell.generate(grid.geometry.graphicsitem(x, y), show_label=self.ui.chk_displayCoords.isChecked())
  62. self._scene.addItem(cell)
  63. self.cells[(x, y)] = cell
  64. self.ui.view.centerOn(QPointF(0, 0))
  65. self.grid = grid
  66. QApplication.restoreOverrideCursor()
  67. def add_to_selection(self, x, y):
  68. self.selection.append((x, y))
  69. def remove_from_selection(self, x, y):
  70. self.selection.remove((x, y))
  71. def update_selected_cells(self, new_selection):
  72. if not new_selection != self.selection:
  73. return
  74. QApplication.setOverrideCursor(Qt.WaitCursor)
  75. for x, y in tuple(self.selection):
  76. self.cells[(x, y)].unselect()
  77. for x, y in new_selection:
  78. if (x, y) in self.grid:
  79. self.cells[(x, y)].select()
  80. QApplication.restoreOverrideCursor()
  81. def update_cell_labels(self):
  82. for cell in self.cells.values():
  83. cell.show_label(bool(self.ui.chk_displayCoords.isChecked()))
  84. def zoom_plus(self):
  85. self.ui.view.scale(1.1, 1.1)
  86. def zoom_minus(self):
  87. self.ui.view.scale(0.9, 0.9)
  88. def new_grid_dialog(self):
  89. grid = GridDialogBox.get()
  90. self.make_grid(grid)
  91. def list_view_dialog(self):
  92. new_lst = ListViewDialog(self.selection).exec_()
  93. self.update_selected_cells(new_lst)
  94. def wheelEvent(self, event):
  95. if event.angleDelta().y() > 0:
  96. # self.zoom_plus()
  97. event.accept()
  98. elif event.angleDelta().y() < 0:
  99. # self.zoom_minus()
  100. event.accept()
  101. else:
  102. event.ignore()
  103. def keyPressEvent(self, event):
  104. if event.key() == Qt.Key_Left:
  105. pass
  106. elif event.key() == Qt.Key_Right:
  107. pass
  108. elif event.key() == Qt.Key_Down:
  109. pass
  110. elif event.key() == Qt.Key_Up:
  111. pass
  112. def job_names(self):
  113. with open("jobs.yml", "r") as f:
  114. jobs = yaml.load(f)
  115. return jobs.keys()
  116. def run_selected_job(self):
  117. self.job_index = 0
  118. self.job_results = self.run_job(self.ui.cb_jobs.currentText())
  119. self.update_stack_job()
  120. def update_stack_job(self):
  121. if not self.job_results:
  122. self.ui.stack_job.setCurrentIndex(0)
  123. return
  124. self.ui.stack_job.setCurrentIndex(1)
  125. self.ui.lbl_job_number.setText("Test {} / {}".format(self.job_index + 1, len(self.job_results)))
  126. gridstr, callstr, result, ittime = self.job_results[self.job_index]
  127. new_grid = eval(gridstr)
  128. if not (new_grid.__class__ == self.grid.__class__ and
  129. new_grid.width == self.grid.width and
  130. new_grid.height == self.grid.height):
  131. self.make_grid(new_grid)
  132. self.ui.txt_job_run.setText(callstr)
  133. self.update_selected_cells(result)
  134. saved = self.saved_result_for(callstr)
  135. if saved:
  136. self.ui.lbl_job_exectime.setText("Exec. in {0:.2f} ms. / Saved: {1:.2f} ms. / Same result: {2:}".format(ittime, saved[3], str(result) == saved[2]))
  137. else:
  138. self.ui.lbl_job_exectime.setText("Exec. in {0:.2f} ms.".format(ittime))
  139. def job_next(self):
  140. if self.job_index < (len(self.job_results) - 1):
  141. self.job_index += 1
  142. self.update_stack_job()
  143. def job_previous(self):
  144. if self.job_index > 0:
  145. self.job_index -= 1
  146. self.update_stack_job()
  147. def run_job(self, job_name):
  148. with open("jobs.yml", "r") as f:
  149. jobs = yaml.load(f)
  150. callstrings = [(gridstr, "{}.{}".format(gridstr, funcstr)) for gridstr, calls in jobs[job_name].items() for funcstr in calls]
  151. return [(gridstr, callstr, eval(callstr), self.ittime(callstr)) for gridstr, callstr in callstrings]
  152. def ittime(self, callstr):
  153. """ returns the execution time in milli-seconds
  154. callstr has to be a string
  155. (ex: 'time.sleep(1)', which will return 1000)
  156. """
  157. number, t = 1, 0
  158. while t < 10 ** 8:
  159. t = timeit(lambda: eval(callstr), number=number)
  160. if t >= 0.001:
  161. return 1000 * t / number
  162. number *= 10
  163. else:
  164. return -1
  165. def saved_results(self):
  166. try:
  167. with open("results.yml", "r") as f:
  168. data = yaml.load(f)
  169. return dict(data)
  170. except (FileNotFoundError, TypeError):
  171. return {}
  172. def saved_result_for(self, callstr):
  173. try:
  174. return tuple(self.saved_results()[callstr])
  175. except (TypeError, KeyError):
  176. return None
  177. def job_validate(self):
  178. gridstr, callstr, result, ittime = self.job_results[self.job_index]
  179. data = self.saved_results()
  180. data[callstr] = [gridstr, callstr, str(result), ittime]
  181. with open("results.yml", "w+") as f:
  182. yaml.dump(data, f)
  183. self.update_stack_job()