class MainDialog(DialogBase): """Main dialog for the anaconda navgator updater.""" # Signals sig_application_updated = Signal() sig_ready = Signal() # Class variables PACKAGE = 'anaconda-navigator' WIDTH = 450 HEIGHT = 200 def __init__(self, latest_version=None, prefix=None): """Main dialog for the anaconda navgator updater.""" super(MainDialog, self).__init__() # Variables self.api = CondaAPI() self.prefix = prefix or os.environ.get('CONDA_PREFIX', self.api.ROOT_PREFIX) self.info = {} self.first_run = True self.setup_ready = False self.busy = False self.up_to_date = False self.error = False self.success = False self.status = '' self.current_version = None self.latest_version = latest_version self.style_sheet = load_style_sheet() self.timer = QTimer() self.timer_2 = QTimer() self._windows_appusermodelid = None # Widgets self.message_box = None # For testing self.label_icon = QSvgWidget() self.label_message = LabelBase( "There's a new version of Anaconda Navigator available. " "We strongly recommend you to update.") self.label_status = LabelBase('') self.progress_bar = QProgressBar() self.button_cancel = ButtonNormal('Dismiss') self.button_update = ButtonPrimary('Update now') self.button_launch = ButtonPrimary('Launch Navigator') # Widgets setup if WIN: self._windows_appusermodelid = set_windows_appusermodelid() self.setMinimumSize(self.WIDTH, self.HEIGHT) self.label_message.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.label_message.setWordWrap(True) self.label_status.setWordWrap(True) self.button_update.setAutoDefault(True) self.button_launch.setAutoDefault(True) self.button_cancel.setFocusPolicy(Qt.NoFocus) self.timer.setInterval(1000) self.timer_2.setInterval(5000) self.progress_bar.setTextVisible(False) self.progress_bar.setStyleSheet(self.style_sheet) self.label_icon.load(images.ANACONDA_LOGO) self.label_icon.setMaximumSize(QSize(64, 64)) self.label_icon.setMinimumSize(QSize(64, 64)) self.setWindowTitle('Anaconda Navigator Updater') self.progress_bar.setMaximumWidth(self.WIDTH / 3) self.setMinimumWidth(self.WIDTH) self.setMaximumWidth(self.WIDTH) self.setMinimumHeight(self.HEIGHT) # Layouts layout_status = QHBoxLayout() layout_status.addWidget(self.label_status) layout_status.addWidget(SpacerHorizontal()) layout_status.addWidget(self.progress_bar) layout_text = QVBoxLayout() layout_text.addWidget(self.label_message) layout_text.addStretch() layout_text.addWidget(SpacerVertical()) layout_text.addLayout(layout_status) layout_icon = QVBoxLayout() layout_icon.addWidget(self.label_icon) layout_icon.addStretch() layout_top = QHBoxLayout() layout_top.addLayout(layout_icon) layout_top.addWidget(SpacerHorizontal()) layout_top.addLayout(layout_text) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_update) layout_buttons.addWidget(self.button_launch) layout = QVBoxLayout() layout.addLayout(layout_top) layout.addWidget(SpacerVertical()) layout.addWidget(SpacerVertical()) layout.addStretch() layout.addLayout(layout_buttons) self.setLayout(layout) # Signals self.button_update.clicked.connect(self.install_update) self.button_cancel.clicked.connect(self.reject) self.button_launch.clicked.connect(self.launch) self.timer.timeout.connect(self.refresh) self.timer_2.timeout.connect(self.check_conditions) # Setup self.timer.start() self.timer_2.start() self.check_conditions() self.refresh() def check_conditions(self): """Check every 5 seconds installed packages in case codna was used.""" packages = self.api.linked(prefix=self.prefix) package = [p for p in packages if self.PACKAGE in p] if package: n, v, b = self.api.split_canonical_name(package[0]) self.current_version = v else: self.current_version = None if self.latest_version is None: worker_search = self.api.search(self.PACKAGE, platform=self.api.get_platform()) worker_search.sig_finished.connect(self._search_callback) else: worker = self.api.info() worker.sig_finished.connect(self.setup) self.check_versions() def check_versions(self): """Check if navigator is up to date.""" if self.latest_version and self.current_version: from distutils.version import LooseVersion cur_ver = LooseVersion(self.current_version) lat_ver = LooseVersion(self.latest_version) self.up_to_date = cur_ver >= lat_ver else: self.up_to_date = False def _search_callback(self, worker, output, error): """Setup the widget.""" if isinstance(output, dict): packages = output.get(self.PACKAGE, []) versions = [package.get('version') for package in packages] unique_versions = [] for version in versions: if version not in unique_versions: unique_versions.append(version) if unique_versions: self.latest_version = unique_versions[-1] self.check_versions() worker = self.api.info() worker.sig_finished.connect(self.setup) self.refresh() def setup(self, worker, info, error): """Setup the widget.""" self.info = info self.setup_ready = True self.sig_ready.emit() self.refresh() if self.button_update.isVisible(): self.button_update.setFocus() if self.button_launch.isVisible(): self.button_launch.setFocus() def update_style_sheet(self): """Update custom CSS style sheet.""" self.style_sheet = load_style_sheet() self.setStyleSheet(self.style_sheet) def refresh(self): """Refresh enabled/disabled status of widgets.""" current_version = 'Not installed' if self.current_version: current_version = self.current_version latest_version = '-' if self.latest_version: latest_version = self.latest_version main_message = ( "Current version: <i>{0}</i><br>" "Available version: <b>{1}</b><br>").format( current_version, latest_version) message = self.status running = self.check_running() self.button_launch.setVisible(False) if not self.setup_ready: self.button_update.setDisabled(True) self.progress_bar.setVisible(True) message = 'Updating index...' self.update_status(message) elif self.busy: self.button_update.setDisabled(True) self.progress_bar.setVisible(True) else: self.progress_bar.setVisible(False) if running: message = 'Please close Anaconda Navigator before updating.' self.button_update.setDisabled(running) elif not running: self.button_update.setDisabled(False) if self.success and self.current_version: message = 'Anaconda Navigator was updated successfully.' self.button_update.setVisible(False) self.button_launch.setVisible(True) elif self.up_to_date: message = 'Anaconda Navigator is already up to date.' self.button_update.setVisible(False) self.button_launch.setVisible(True) elif not self.error: self.button_update.setVisible(True) if self.current_version: message = ('An update for Anaconda Navigator is now ' 'available.') self.button_update.setText('Update now') else: message = ( 'Anaconda Navigator is available for install.') self.button_update.setText('Install now') if self.error: self.button_update.setDisabled(False) message = 'Cannot update Anaconda Navigator, <b>{0}</b>' message = message.format(self.error) self.label_status.setText(message) self.label_message.setText(main_message) def update_status(self, status='', value=-1, max_val=-1): """Update progress bar and message status.""" if status: self.status = status self.label_status.setText(status) if value < 0 and max_val < 0: self.progress_bar.setRange(0, 0) else: self.progress_bar.setMinimum(0) self.progress_bar.setMaximum(max_val) self.progress_bar.setValue(value) def check_running(self): """Check if Anaconda Navigator is running.""" # Create file lock lock = filelock.FileLock(NAVIGATOR_LOCKFILE) try: running = False with lock.acquire(timeout=0.01): pass except filelock.Timeout: running = True return running # --- Conda actions and helpers # ------------------------------------------------------------------------- def partial_output_ready(self, worker, output, error): """Handle conda partial output ready.""" self.busy = True # print(type(output)) # print(output) # Get errors and data from ouput if it exists fetch = None if output and isinstance(output, dict): fetch = output.get('fetch') max_val = output.get('maxval', -1) value = output.get('progress', -1) if fetch: status = 'Fetching <b>{0}</b>...'.format(fetch) self.update_status(status=status, max_val=max_val, value=value) def output_ready(self, worker, output, error): """Handle conda output ready.""" self.check_conditions() # Get errors and data from ouput if it exists error_text = output.get('error', '') exception_type = output.get('exception_type', '') exception_name = output.get('exception_name', '') success = output.get('success') actions = output.get('actions', {}) # op_order = output.get('op_order', []) # action_check_fetch = actions.get('CHECK_FETCH', []) # action_rm_fetch = actions.get('RM_FETCHED', []) # action_fetch = actions.get('FETCH', []) # action_check_extract = actions.get('CHECK_EXTRACT', []) # action_rm_extract = actions.get('RM_EXTRACTED', []) # action_extract = actions.get('EXTRACT', []) # action_unlink = actions.get('UNLINK', []) action_link = actions.get('LINK', []) # action_symlink_conda = actions.get('SYMLINK_CONDA', []) self.busy = False # Get errors from json output if error_text or exception_type or exception_name or not success: self.error = exception_name self.success = False self.up_to_date = False elif success and action_link: self.sig_application_updated.emit() self.error = None self.success = True self.up_to_date = False elif success: self.success = False self.error = None self.up_to_date = True worker.lock.release() self.refresh() def install_update(self): """Install the specified version or latest version of navigator.""" self.busy = True self.refresh() # conda_prefix = self.info.et('conda_prefix') # root_prefix = self.info.et('root_prefix') navigator_prefixes = [ # os.path.join(self.api.ROOT_PREFIX, 'envs', '_navigator_'), # os.path.join(self.api.ROOT_PREFIX, 'envs', '_conda_'), self.prefix, ] for prefix in navigator_prefixes: if self.api.environment_exists(prefix=prefix): break if self.latest_version: pkgs = ['{0}=={1}'.format(self.PACKAGE, self.latest_version)] else: pkgs = [self.PACKAGE.format(self.latest_version)] # Lock Navigator lock = filelock.FileLock(NAVIGATOR_LOCKFILE) lock.acquire() worker = self.api.install(prefix=prefix, pkgs=pkgs) worker.lock = lock worker.sig_partial.connect(self.partial_output_ready) worker.sig_finished.connect(self.output_ready) self.refresh() if self.prefix == self.api.ROOT_PREFIX: name = 'root' else: name = os.path.basename(self.prefix) self.button_launch.setFocus() if self.current_version: msg = 'Updating package on <b>{0}</b>...'.format(name) else: msg = 'Installing package on <b>{0}</b>...'.format(name) self.update_status(msg) def launch(self): """Launch Anaconda Navigator.""" leave_path_alone = True root_prefix = self.api.ROOT_PREFIX prefix = self.prefix command = ['anaconda-navigator'] # Use the app bundle on OSX if MAC: command = ['open', os.path.join(prefix, 'Anaconda-Navigator.app')] launch_cmd( prefix, command, leave_path_alone, package_name='anaconda-navigator-app', root_prefix=root_prefix, ) self.close() # --- Qt Overrides # ------------------------------------------------------------------------- def reject(self): """Override Qt method.""" if self.busy: msg_box = MessageBoxQuestion(title='Quit Navigator Updater?', text='Anaconda Navigator is being ' 'updated. <br><br>' 'Are you sure you want to quit?') if msg_box.exec_(): super(MainDialog, self).reject() else: super(MainDialog, self).reject()
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)