class FileProgressBar(QWidget): """Simple progress bar with a label""" MAX_LABEL_LENGTH = 60 def __init__(self, parent, *args, **kwargs): QWidget.__init__(self, parent) self.pap = parent self.status_text = QLabel(self) self.bar = QProgressBar(self) self.bar.setRange(0, 0) layout = QVBoxLayout() layout.addWidget(self.status_text) layout.addWidget(self.bar) self.setLayout(layout) def __truncate(self, text): ellipsis = '...' part_len = (self.MAX_LABEL_LENGTH - len(ellipsis)) / 2.0 left_text = text[:int(math.ceil(part_len))] right_text = text[-int(math.floor(part_len)):] return left_text + ellipsis + right_text @Slot(str, int) def set_label_file(self, file, size): text = self.__truncate(file) status_str = 'Downloading file list: {0} ({1})'.format( text, humanize.naturalsize(size)) self.status_text.setText(status_str) def set_bounds(self, a, b): self.bar.setRange(a, b) def reset_files(self): self.status_text.setText(" Downloading file(s)...") self.bar.show() def reset_status(self): self.status_text.setText(" Download Complete!") self.bar.hide() @Slot(str, int, int, int) def update_progress(self, file, num_chunks, bytes_recv, total_bytes): text = " Downloading {0} - {1}/{2} (Chunk {3})" self.status_text.setText( text.format(file, humanize.naturalsize(bytes_recv), humanize.naturalsize(total_bytes), num_chunks)) self.bar.setValue(bytes_recv)
def __init__(self, parent=None): QWidget.__init__(self, parent) self.home_url = None self.webview = WebView(self) self.webview.loadFinished.connect(self.load_finished) self.webview.titleChanged.connect(self.setWindowTitle) self.webview.urlChanged.connect(self.url_changed) home_button = create_toolbutton(self, icon=ima.icon('home'), tip=_("Home"), triggered=self.go_home) zoom_out_button = action2button(self.webview.zoom_out_action) zoom_in_button = action2button(self.webview.zoom_in_action) pageact2btn = lambda prop: action2button(self.webview.pageAction(prop), parent=self.webview) refresh_button = pageact2btn(QWebEnginePage.Reload) stop_button = pageact2btn(QWebEnginePage.Stop) previous_button = pageact2btn(QWebEnginePage.Back) next_button = pageact2btn(QWebEnginePage.Forward) stop_button.setEnabled(False) self.webview.loadStarted.connect(lambda: stop_button.setEnabled(True)) self.webview.loadFinished.connect(lambda: stop_button.setEnabled(False)) progressbar = QProgressBar(self) progressbar.setTextVisible(False) progressbar.hide() self.webview.loadStarted.connect(progressbar.show) self.webview.loadProgress.connect(progressbar.setValue) self.webview.loadFinished.connect(lambda _state: progressbar.hide()) label = QLabel(self.get_label()) self.url_combo = UrlComboBox(self) self.url_combo.valid.connect(self.url_combo_activated) if not WEBENGINE: self.webview.iconChanged.connect(self.icon_changed) self.find_widget = FindReplace(self) self.find_widget.set_editor(self.webview) self.find_widget.hide() find_button = create_toolbutton(self, icon=ima.icon('find'), tip=_("Find text"), toggled=self.toggle_find_widget) self.find_widget.visibility_changed.connect(find_button.setChecked) hlayout = QHBoxLayout() for widget in (previous_button, next_button, home_button, find_button, label, self.url_combo, zoom_out_button, zoom_in_button, refresh_button, progressbar, stop_button): hlayout.addWidget(widget) layout = QVBoxLayout() layout.addLayout(hlayout) layout.addWidget(self.webview) layout.addWidget(self.find_widget) self.setLayout(layout)
def __init__(self, parent=None, options_button=None, handle_links=True): QWidget.__init__(self, parent) self.home_url = None self.webview = WebView(self, handle_links=handle_links) self.webview.setup() self.webview.loadFinished.connect(self.load_finished) self.webview.titleChanged.connect(self.setWindowTitle) self.webview.urlChanged.connect(self.url_changed) home_button = create_toolbutton(self, icon=ima.icon('home'), tip=_("Home"), triggered=self.go_home) zoom_out_button = action2button(self.webview.zoom_out_action) zoom_in_button = action2button(self.webview.zoom_in_action) def pageact2btn(prop, icon=None): return action2button(self.webview.pageAction(prop), parent=self.webview, icon=icon) refresh_button = pageact2btn(QWebEnginePage.Reload, icon=ima.icon('refresh')) stop_button = pageact2btn(QWebEnginePage.Stop, icon=ima.icon('stop')) previous_button = pageact2btn(QWebEnginePage.Back, icon=ima.icon('previous')) next_button = pageact2btn(QWebEnginePage.Forward, icon=ima.icon('next')) stop_button.setEnabled(False) self.webview.loadStarted.connect(lambda: stop_button.setEnabled(True)) self.webview.loadFinished.connect( lambda: stop_button.setEnabled(False)) progressbar = QProgressBar(self) progressbar.setTextVisible(False) progressbar.hide() self.webview.loadStarted.connect(progressbar.show) self.webview.loadProgress.connect(progressbar.setValue) self.webview.loadFinished.connect(lambda _state: progressbar.hide()) label = QLabel(self.get_label()) self.url_combo = UrlComboBox(self) self.url_combo.valid.connect(self.url_combo_activated) if not WEBENGINE: self.webview.iconChanged.connect(self.icon_changed) self.find_widget = FindReplace(self) self.find_widget.set_editor(self.webview) self.find_widget.hide() find_button = create_toolbutton(self, icon=ima.icon('find'), tip=_("Find text"), toggled=self.toggle_find_widget) self.find_widget.visibility_changed.connect(find_button.setChecked) hlayout = QHBoxLayout() for widget in (previous_button, next_button, home_button, find_button, label, self.url_combo, zoom_out_button, zoom_in_button, refresh_button, progressbar, stop_button): hlayout.addWidget(widget) if options_button: hlayout.addWidget(options_button) layout = create_plugin_layout(hlayout) layout.addWidget(self.webview) layout.addWidget(self.find_widget) self.setLayout(layout)
class GcodeBackplot(QBackPlot): line_selected = Signal(int) gcode_error = Signal(str) def __init__(self, parent=None, standalone=False): super(GcodeBackplot, self).__init__(parent) # This prevents doing unneeded initialization # when QtDesginer loads the plugin. if parent is None and not standalone: return self.show_overlay = False # no DRO or DRO overlay self.program_alpha = True self.grid_size = 1 self._reload_filename = None # Add loading progress bar and abort button self.progressBar = QProgressBar(visible=False) self.progressBar.setFormat("Loading backplot: %p%") self.abortButton = QPushButton('Abort', visible=False) hBox = QHBoxLayout() hBox.addWidget(self.progressBar) hBox.addWidget(self.abortButton) vBox = QVBoxLayout(self) vBox.addStretch() vBox.addLayout(hBox) self.abortButton.clicked.connect(self.abort) STATUS.actual_position.onValueChanged(self.update) STATUS.joint_actual_position.onValueChanged(self.update) STATUS.homed.onValueChanged(self.update) STATUS.limit.onValueChanged(self.update) STATUS.tool_in_spindle.onValueChanged(self.update) STATUS.motion_mode.onValueChanged(self.update) STATUS.current_vel.onValueChanged(self.update) STATUS.g5x_offset.onValueChanged(self.reloadBackplot) STATUS.g92_offset.onValueChanged(self.reloadBackplot) # Connect status signals STATUS.file.notify(self.loadBackplot) # STATUS.reload_backplot.notify(self.reloadBackplot) STATUS.program_units.notify(lambda v: self.setMetricUnits(v == 2)) def loadBackplot(self, fname): LOG.debug('load the display: {}'.format(fname.encode('utf-8'))) self._reload_filename = fname self.load(fname) @Slot() def reloadBackplot(self): QTimer.singleShot(100, lambda: self._reloadBackplot()) def _reloadBackplot(self): LOG.debug('reload the display: {}'.format(self._reload_filename)) dist = self.get_zoom_distance() try: self.load(self._reload_filename) self.set_zoom_distance(dist) except: LOG.warning("Problem reloading backplot file: {}".format(self._reload_filename), exc_info=True) # ========================================================================== # Override QBackPlot methods # ========================================================================== def report_loading_started(self): self.progressBar.show() self.abortButton.show() self.start = time.time() def report_progress_percentage(self, percentage): QApplication.processEvents() self.progressBar.setValue(percentage) def report_loading_finished(self): print((time.time() - self.start)) self.progressBar.hide() self.abortButton.hide() # overriding functions def report_gcode_error(self, result, seq, filename): error = gcode.strerror(result) file = os.path.basename(filename) line = seq - 1 msg = "G-code error in '{}' near line {}: {}".format(file, line, error) LOG.error(msg) STATUS.backplot_gcode_error.emit(msg) # Override gremlin's / glcannon.py function so we can emit a GObject signal def update_highlight_variable(self, line): self.highlight_line = line if line is None: line = -1 STATUS.backplot_line_selected.emit(line) # ============================================================================== # QtDesigner property setters/getters # ============================================================================== @Slot(str) def setView(self, view): view = view.lower() if self.is_lathe: if view not in ['p', 'y', 'y2']: return False elif view not in ['p', 'x', 'y', 'z', 'z2']: return False self.current_view = view if self.initialised: self.set_current_view() def getView(self): return self.current_view defaultView = Property(str, getView, setView) @Slot() def setViewP(self): self.setView('p') @Slot() def setViewX(self): self.setView('x') @Slot() def setViewY(self): self.setView('y') @Slot() def setViewZ(self): self.setView('z') @Slot() def setViewZ2(self): self.setView('z2') @Slot() def clearLivePlot(self): self.clear_live_plotter() @Slot() def zoomIn(self): self.zoomin() @Slot() def zoomOut(self): self.zoomout() @Slot(bool) def alphaBlend(self, alpha): self.program_alpha = alpha self.update() @Slot(bool) def showGrid(self, grid): self.grid_size = int(grid) # ugly hack for now self.update() # @Slot(str) Fixme check for the correct data type def setdro(self, state): self.enable_dro = state self.updateGL() def getdro(self): return self.enable_dro _dro = Property(bool, getdro, setdro) # DTG # @Slot(str) Fixme check for the correct data type def setdtg(self, state): self.show_dtg = state self.updateGL() def getdtg(self): return self.show_dtg _dtg = Property(bool, getdtg, setdtg) # METRIC # @Slot(str) Fixme check for the correct data type def setMetricUnits(self, metric): self.metric_units = metric self.updateGL() def getMetricUnits(self): return self.metric_units metricUnits = Property(bool, getMetricUnits, setMetricUnits) # @Slot(str) Fixme check for the correct data type def setProgramAlpha(self, alpha): self.program_alpha = alpha self.updateGL() def getProgramAlpha(self): return self.program_alpha renderProgramAlpha = Property(bool, getProgramAlpha, setProgramAlpha) # @Slot(str) Fixme check for the correct data type def setBackgroundColor(self, color): self.colors['back'] = color.getRgbF()[:3] self.updateGL() def getBackgroundColor(self): r, g, b = self.colors['back'] color = QColor() color.setRgbF(r, g, b, 1.0) return color backgroundColor = Property(QColor, getBackgroundColor, setBackgroundColor)
class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) uic.loadUi(f'{pathlib.Path(__file__).parent}/UI/mainwindow.ui', self) self.setWindowTitle('BlastSightDM') self.setWindowIcon(IconCollection.get('blastsight.png')) self.toolbar.setWindowTitle('Toolbar') self.setFocusPolicy(Qt.StrongFocus) self.setAcceptDrops(True) self.statusBar.showMessage('Ready') # Attributes self.filters_dict = { 'mesh': { 'load': 'Mesh Files (*.dxf *.off *.h5m);;' 'DXF Files (*.dxf);;' 'OFF Files (*.off);;' 'H5M Files (*.h5m);;' 'All Files (*.*)', 'export': 'BlastSight Mesh (*.h5m);;' 'OFF File (*.off);;' }, 'block': { 'load': 'Block Files (*.csv *.h5p *.out);;' 'CSV Files (*.csv);;' 'H5P Files (*.h5p);;' 'GSLib Files (*.out);;' 'All Files (*.*)', 'export': 'BlastSight Blocks (*.h5p);;' 'CSV File (*.csv);;' }, 'point': { 'load': 'Point Files (*.csv *.h5p *.out);;' 'CSV Files (*.csv);;' 'H5P Files (*.h5p);;' 'GSLib Files (*.out);;' 'All Files (*.*)', 'export': 'BlastSight Points (*.h5p);;' 'CSV File (*.csv);;' }, 'line': { 'load': 'Line Files (*.csv *.dxf);;' 'CSV Files (*.csv);;' 'DXF Files (*.dxf);;' 'All Files (*.*)', 'export': 'CSV File (*.csv);;' }, 'tube': { 'load': 'Line Files (*.csv *.dxf);;' 'CSV Files (*.csv);;' 'DXF Files (*.dxf);;' 'All Files (*.*)', 'export': 'CSV File (*.csv);;' } } self.settings = QSettings('BlastSightDM', application='blastsight-dm', parent=self) # Progress bar (hidden by default) self.progress_bar = QProgressBar(self.statusBar) self.progress_bar.setValue(0) self.progress_bar.setMaximumWidth(self.width() / 5) self.progress_bar.hide() self.statusBar.addPermanentWidget(self.progress_bar) # Grid Widget self.grid_widget = GridWidget() self.grid_widget.connect_viewer(self.viewer) # XSection Widget self.xsection_widget = XSectionWidget() self.xsection_widget.connect_viewer(self.viewer) # Extra actions actions = self.toolbar.action_collection self.toolbar.addAction(actions.action_quit) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.generate_menubar() self.connect_actions() # Set auto-fit as True when starting the app if not actions.action_autofit.isChecked(): actions.action_autofit.trigger() # Set auto-rotate as True when starting the app if not actions.action_autorotate.isChecked(): actions.action_autorotate.trigger() # Set animated as True when starting the app if not actions.action_animated.isChecked(): actions.action_animated.trigger() # Set camera widget as hidden self.dockWidget_camera.hide() def generate_menubar(self) -> None: actions = self.toolbar.action_collection # File self.menu_File.addAction(actions.action_load_mesh) self.menu_File.addAction(actions.action_load_blocks) self.menu_File.addAction(actions.action_load_points) self.menu_File.addAction(actions.action_load_lines) self.menu_File.addAction(actions.action_load_tubes) self.menu_File.addSeparator() self.menu_File.addAction(actions.action_load_mesh_folder) self.menu_File.addAction(actions.action_load_blocks_folder) self.menu_File.addAction(actions.action_load_points_folder) self.menu_File.addAction(actions.action_load_lines_folder) self.menu_File.addAction(actions.action_load_tubes_folder) self.menu_File.addSeparator() self.menu_File.addAction(actions.action_quit) # View self.menu_View.addAction(actions.action_viewer_properties) self.menu_View.addAction(actions.action_plan_view) self.menu_View.addAction(actions.action_north_view) self.menu_View.addAction(actions.action_east_view) self.menu_View.addAction(actions.action_fit_to_screen) self.menu_View.addSeparator() self.menu_View.addAction(actions.action_perspective_projection) self.menu_View.addAction(actions.action_orthographic_projection) self.menu_View.addSeparator() self.menu_View.addAction(actions.action_grid) self.menu_View.addAction(actions.action_take_screenshot) # Tools self.menu_Tools.addAction(actions.action_slice_meshes) self.menu_Tools.addAction(actions.action_slice_blocks) self.menu_Tools.addAction(actions.action_slice_points) self.menu_Tools.addAction(actions.action_detection_controller) self.menu_Tools.addAction(actions.action_measurement_controller) self.menu_Tools.addSeparator() self.menu_Tools.addAction(actions.action_xsection) self.menu_Tools.addAction(actions.action_normal_controller) # Settings self.menu_Settings.addAction(actions.action_autofit) self.menu_Settings.addAction(actions.action_animated) self.menu_Settings.addAction(actions.action_autorotate) self.menu_Settings.addAction(actions.action_turbo_rendering) # Help self.menu_Help.addAction(actions.action_help) self.menu_Help.addAction(actions.action_about) def connect_actions(self) -> None: actions = self.toolbar.action_collection # Toolbar/Tree/Camera self.toolbar.connect_viewer(self.viewer) self.toolbar.connect_tree(self.dockWidget_tree) self.toolbar.connect_camera(self.dockWidget_camera) self.toolbar.connect_xsection(self.xsection_widget) self.toolbar.connect_grid(self.grid_widget) self.cameraWidget.connect_viewer(self.viewer) self.treeWidget.connect_viewer(self.viewer) self.treeWidget.enable_exportability(True) # File actions.action_load_mesh.triggered.connect(self.dialog_load_mesh) actions.action_load_blocks.triggered.connect(self.dialog_load_blocks) actions.action_load_points.triggered.connect(self.dialog_load_points) actions.action_load_lines.triggered.connect(self.dialog_load_lines) actions.action_load_tubes.triggered.connect(self.dialog_load_tubes) actions.action_load_mesh_folder.triggered.connect(self.dialog_load_mesh_folder) actions.action_load_blocks_folder.triggered.connect(self.dialog_load_blocks_folder) actions.action_load_points_folder.triggered.connect(self.dialog_load_points_folder) actions.action_load_lines_folder.triggered.connect(self.dialog_load_lines_folder) actions.action_load_tubes_folder.triggered.connect(self.dialog_load_tubes_folder) actions.action_quit.triggered.connect(self.close) # View actions.action_take_screenshot.triggered.connect(self.slot_screenshot) # Tools actions.action_slice_meshes.triggered.connect(self.slot_slice_meshes) actions.action_slice_blocks.triggered.connect(self.slot_slice_blocks) actions.action_slice_points.triggered.connect(self.slot_slice_points) actions.action_detection_controller.triggered.connect(self.slot_detection_controller) actions.action_measurement_controller.triggered.connect(self.slot_measurement_controller) actions.action_normal_controller.triggered.connect(self.slot_normal_controller) # Help actions.action_help.triggered.connect(self.slot_help) actions.action_about.triggered.connect(self.slot_about) # Viewer signals self.viewer.signal_fps_updated.connect(self.print_fps) self.viewer.signal_controller_updated.connect(self.slot_controller_updated) self.viewer.signal_elements_detected.connect(self.slot_elements_detected) self.viewer.signal_mesh_distances.connect(self.slot_mesh_distances) self.viewer.signal_load_success.connect(self.slot_element_load_success) self.viewer.signal_load_failure.connect(self.slot_element_load_failure) self.viewer.signal_export_success.connect(self.slot_element_export_success) self.viewer.signal_export_failure.connect(self.slot_element_export_failure) self.viewer.signal_process_updated.connect(self.slot_process_updated) self.viewer.signal_process_started.connect(self.slot_process_started) self.viewer.signal_process_finished.connect(self.slot_process_finished) # TreeWidget actions self.treeWidget.signal_export_element.connect(self._dialog_export_element) @property def last_dir(self) -> str: return self.settings.value('last_directory', '.') @last_dir.setter def last_dir(self, _last_dir: str) -> None: self.settings.setValue('last_directory', _last_dir) @staticmethod def print_fps(fps) -> None: print(f' \r', end='') print(f'FPS: {fps:.1f} \r', end='') """ Status bar updates """ def slot_element_load_success(self, _id: int) -> None: self.statusBar.showMessage(f'Load successful (id: {_id}).') def slot_element_load_failure(self) -> None: self.statusBar.showMessage(f'Failed to load.') def slot_element_export_success(self, _id: int) -> None: self.statusBar.showMessage(f'Export successful (id: {_id}).') def slot_element_export_failure(self) -> None: self.statusBar.showMessage(f'Failed to export.') def slot_controller_updated(self, name: str) -> None: self.statusBar.showMessage(f'Controller: {name}') def slot_mesh_distances(self, distance_dict: dict) -> None: self.statusBar.showMessage(f'Distance: {distance_dict.get("distance")}') def slot_elements_detected(self, attributes: list) -> None: id_list = sorted(map(lambda attr: attr.get('id', -1), attributes)) self.statusBar.showMessage(f'Detected elements: {id_list}') """ Slots for slices """ def handle_slices(self, description: dict, executer: callable) -> None: # Retrieve description vectors origin = description.get('origin') normal = description.get('normal') up = description.get('up') # Execute the callable over the elements executer(origin, normal) # Auto-rotate camera to meet cross-section actions = self.toolbar.action_collection if actions.action_autorotate.isChecked(): self.viewer.set_camera_from_vectors(normal, up) def slot_slice_meshes(self) -> None: def executer(origin, normal) -> None: slices = self.viewer.slice_meshes(origin, normal) self.add_mesh_slices(slices) def handler(description: dict) -> None: self.handle_slices(description, executer) # Disconnect self.viewer.set_normal_controller() self.viewer.signal_slice_description.disconnect() self.viewer.set_slice_controller() self.viewer.signal_slice_description.connect(handler) def slot_slice_blocks(self) -> None: def executer(origin, normal) -> None: slices = self.viewer.slice_blocks(origin, normal) self.add_block_slices(slices) def handler(description: dict) -> None: self.handle_slices(description, executer) # Disconnect self.viewer.set_normal_controller() self.viewer.signal_slice_description.disconnect() self.viewer.set_slice_controller() self.viewer.signal_slice_description.connect(handler) def slot_slice_points(self) -> None: def executer(origin, normal) -> None: slices = self.viewer.slice_points(origin, normal) self.add_point_slices(slices) def handler(description: dict) -> None: self.handle_slices(description, executer) # Disconnect self.viewer.set_normal_controller() self.viewer.signal_slice_description.disconnect() self.viewer.set_slice_controller() self.viewer.signal_slice_description.connect(handler) def add_mesh_slices(self, slice_list: list) -> None: def add_slice(description: dict) -> None: slices = description.get('vertices') mesh_id = description.get('element_id') mesh = self.viewer.get_drawable(mesh_id) def add_subslice(subslice, num: int) -> None: self.viewer.lines(vertices=subslice, color=mesh.color, name=f'MESHSLICE_{num}_{mesh.name}', extension='csv', loop=True) # Execute add_subslice for all subslices of the slice for i, ssl in enumerate(slices): add_subslice(ssl, i) # Execute add_slice over all slice descriptions for sl in slice_list: add_slice(sl) def add_block_slices(self, slice_list: list) -> None: def add_slice(description: dict) -> None: indices = description.get('indices') block_id = description.get('element_id') block = self.viewer.get_drawable(block_id) if block.is_slice: return self.viewer.blocks(vertices=block.vertices[indices], values=block.values[indices], color=block.color[indices], vmin=block.vmin, vmax=block.vmax, colormap=block.colormap, block_size=block.block_size, name=f'BLOCKSLICE_{block.name}', extension='csv', is_slice=True) # Execute add_slice over all slice descriptions for sl in slice_list: add_slice(sl) def add_point_slices(self, slice_list: list) -> None: def add_slice(description: dict) -> None: indices = description.get('indices') point_id = description.get('element_id') point = self.viewer.get_drawable(point_id) if point.is_slice: return self.viewer.points(vertices=point.vertices[indices], values=point.values[indices], color=point.color[indices], vmin=point.vmin, vmax=point.vmax, colormap=point.colormap, point_size=point.point_size, name=f'POINTSLICE_{point.name}', extension='csv', is_slice=True) # Execute add_slice over all slice descriptions for sl in slice_list: add_slice(sl) """ Common functionality for loading """ @staticmethod def _thread_runner(method: callable, *args, **kwargs) -> None: worker = ThreadWorker(method, *args, **kwargs) QThreadPool.globalInstance().start(worker) def _dialog_load_element(self, loader: classmethod, hint: str, *args, **kwargs) -> None: (paths, selected_filter) = QFileDialog.getOpenFileNames( parent=self, directory=self.last_dir, filter=self.filters_dict.get(hint).get('load')) # If path == '', then bool(path) is False path_list = sorted(filter(bool, paths)) if len(path_list) > 0: self.statusBar.showMessage(f'Loading {len(path_list)} element(s)...') self._thread_runner(self.viewer.load_multiple, path_list, loader, *args, **kwargs) self.last_dir = QFileInfo(path_list[-1]).absoluteDir().absolutePath() def _dialog_load_folder(self, loader: classmethod, *args, **kwargs) -> None: path = QFileDialog.getExistingDirectory( parent=self, directory=self.last_dir, options=QFileDialog.ShowDirsOnly) # Execute method if bool(path): self.statusBar.showMessage('Loading folder...') self._thread_runner(loader, path, *args, **kwargs) self.last_dir = path """ Slots for progress updates """ def slot_process_updated(self, value: int) -> None: self.progress_bar.setValue(value) def slot_process_started(self) -> None: self.progress_bar.setValue(0) self.progress_bar.show() def slot_process_finished(self,) -> None: self.progress_bar.hide() """ Slot for extra items in view """ def slot_screenshot(self) -> None: (path, selected_filter) = QFileDialog.getSaveFileName( parent=self.viewer, directory=f'BlastSight Screenshot ({datetime.now().strftime("%Y%m%d-%H%M%S")})', filter='PNG image (*.png);;') self.viewer.take_screenshot(path) """ Slots for loading files """ def dialog_load_mesh(self) -> None: self._dialog_load_element(loader=self.viewer.load_mesh, hint='mesh') def dialog_load_blocks(self) -> None: self._dialog_load_element(loader=self.viewer.load_blocks, hint='block') def dialog_load_points(self) -> None: self._dialog_load_element(loader=self.viewer.load_points, hint='point') def dialog_load_lines(self) -> None: self._dialog_load_element(loader=self.viewer.load_lines, hint='line') def dialog_load_tubes(self) -> None: self._dialog_load_element(loader=self.viewer.load_tubes, hint='tube') def dialog_load_mesh_folder(self) -> None: self._dialog_load_folder(loader=self.viewer.load_mesh_folder) def dialog_load_blocks_folder(self) -> None: self._dialog_load_folder(loader=self.viewer.load_blocks_folder) def dialog_load_points_folder(self) -> None: self._dialog_load_folder(loader=self.viewer.load_points_folder) def dialog_load_lines_folder(self) -> None: self._dialog_load_folder(loader=self.viewer.load_lines_folder) def dialog_load_tubes_folder(self) -> None: self._dialog_load_folder(loader=self.viewer.load_tubes_folder) """ Slots for exporting elements """ def _dialog_export_element(self, _id: int) -> None: element = self.viewer.get_drawable(_id).element proposed_path = QDir(self.last_dir).filePath(element.name) # TODO Check hints by element type filters = 'BlastSight Mesh (*.h5m);;'\ 'BlastSight Blocks/Points (*.h5p);;' (path, selected_filter) = QFileDialog.getSaveFileName( parent=self, directory=proposed_path, filter=filters) # Execute method if bool(path): self.statusBar.showMessage('Exporting...') self._thread_runner(self.viewer.export_element, path, _id) """ Slots for modifying interaction controllers """ def slot_normal_controller(self) -> None: self.viewer.set_normal_controller() def slot_detection_controller(self) -> None: self.viewer.set_detection_controller() def slot_measurement_controller(self) -> None: self.viewer.set_measurement_controller() """ Slots for showing help/about dialogs """ def slot_help(self) -> None: HelpDialog(self).exec_() def slot_about(self) -> None: AboutDialog(self).exec_() """ Events pass-through """ def dragEnterEvent(self, event, *args, **kwargs) -> None: self.viewer.dragEnterEvent(event, *args, **kwargs) def dropEvent(self, event, *args, **kwargs) -> None: self.viewer.dropEvent(event, *args, **kwargs)