From dd4269df605a6f9687906fb8b6cbe7bf6b59bdb8 Mon Sep 17 00:00:00 2001 From: Jeremy Wright Date: Thu, 6 Feb 2025 15:33:10 -0500 Subject: [PATCH] Revert "Status bar messages to indicate rendering and viewing progress" --- cq_editor/main_window.py | 48 ++++----------------------- cq_editor/widgets/debugger.py | 7 ---- cq_editor/widgets/object_tree.py | 20 +++++------ cq_editor/widgets/traceback_viewer.py | 3 +- cq_editor/widgets/viewer.py | 37 ++++++++++++--------- tests/test_app.py | 42 ++++++++++++----------- 6 files changed, 60 insertions(+), 97 deletions(-) diff --git a/cq_editor/main_window.py b/cq_editor/main_window.py index a8ee6b70..dbf8b5f0 100644 --- a/cq_editor/main_window.py +++ b/cq_editor/main_window.py @@ -1,8 +1,6 @@ import sys -from typing import Optional -from PyQt5.QtCore import pyqtSlot -from PyQt5.QtWidgets import (QApplication, QLabel, QMainWindow, QToolBar, QDockWidget, QAction) +from PyQt5.QtWidgets import (QLabel, QMainWindow, QToolBar, QDockWidget, QAction) from logbook import Logger import cadquery as cq @@ -67,8 +65,6 @@ def __init__(self,parent=None, filename=None): self.restoreComponentState() - self.on_idle() - def closeEvent(self,event): self.saveWindow() @@ -206,7 +202,7 @@ def prepare_toolbar(self): self.toolbar = QToolBar('Main toolbar',self,objectName='Main toolbar') for c in self.components.values(): - add_actions(self.toolbar, c.toolbarActions()) + add_actions(self.toolbar,c.toolbarActions()) self.addToolBar(self.toolbar) @@ -217,25 +213,18 @@ def prepare_statusbar(self): def prepare_actions(self): - self.components['debugger'].sigRenderStarted \ - .connect(self.on_render_start) self.components['debugger'].sigRendered\ .connect(self.components['object_tree'].addObjects) self.components['debugger'].sigTraceback\ .connect(self.components['traceback_viewer'].addTraceback) - self.components['debugger'].sigRendered \ - .connect(lambda _: self.on_idle()) - self.components['debugger'].sigTraceback \ - .connect(lambda _: self.on_idle()) - self.components['debugger'].sigLocals\ .connect(self.components['variables_viewer'].update_frame) self.components['debugger'].sigLocals\ .connect(self.components['console'].push_vars) - self.components['object_tree'].sigObjectsAdded[list, list]\ - .connect(lambda objects, names: self.components['viewer'].display_many(objects, None, names)) - self.components['object_tree'].sigObjectsAdded[list, bool, list]\ + self.components['object_tree'].sigObjectsAdded[list]\ + .connect(self.components['viewer'].display_many) + self.components['object_tree'].sigObjectsAdded[list,bool]\ .connect(self.components['viewer'].display_many) self.components['object_tree'].sigItemChanged.\ connect(self.components['viewer'].update_item) @@ -250,8 +239,6 @@ def prepare_actions(self): self.components['viewer'].sigObjectSelected\ .connect(self.components['object_tree'].handleGraphicalSelection) - self.components['viewer'].sigDisplayProgress \ - .connect(self.on_display_progress) self.components['traceback_viewer'].sigHighlightLine\ .connect(self.components['editor'].go_to_line) @@ -357,27 +344,6 @@ def handle_filename_change(self, fname): new_title = fname if fname else "*" self.setWindowTitle(f"{self.name}: {new_title}") - def on_idle(self): - self.components['debugger'].set_rendering_state(False) - self.set_status_message('Idle', '#000000') +if __name__ == "__main__": - @pyqtSlot() - def on_render_start(self): - self.components['debugger'].set_rendering_state(True) - self.set_status_message('Rendering...', '#ff0000') - - @pyqtSlot(int, int, str) - def on_display_progress(self, current: int, total: int, name: Optional[str]): - if current == total: - self.on_idle() - else: - message = f'Displaying Shape {current + 1} / {total}' - if name: - message += f' ({name})' - self.set_status_message(message, '#0000ff') - - def set_status_message(self, message: str, color: str): - self.statusBar().showMessage(message) - self.statusBar().setStyleSheet(f'color: {color}') - # required because rendering is currently done on the main thread - QApplication.processEvents() + pass diff --git a/cq_editor/widgets/debugger.py b/cq_editor/widgets/debugger.py index ddef98ad..70d5795f 100644 --- a/cq_editor/widgets/debugger.py +++ b/cq_editor/widgets/debugger.py @@ -111,7 +111,6 @@ class Debugger(QObject,ComponentMixin): ]) - sigRenderStarted = pyqtSignal() sigRendered = pyqtSignal(dict) sigLocals = pyqtSignal(dict) sigTraceback = pyqtSignal(object,str) @@ -264,7 +263,6 @@ def _cleanup_locals(self,module,injected_names): @pyqtSlot(bool) def render(self): - self.sigRenderStarted.emit() seed(59798267586177) if self.preferences['Reload CQ']: @@ -296,11 +294,6 @@ def render(self): sys.last_traceback = exc_info[-1] self.sigTraceback.emit(exc_info, cq_script) - def set_rendering_state(self, rendering): - render_action = self._actions['Run'][0] - render_action.setCheckable(rendering) - render_action.setChecked(rendering) - @property def breakpoints(self): return [ el[0] for el in self.get_breakpoints()] diff --git a/cq_editor/widgets/object_tree.py b/cq_editor/widgets/object_tree.py index de2ffb2b..1778bfd5 100644 --- a/cq_editor/widgets/object_tree.py +++ b/cq_editor/widgets/object_tree.py @@ -97,7 +97,7 @@ class ObjectTree(QWidget,ComponentMixin): {'name': 'Clear all before each run', 'type': 'bool', 'value': True}, {'name': 'STL precision','type': 'float', 'value': .1}]) - sigObjectsAdded = pyqtSignal([list, list],[list, bool, list]) + sigObjectsAdded = pyqtSignal([list],[list,bool]) sigObjectsRemoved = pyqtSignal(list) sigCQObjectSelected = pyqtSignal(object) sigAISObjectsSelected = pyqtSignal(list) @@ -201,7 +201,6 @@ def addLines(self): origin = (0,0,0) ais_list = [] - names = [] for name,color,direction in zip(('X','Y','Z'), ('red','lawngreen','blue'), @@ -215,9 +214,8 @@ def addLines(self): ais=line)) ais_list.append(line) - names.append(name) - self.sigObjectsAdded.emit(ais_list, names) + self.sigObjectsAdded.emit(ais_list) def _current_properties(self): @@ -250,7 +248,6 @@ def addObjects(self,objects,clean=False,root=None): self.removeObjects() ais_list = [] - names = [] #remove empty objects objects_f = {k:v for k,v in objects.items() if not is_obj_empty(v.shape)} @@ -269,14 +266,13 @@ def addObjects(self,objects,clean=False,root=None): if child.properties['Visible']: ais_list.append(ais) - names.append(name) - + root.addChild(child) if request_fit_view: - self.sigObjectsAdded[list, bool, list].emit(ais_list, True, names) + self.sigObjectsAdded[list,bool].emit(ais_list,True) else: - self.sigObjectsAdded[list, list].emit(ais_list, names) + self.sigObjectsAdded[list].emit(ais_list) @pyqtSlot(object,str,object) def addObject(self,obj,name='',options=None): @@ -285,7 +281,7 @@ def addObject(self,obj,name='',options=None): root = self.CQ - ais, shape_display = make_AIS(obj, options) + ais,shape_display = make_AIS(obj, options) root.addChild(ObjectTreeItem(name, shape=obj, @@ -293,7 +289,7 @@ def addObject(self,obj,name='',options=None): ais=ais, sig=self.sigObjectPropertiesChanged)) - self.sigObjectsAdded.emit([ais], [name]) + self.sigObjectsAdded.emit([ais]) @pyqtSlot(list) @pyqtSlot() @@ -317,7 +313,7 @@ def stashObjects(self,action : bool): self.removeObjects() self.CQ.addChildren(self._stash) ais_list = [el.ais for el in self._stash] - self.sigObjectsAdded.emit(ais_list, [''] * len(ais_list)) + self.sigObjectsAdded.emit(ais_list) @pyqtSlot() def removeSelected(self): diff --git a/cq_editor/widgets/traceback_viewer.py b/cq_editor/widgets/traceback_viewer.py index aa7cd9a8..7d1051a0 100644 --- a/cq_editor/widgets/traceback_viewer.py +++ b/cq_editor/widgets/traceback_viewer.py @@ -36,7 +36,8 @@ def __init__(self,parent): self.tree = TracebackTree(self) self.current_exception = QLabel(self) - self.current_exception.setStyleSheet("QLabel {color : red; }"); + self.current_exception.setStyleSheet(\ + "QLabel {color : red; }"); layout(self, (self.current_exception, diff --git a/cq_editor/widgets/viewer.py b/cq_editor/widgets/viewer.py index 498f8438..9c5d620b 100644 --- a/cq_editor/widgets/viewer.py +++ b/cq_editor/widgets/viewer.py @@ -1,6 +1,5 @@ from PyQt5.QtWidgets import QWidget, QDialog, QTreeWidgetItem, QApplication, QAction -from typing import Optional, List from PyQt5.QtCore import pyqtSlot, pyqtSignal from PyQt5.QtGui import QIcon @@ -48,7 +47,6 @@ class OCCViewer(QWidget,ComponentMixin): IMAGE_EXTENSIONS = 'png' sigObjectSelected = pyqtSignal(list) - sigDisplayProgress = pyqtSignal(int, int, str) def __init__(self,parent=None): @@ -181,23 +179,31 @@ def clear(self): context.PurgeDisplay() context.RemoveAll(True) + def _display(self,shape): + + ais = make_AIS(shape) + self.canvas.context.Display(shape,True) + + self.displayed_shapes.append(shape) + self.displayed_ais.append(ais) + + #self.canvas._display.Repaint() + @pyqtSlot(object) - def display(self, ais): - self.display_many([ais]) + def display(self,ais): + + context = self._get_context() + context.Display(ais,True) + + if self.preferences['Fit automatically']: self.fit() @pyqtSlot(list) - @pyqtSlot(list, bool, list) - def display_many(self, ais_list, fit: Optional[bool] = None, names: Optional[List] = None): - if names is None: - names = [None] * len(ais_list) - assert len(ais_list) == len(names) + @pyqtSlot(list,bool) + def display_many(self,ais_list,fit=None): context = self._get_context() - num_objects = len(ais_list) - for i, (ais, name) in enumerate(zip(ais_list, names)): - self.sigDisplayProgress.emit(i, num_objects, name) - context.Display(ais, True) - self.sigDisplayProgress.emit(num_objects, num_objects, None) + for ais in ais_list: + context.Display(ais,True) if self.preferences['Fit automatically'] and fit is None: self.fit() @@ -217,8 +223,7 @@ def update_item(self,item,col): def remove_items(self,ais_items): ctx = self._get_context() - for ais in ais_items: - ctx.Erase(ais,True) + for ais in ais_items: ctx.Erase(ais,True) @pyqtSlot() def redraw(self): diff --git a/tests/test_app.py b/tests/test_app.py index a5ad8490..2ec4baa7 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1,9 +1,6 @@ from path import Path import os, sys, asyncio -from pytestqt.qtbot import QtBot -import pytestqt.exceptions - if sys.platform == 'win32': asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) @@ -94,8 +91,6 @@ sk = cq.Sketch().rect(1,1) """ -TIMEOUT = 10_000 - def _modify_file(code, path="test.py"): with open(path, "w", 1) as f: f.write(code) @@ -129,7 +124,7 @@ def get_rgba(ais): return color.redF(), color.greenF(), color.blueF(), alpha @pytest.fixture -def main(qtbot: QtBot, mocker): +def main(qtbot,mocker): mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.Yes) @@ -147,14 +142,15 @@ def main(qtbot: QtBot, mocker): return qtbot, win @pytest.fixture -def main_clean(qtbot: QtBot, mocker): +def main_clean(qtbot,mocker): mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.Yes) win = MainWindow() + win.show() + qtbot.addWidget(win) - with qtbot.waitExposed(win, timeout=TIMEOUT): - win.show() + qtbot.waitForWindowShown(win) editor = win.components['editor'] editor.set_text(code) @@ -162,14 +158,15 @@ def main_clean(qtbot: QtBot, mocker): return qtbot, win @pytest.fixture -def main_clean_do_not_close(qtbot: QtBot, mocker): +def main_clean_do_not_close(qtbot,mocker): mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.No) win = MainWindow() + win.show() + qtbot.addWidget(win) - with qtbot.waitExposed(win, timeout=TIMEOUT): - win.show() + qtbot.waitForWindowShown(win) editor = win.components['editor'] editor.set_text(code) @@ -177,15 +174,16 @@ def main_clean_do_not_close(qtbot: QtBot, mocker): return qtbot, win @pytest.fixture -def main_multi(qtbot: QtBot, mocker): +def main_multi(qtbot,mocker): mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.Yes) mocker.patch.object(QFileDialog, 'getSaveFileName', return_value=('out.step','')) win = MainWindow() + win.show() + qtbot.addWidget(win) - with qtbot.waitExposed(win, timeout=TIMEOUT): - win.show() + qtbot.waitForWindowShown(win) editor = win.components['editor'] editor.set_text(code_multi) @@ -573,7 +571,7 @@ def test_traceback(main): assert(traceback_view.tree.root.childCount() == 3) # 1 in user code + 2 in CQ code @pytest.fixture -def editor(qtbot: QtBot): +def editor(qtbot): win = Editor() win.show() @@ -665,6 +663,8 @@ def test_editor_autoreload(monkeypatch,editor): qtbot, editor = editor + TIMEOUT = 500 + # start out with autoreload enabled editor.autoreload(True) @@ -713,6 +713,7 @@ def test_autoreload_nested(editor): qtbot, editor = editor + TIMEOUT = 500 editor.autoreload(True) editor.preferences['Autoreload: watch imported modules'] = True @@ -746,10 +747,9 @@ def test_console(main): assert(len(a) == 1) # test print_text - text_before = console._control.document().toPlainText() - console.print_text('foo') - text_after = console._control.document().toPlainText() - assert text_after == text_before + 'foo' + pos_orig = console._prompt_pos + console.print_text('a') + assert(console._prompt_pos == pos_orig + len('a')) def test_viewer(main): @@ -1440,6 +1440,7 @@ def makebox(z): def test_reload_import_handle_error(tmp_path, main): + TIMEOUT = 500 qtbot, win = main editor = win.components["editor"] debugger = win.components["debugger"] @@ -1480,6 +1481,7 @@ def test_reload_import_handle_error(tmp_path, main): def test_modulefinder(tmp_path, main): + TIMEOUT = 500 qtbot, win = main editor = win.components["editor"] debugger = win.components["debugger"]