def container_registry(application): MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-definitioncontainer", comment = "Uranium Definition Container", suffixes = ["def.json"] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-instancecontainer", comment = "Uranium Instance Container", suffixes = [ "inst.cfg" ] ) ) MimeTypeDatabase.addMimeType( MimeType( name = "application/x-uranium-containerstack", comment = "Uranium Container Stack", suffixes = [ "stack.cfg" ] ) ) Resources.addSearchPath(os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..", "Settings"))) ContainerRegistry._ContainerRegistry__instance = None # Reset the private instance variable every time PluginRegistry.getInstance().removeType("settings_container") ContainerRegistry.getInstance().load() return ContainerRegistry.getInstance()
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode): archive = VirtualFile() archive.openStream(stream, "application/x-ufp", OpenMode.WriteOnly) #Store the g-code from the scene. archive.addContentType(extension = "gcode", mime_type = "text/x-gcode") gcode_textio = StringIO() #We have to convert the g-code into bytes. PluginRegistry.getInstance().getPluginObject("GCodeWriter").write(gcode_textio, None) gcode = archive.getStream("/3D/model.gcode") gcode.write(gcode_textio.getvalue().encode("UTF-8")) archive.addRelation(virtual_path = "/3D/model.gcode", relation_type = "http://schemas.ultimaker.org/package/2018/relationships/gcode") #Store the thumbnail. if self._snapshot: archive.addContentType(extension = "png", mime_type = "image/png") thumbnail = archive.getStream("/Metadata/thumbnail.png") thumbnail_buffer = QBuffer() thumbnail_buffer.open(QBuffer.ReadWrite) thumbnail_image = self._snapshot thumbnail_image.save(thumbnail_buffer, "PNG") thumbnail.write(thumbnail_buffer.data()) archive.addRelation(virtual_path = "/Metadata/thumbnail.png", relation_type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail", origin = "/3D/model.gcode") else: Logger.log("d", "Thumbnail not created, cannot save it") archive.close() return True
def _createMonitorViewFromQML(self) -> None: if self._monitor_view_qml_path is None and PluginRegistry.getInstance() is not None: self._monitor_view_qml_path = os.path.join( PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting"), "resources", "qml", "MonitorStage.qml" ) super()._createMonitorViewFromQML()
def _read(self, file_name): with open(file_name, "rb") as file: file_data = file.read() uncompressed_gcode = gzip.decompress(file_data).decode("utf-8") PluginRegistry.getInstance().getPluginObject("GCodeReader").preReadFromStream(uncompressed_gcode) result = PluginRegistry.getInstance().getPluginObject("GCodeReader").readFromStream(uncompressed_gcode) return result
def _spawnPrinterSelectionDialog(self): if self._printer_selection_dialog is None: if PluginRegistry.getInstance() is not None: path = os.path.join( PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting"), "resources", "qml", "PrintWindow.qml" ) self._printer_selection_dialog = self._application.createQmlComponent(path, {"OutputDevice": self}) if self._printer_selection_dialog is not None: self._printer_selection_dialog.show()
def activeToolPanel(self): if not self._active_tool: return QUrl() try: panel_file = PluginRegistry.getInstance().getMetaData(self._active_tool.getPluginId())["tool"]["tool_panel"] except KeyError: return QUrl() return QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self._active_tool.getPluginId()), panel_file))
def _createView(self): ## Load all scripts in the scripts folder self.loadAllScripts(os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "scripts")) path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "PostProcessingPlugin.qml")) self._component = QQmlComponent(Application.getInstance()._engine, path) self._context = QQmlContext(Application.getInstance()._engine.rootContext()) self._context.setContextProperty("manager", self) self._view = self._component.create(self._context)
def __init__(self, device_id, address, properties, parent = None) -> None: super().__init__(device_id = device_id, address = address, properties=properties, connection_type = ConnectionType.NetworkConnection, parent = parent) self._api_prefix = "/cluster-api/v1/" self._application = CuraApplication.getInstance() self._number_of_extruders = 2 self._dummy_lambdas = ( "", {}, io.BytesIO() ) # type: Tuple[Optional[str], Dict[str, Union[str, int, bool]], Union[io.StringIO, io.BytesIO]] self._print_jobs = [] # type: List[UM3PrintJobOutputModel] self._received_print_jobs = False # type: bool if PluginRegistry.getInstance() is not None: plugin_path = PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting") if plugin_path is None: Logger.log("e", "Cloud not find plugin path for plugin UM3NetworkPrnting") raise RuntimeError("Cloud not find plugin path for plugin UM3NetworkPrnting") self._monitor_view_qml_path = os.path.join(plugin_path, "resources", "qml", "MonitorStage.qml") # Trigger the printersChanged signal when the private signal is triggered self.printersChanged.connect(self._clusterPrintersChanged) self._accepts_commands = True # type: bool # Cluster does not have authentication, so default to authenticated self._authentication_state = AuthState.Authenticated self._error_message = None # type: Optional[Message] self._write_job_progress_message = None # type: Optional[Message] self._progress_message = None # type: Optional[Message] self._active_printer = None # type: Optional[PrinterOutputModel] self._printer_selection_dialog = None # type: QObject self.setPriority(3) # Make sure the output device gets selected above local file output self.setName(self._id) self.setShortDescription(i18n_catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print over network")) self.setDescription(i18n_catalog.i18nc("@properties:tooltip", "Print over network")) self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network")) self._printer_uuid_to_unique_name_mapping = {} # type: Dict[str, str] self._finished_jobs = [] # type: List[UM3PrintJobOutputModel] self._cluster_size = int(properties.get(b"cluster_size", 0)) # type: int self._latest_reply_handler = None # type: Optional[QNetworkReply] self._sending_job = None self._active_camera_url = QUrl() # type: QUrl
def __init__(self, api_client: CloudApiClient, cluster: CloudClusterResponse, parent: QObject = None) -> None: # The following properties are expected on each networked output device. # Because the cloud connection does not off all of these, we manually construct this version here. # An example of why this is needed is the selection of the compatible file type when exporting the tool path. properties = { b"address": b"", b"name": cluster.host_name.encode() if cluster.host_name else b"", b"firmware_version": cluster.host_version.encode() if cluster.host_version else b"", b"printer_type": b"" } super().__init__(device_id = cluster.cluster_id, address = "", connection_type = ConnectionType.CloudConnection, properties = properties, parent = parent) self._api = api_client self._cluster = cluster self._setInterfaceElements() self._account = api_client.account # We use the Cura Connect monitor tab to get most functionality right away. if PluginRegistry.getInstance() is not None: self._monitor_view_qml_path = os.path.join( PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting"), "resources", "qml", "MonitorStage.qml" ) # Trigger the printersChanged signal when the private signal is triggered. self.printersChanged.connect(self._clusterPrintersChanged) # We keep track of which printer is visible in the monitor page. self._active_printer = None # type: Optional[PrinterOutputModel] # Properties to populate later on with received cloud data. self._print_jobs = [] # type: List[UM3PrintJobOutputModel] self._number_of_extruders = 2 # All networked printers are dual-extrusion Ultimaker machines. # We only allow a single upload at a time. self._progress = CloudProgressMessage() # Keep server string of the last generated time to avoid updating models more than once for the same response self._received_printers = None # type: Optional[List[CloudClusterPrinterStatus]] self._received_print_jobs = None # type: Optional[List[CloudClusterPrintJobStatus]] # A set of the user's job IDs that have finished self._finished_jobs = set() # type: Set[str] # Reference to the uploaded print job / mesh self._tool_path = None # type: Optional[bytes] self._uploaded_print_job = None # type: Optional[CloudPrintJobResponse]
def _onToolsChanged(self): items = [] tools = self._controller.getAllTools() for name in tools: toolMetaData = PluginRegistry.getInstance().getMetaData(name).get("tool", {}) # Skip tools that are marked as not visible if "visible" in toolMetaData and not toolMetaData["visible"]: continue # Optional metadata elements description = toolMetaData.get("description", "") iconName = toolMetaData.get("icon", "default.png") weight = toolMetaData.get("weight", 0) enabled = self._controller.getTool(name).getEnabled() items.append({ "id": name, "name": toolMetaData.get("name", name), "icon": iconName, "active": False, "enabled": enabled, "description": description, "weight": weight }) items.sort(key = lambda t: t["weight"]) self.setItems(items)
def loadChangeLogs(self): self._change_logs = collections.OrderedDict() with open( os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r", -1, "utf-8", ) as f: open_version = None open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog for line in f: line = line.replace("\n", "") if "[" in line and "]" in line: line = line.replace("[", "") line = line.replace("]", "") open_version = Version(line) open_header = "" self._change_logs[open_version] = collections.OrderedDict() elif line.startswith("*"): open_header = line.replace("*", "") self._change_logs[open_version][open_header] = [] elif line != "": if open_header not in self._change_logs[open_version]: self._change_logs[open_version][open_header] = [] self._change_logs[open_version][open_header].append(line)
def qmlPath(self) -> "QUrl": plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId()) if plugin_path is None: Logger.log("e", "Cannot create QML view: cannot find plugin path for plugin [%s]", self.getPluginId()) return QUrl("") path = os.path.join(plugin_path, self._qml_url) return QUrl.fromLocalFile(path)
def createChangelogWindow(self): path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.qml")) component = QQmlComponent(Application.getInstance()._engine, path) self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext()) self._changelog_context.setContextProperty("manager", self) self._changelog_window = component.create(self._changelog_context)
def importProfile(self, file_name): if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")} plugin_registry = PluginRegistry.getInstance() for plugin_id, meta_data in self._getIOPlugins("profile_reader"): profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. except Exception as e: #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e)) return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))} if profile_or_list: # Success! name_seed = os.path.splitext(os.path.basename(file_name))[0] if type(profile_or_list) is not list: profile = profile_or_list self._configureProfile(profile, name_seed) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } else: for profile in profile_or_list: self._configureProfile(profile, name_seed) if len(profile_or_list) == 1: return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())} else: profile_names = ", ".join([profile.getName() for profile in profile_or_list]) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profiles {0}", profile_names) } #If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
def _update(self) -> None: items = [] views = self._controller.getAllViews() current_view = self._controller.getActiveView() if current_view is None: return for view_id in views: view_meta_data = PluginRegistry.getInstance().getMetaData(view_id).get("view", {}) # Skip view modes that are marked as not visible if "visible" in view_meta_data and not view_meta_data["visible"]: continue # Metadata elements name = view_meta_data.get("name", view_id) description = view_meta_data.get("description", "") icon_name = view_meta_data.get("icon", "") weight = view_meta_data.get("weight", 0) items.append({ "id": view_id, "name": name, "active": view_id == current_view.getPluginId(), "description": description, "icon": icon_name, "weight": weight }) items.sort(key = lambda t: t["weight"]) self.setItems(items)
def _onEngineCreated(self) -> None: plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId()) if plugin_path: self.addDisplayComponent("main", os.path.join(plugin_path, "SimulationViewMainComponent.qml")) self.addDisplayComponent("menu", os.path.join(plugin_path, "SimulationViewMenuComponent.qml")) else: Logger.log("e", "Unable to find the path for %s", self.getPluginId())
def _createConfigUI(self): if self._ui_view is None: Logger.log("d", "Creating ImageReader config UI") path = os.path.join(PluginRegistry.getInstance().getPluginPath("ImageReader"), "ConfigUI.qml") self._ui_view = Application.getInstance().createQmlComponent(path, {"manager": self}) self._ui_view.setFlags(self._ui_view.flags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowMinimizeButtonHint & ~Qt.WindowMaximizeButtonHint); self._disable_size_callbacks = False
def _createViewFromQML(self): path = QUrl.fromLocalFile( os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), self._qml_url)) self._component = QQmlComponent(Application.getInstance()._engine, path) self._context = QQmlContext(Application.getInstance()._engine.rootContext()) self._context.setContextProperty("manager", self) self._view = self._component.create(self._context)
def importProfile(self, file_name): if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")} plugin_registry = PluginRegistry.getInstance() for plugin_id, meta_data in self._getIOPlugins("profile_reader"): profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile = profile_reader.read(file_name) #Try to open the file with the profile reader. except Exception as e: #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e)) return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))} if profile: #Success! profile.setReadOnly(False) new_name = self.createUniqueName("quality", "", os.path.splitext(os.path.basename(file_name))[0], catalog.i18nc("@label", "Custom profile")) profile.setName(new_name) profile._id = new_name if self._machineHasOwnQualities(): profile.setDefinition(self._activeDefinition()) if self._machineHasOwnMaterials(): profile.addMetaDataEntry("material", self._activeMaterialId()) else: profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0]) ContainerRegistry.getInstance().addContainer(profile) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } #If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
def __init__(self, current_versions): self._version_upgrades = {} #For each config type and each version, gives a set of upgrade plug-ins that can convert them to something else. self._get_version_functions = {} #For each config type, gives a function with which to get the version number from those files. self._storage_paths = {} #For each config type, a set of storage paths to search for old config files. self._current_versions = current_versions #To know which preference versions and types to upgrade to. self._registry = PluginRegistry.getInstance() PluginRegistry.addType("version_upgrade", self._addVersionUpgrade)
def _createView(self): Logger.log("d", "Creating post processing plugin view.") ## Load all scripts in the scripts folder try: self.loadAllScripts(os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "scripts")) except Exception as e: print("Exception occured", e) # TODO: Debug code (far to general catch. Remove this once done testing) path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "PostProcessingPlugin.qml")) self._component = QQmlComponent(Application.getInstance()._engine, path) # We need access to engine (although technically we can't) self._context = QQmlContext(Application.getInstance()._engine.rootContext()) self._context.setContextProperty("manager", self) self._view = self._component.create(self._context) Logger.log("d", "Post processing view created.")
def spawnFirmwareInterface(self, serial_port): if self._firmware_view is None: path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("Doodle3D"), "SettingsWindow.qml")) component = QQmlComponent(Application.getInstance()._engine, path) self._firmware_context = QQmlContext(Application.getInstance()._engine.rootContext()) self._firmware_context.setContextProperty("manager", self) self._firmware_view = component.create(self._firmware_context) self._firmware_view.show()
def getWriterByMimeType(self, mime): writer_data = PluginRegistry.getInstance().getAllMetaData(filter = {"mesh_writer": {}}, active_only = True) for entry in writer_data: for output in entry["mesh_writer"].get("output", []): if mime == output["mime_type"]: return self._mesh_writers[entry["id"]] return None
def getWriterByMimeType(self, mime: str) -> Optional["FileWriter"]: writer_data = PluginRegistry.getInstance().getAllMetaData(filter={self._writer_type: {}}, active_only=True) for entry in writer_data: for output in entry[self._writer_type].get("output", []): if mime == output["mime_type"]: return self._writers[entry["id"]] return None
def createControlInterface(self): if self._control_view is None: Logger.log("d", "Creating control interface for printer connection") path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "ControlWindow.qml")) component = QQmlComponent(Application.getInstance()._engine, path) self._control_context = QQmlContext(Application.getInstance()._engine.rootContext()) self._control_context.setContextProperty("manager", self) self._control_view = component.create(self._control_context)
def __eq__(self, other: object) -> bool: if type(other) is not type(self): return False other = cast(ContainerProvider, other) plugin_registry = PluginRegistry.getInstance() my_metadata = plugin_registry.getMetaData(self.getPluginId()) other_metadata = plugin_registry.getMetaData(other.getPluginId()) return my_metadata["container_provider"]["priority"] == other_metadata["container_provider"]["priority"]
def _checkAlreadyInstalled(self, id): plugin_registry = PluginRegistry.getInstance() metadata = plugin_registry.getMetaData(id) if metadata != {}: return True else: if id in self._newly_installed_plugin_ids: return True # We already installed this plugin, but the registry just doesn't know it yet. return False
def _createSocket(self, protocol_file: str = None) -> None: if not protocol_file: plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId()) if not plugin_path: Logger.log("e", "Could not get plugin path!", self.getPluginId()) return protocol_file = os.path.abspath(os.path.join(plugin_path, "Cura.proto")) super()._createSocket(protocol_file) self._engine_is_fresh = True
def _createViewFromQML(self): path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath("3MFReader"), self._qml_url)) self._component = QQmlComponent(Application.getInstance()._engine, path) self._context = QQmlContext(Application.getInstance()._engine.rootContext()) self._context.setContextProperty("manager", self) self._view = self._component.create(self._context) if self._view is None: Logger.log("c", "QQmlComponent status %s", self._component.status()) Logger.log("c", "QQmlComponent error string %s", self._component.errorString())
def _getIOPlugins(self, io_type): plugin_registry = PluginRegistry.getInstance() active_plugin_ids = plugin_registry.getActivePlugins() result = [] for plugin_id in active_plugin_ids: meta_data = plugin_registry.getMetaData(plugin_id) if io_type in meta_data: result.append( (plugin_id, meta_data) ) return result
def onFilenameAccepted(self): self._fileName = self._dialog.findChild(QObject, "nameField").property('text') if not self._fileName.endswith('.gcode') and '.' not in self._fileName: self._fileName += '.gcode' Logger.log("d", self._name_id + " | Filename set to: " + self._fileName) self._dialog.deleteLater() # create the temp file for the gcode self._stream = StringIO() self._stage = OutputStage.writing self.writeStarted.emit(self) # show a progress message self._message = Message( catalog.i18nc("@info:progress", "Sending to {}").format(self._name), 0, False, -1) self._message.show() Logger.log("d", self._name_id + " | Loading gcode...") # get the g-code through the GCodeWrite plugin # this serializes the actual scene and should produce the same output as "Save to File" gcode_writer = cast( MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")) success = gcode_writer.write(self._stream, None) if not success: Logger.log("e", "GCodeWrite failed.") return # start Logger.log("d", self._name_id + " | Connecting...") self._send('connect', [("password", self._duet_password), self._timestamp()], self.onUploadReady)
def _createAdditionalComponentsView(self) -> None: Logger.log("d", "Creating additional ui components for UM3.") # Create networking dialog plugin_path = PluginRegistry.getInstance().getPluginPath( "UM3NetworkPrinting") if not plugin_path: return path = os.path.join(plugin_path, "resources/qml/UM3InfoComponents.qml") self.__additional_components_view = CuraApplication.getInstance( ).createQmlComponent(path, {"manager": self}) if not self.__additional_components_view: Logger.log("w", "Could not create ui components for UM3.") return # Create extra components CuraApplication.getInstance().addAdditionalComponent( "monitorButtons", self.__additional_components_view.findChild( QObject, "networkPrinterConnectButton")) CuraApplication.getInstance().addAdditionalComponent( "machinesDetailPane", self.__additional_components_view.findChild( QObject, "networkPrinterConnectionInfo"))
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._xray_shader: self._xray_shader = OpenGL.getInstance().createShaderProgram( os.path.join( PluginRegistry.getInstance().getPluginPath("XRayView"), "xray.shader")) self._xray_shader.setUniformValue("u_color", [0.1, 0.1, 0.2, 1.0]) for node in BreadthFirstIterator(scene.getRoot()): if not node.render(renderer): if node.getMeshData() and node.isVisible(): renderer.queueNode( node, shader=self._xray_shader, type=RenderBatch.RenderType.Solid, blend_mode=RenderBatch.BlendMode.Additive, sort=-10, state_setup_callback=lambda gl: gl.glDepthFunc( gl.GL_ALWAYS), state_teardown_callback=lambda gl: gl.glDepthFunc( gl.GL_LESS))
def render(self): if not self._shader: self._shader = OpenGL.getInstance().createShaderProgram( os.path.join( PluginRegistry.getInstance().getPluginPath("XRayView"), "xray.shader")) batch = RenderBatch(self._shader, type=RenderBatch.RenderType.NoType, backface_cull=False, blend_mode=RenderBatch.BlendMode.Additive) for node in DepthFirstIterator(self._scene.getRoot()): if isinstance(node, SteSlicerSceneNode) and node.getMeshData( ) and node.isVisible(): batch.addItem(node.getWorldTransformation(), node.getMeshData()) self.bind() self._gl.glDisable(self._gl.GL_DEPTH_TEST) batch.render(self._scene.getActiveCamera()) self._gl.glEnable(self._gl.GL_DEPTH_TEST) self.release()
def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode=MeshWriter.OutputMode.BinaryMode) -> bool: if mode != MeshWriter.OutputMode.BinaryMode: Logger.log("e", "GCodeGzWriter does not support text mode.") self.setInformation( catalog.i18nc("@error:not supported", "GCodeGzWriter does not support text mode.")) return False #Get the g-code from the g-code writer. gcode_textio = StringIO() #We have to convert the g-code into bytes. gcode_writer = cast( MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")) success = gcode_writer.write(gcode_textio, None) if not success: #Writing the g-code failed. Then I can also not write the gzipped g-code. self.setInformation(gcode_writer.getInformation()) return False result = gzip.compress(gcode_textio.getvalue().encode("utf-8")) stream.write(result) return True
def _onToolsChanged(self): self.clear() tools = self._controller.getAllTools() for name in tools: toolMetaData = PluginRegistry.getInstance().getMetaData(name).get("tool", {}) # Skip tools that are marked as not visible if "visible" in toolMetaData and not toolMetaData["visible"]: continue # Optional metadata elements description = toolMetaData.get("description", "") iconName = toolMetaData.get("icon", "default.png") self.appendItem({ "id": name, "name": toolMetaData.get("name", name), "icon": iconName, "active": False, "description": description }) self.sort(lambda t: t["name"])
def loadChangeLogs(self): self._change_logs = collections.OrderedDict() with open( os.path.join( PluginRegistry.getInstance().getPluginPath( self.getPluginId()), "ChangeLog.txt"), "r", -1, "utf-8") as f: open_version = None open_header = None for line in f: line = line.replace("\n", "") if "[" in line and "]" in line: line = line.replace("[", "") line = line.replace("]", "") open_version = Version(line) self._change_logs[Version( line)] = collections.OrderedDict() elif line.startswith("*"): open_header = line.replace("*", "") self._change_logs[open_version][open_header] = [] else: if line != "": self._change_logs[open_version][open_header].append( line)
def importProfile(self, file_name): if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path")} plugin_registry = PluginRegistry.getInstance() container_registry = ContainerRegistry.getInstance() for plugin_id, meta_data in self._getIOPlugins("profile_reader"): profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader. except Exception as e: #Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log("e", "Failed to import profile from %s: %s", file_name, str(e)) return { "status": "error", "message": catalog.i18nc("@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e))} if profile_or_list: # Success! name_seed = os.path.splitext(os.path.basename(file_name))[0] if type(profile_or_list) is not list: profile = profile_or_list self._configureProfile(profile, name_seed) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } else: for profile in profile_or_list: profile.setDirty(True) # Ensure the profiles are correctly saved if profile.getId() != "": container_registry.addContainer(profile) else: self._configureProfile(profile, name_seed) if len(profile_or_list) == 1: return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())} else: profile_names = ", ".join([profile.getName() for profile in profile_or_list]) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profiles {0}", profile_names) } #If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
def _createCloudFlowStartMessage(self): self._start_cloud_flow_message = Message( text=i18n_catalog.i18nc( "@info:status", "Send and monitor print jobs from anywhere using your Ultimaker account." ), lifetime=0, image_source=QUrl.fromLocalFile( os.path.join( PluginRegistry.getInstance().getPluginPath( "UM3NetworkPrinting"), "resources", "svg", "cloud-flow-start.svg")), image_caption=i18n_catalog.i18nc( "@info:status Ultimaker Cloud is a brand name and shouldn't be translated.", "Connect to Ultimaker Cloud"), option_text=i18n_catalog.i18nc( "@action", "Don't ask me again for this printer."), option_state=False) self._start_cloud_flow_message.addAction( "", i18n_catalog.i18nc("@action", "Get started"), "", "") self._start_cloud_flow_message.optionToggled.connect( self._onDontAskMeAgain) self._start_cloud_flow_message.actionTriggered.connect( self._onCloudFlowStarted)
def _onStagesChanged(self): items = [] stages = self._controller.getAllStages() for stage_id, stage in stages.items(): view_meta_data = PluginRegistry.getInstance().getMetaData(stage_id).get("stage", {}) # Skip view modes that are marked as not visible if "visible" in view_meta_data and not view_meta_data["visible"]: continue # Metadata elements name = view_meta_data.get("name", stage_id) weight = view_meta_data.get("weight", 99) items.append({ "id": stage_id, "name": name, "stage": stage, "weight": weight }) items.sort(key=lambda t: t["weight"]) self.setItems(items)
def loadChangeLogs(self): self._change_logs = collections.OrderedDict() with open( os.path.join( PluginRegistry.getInstance().getPluginPath( self.getPluginId()), "ChangeLog.txt"), "r", -1, "utf-8") as f: open_version = None open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog for line in f: line = line.replace("\n", "") if "[" in line and "]" in line: line = line.replace("[", "") line = line.replace("]", "") open_version = Version(line) open_header = "" self._change_logs[open_version] = collections.OrderedDict() elif line.startswith("*"): open_header = line.replace("*", "") self._change_logs[open_version][open_header] = [] elif line != "": if open_header not in self._change_logs[open_version]: self._change_logs[open_version][open_header] = [] self._change_logs[open_version][open_header].append(line)
def addContainerType(cls, container): plugin_id = container.getPluginId() metadata = PluginRegistry.getInstance().getMetaData(plugin_id) if "settings_container" not in metadata or "mimetype" not in metadata["settings_container"]: raise Exception("Plugin {plugin} has incorrect metadata: Expected a 'settings_container' block with a 'mimetype' entry".format(plugin = plugin_id)) cls.addContainerTypeByName(container.__class__, plugin_id, metadata["settings_container"]["mimetype"])
def importProfile(self, file_name): Logger.log("d", "Attempting to import profile %s", file_name) if not file_name: return { "status": "error", "message": catalog.i18nc( "@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, "Invalid path") } plugin_registry = PluginRegistry.getInstance() extension = file_name.split(".")[-1] global_container_stack = Application.getInstance( ).getGlobalContainerStack() if not global_container_stack: return machine_extruders = list( ExtruderManager.getInstance().getMachineExtruders( global_container_stack.getId())) machine_extruders.sort(key=lambda k: k.getMetaDataEntry("position")) for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue profile_reader = plugin_registry.getPluginObject(plugin_id) try: profile_or_list = profile_reader.read( file_name) # Try to open the file with the profile reader. except Exception as e: # Note that this will fail quickly. That is, if any profile reader throws an exception, it will stop reading. It will only continue reading if the reader returned None. Logger.log( "e", "Failed to import profile from %s: %s while using profile reader. Got exception %s", file_name, profile_reader.getPluginId(), str(e)) return { "status": "error", "message": catalog.i18nc( "@info:status", "Failed to import profile from <filename>{0}</filename>: <message>{1}</message>", file_name, str(e)) } if profile_or_list: # Success! name_seed = os.path.splitext(os.path.basename(file_name))[0] new_name = self.uniqueName(name_seed) if type(profile_or_list) is not list: profile = profile_or_list self._configureProfile(profile, name_seed, new_name) return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile.getName()) } else: profile_index = -1 global_profile = None for profile in profile_or_list: if profile_index >= 0: if len(machine_extruders) > profile_index: extruder_id = Application.getInstance( ).getMachineManager().getQualityDefinitionId( machine_extruders[profile_index].getBottom( )) # Ensure the extruder profiles get non-conflicting names # NB: these are not user-facing if "extruder" in profile.getMetaData(): profile.setMetaDataEntry( "extruder", extruder_id) else: profile.addMetaDataEntry( "extruder", extruder_id) profile_id = (extruder_id + "_" + name_seed).lower().replace( " ", "_") elif profile_index == 0: # Importing a multiextrusion profile into a single extrusion machine; merge 1st extruder profile into global profile profile._id = self.uniqueName( "temporary_profile") self.addContainer(profile) ContainerManager.getInstance().mergeContainers( global_profile.getId(), profile.getId()) self.removeContainer(profile.getId()) break else: # The imported composite profile has a profile for an extruder that this machine does not have. Ignore this extruder-profile break else: global_profile = profile profile_id = ( global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_") self._configureProfile(profile, profile_id, new_name) profile_index += 1 return { "status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName()) } # If it hasn't returned by now, none of the plugins loaded the profile successfully. return { "status": "error", "message": catalog.i18nc( "@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name) }
def _onDownloadFinished(self, success_items: Dict[str, str], error_items: List[str]) -> None: # todo handle error items plugin_path = PluginRegistry.getInstance().getPluginPath( self.getPluginId()) self._license_presenter.present(plugin_path, success_items)
def addProvider(self, provider: ContainerProvider) -> None: """Adds a container provider to search through containers in.""" self._providers.append(provider) # Re-sort every time. It's quadratic, but there shouldn't be that many providers anyway... self._providers.sort(key = lambda provider: PluginRegistry.getInstance().getMetaData(provider.getPluginId())["container_provider"].get("priority", 0))
def _createViewFromQML(self): path = os.path.join( PluginRegistry.getInstance().getPluginPath("3MFReader"), self._qml_url) self._view = Application.getInstance().createQmlComponent( path, {"manager": self})
def event(self, event): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers & Qt.ControlModifier shift_is_active = modifiers & Qt.ShiftModifier if event.type == Event.KeyPressEvent and ctrl_is_active: amount = 10 if shift_is_active else 1 if event.key == KeyEvent.UpKey: self.setLayer(self._current_layer_num + amount) return True if event.key == KeyEvent.DownKey: self.setLayer(self._current_layer_num - amount) return True if event.type == Event.ViewActivateEvent: # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching. # This can happen when you do the following steps: # 1. Start Cura # 2. Load a model # 3. Switch to Custom mode # 4. Select the model and click on the per-object tool icon # 5. Switch view to Layer view or X-Ray # 6. Cura will very likely crash # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why. # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL # context is None. if Platform.isOSX(): if QOpenGLContext.currentContext() is None: Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later") CuraApplication.getInstance().callLater(lambda e=event: self.event(e)) return # Make sure the SimulationPass is created layer_pass = self.getSimulationPass() self.getRenderer().addRenderPass(layer_pass) # Make sure the NozzleNode is add to the root nozzle = self.getNozzleNode() nozzle.setParent(self.getController().getScene().getRoot()) nozzle.setVisible(False) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) self._onGlobalStackChanged() if not self._simulationview_composite_shader: self._simulationview_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), "simulationview_composite.shader")) theme = Application.getInstance().getTheme() self._simulationview_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb())) self._simulationview_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb())) if not self._composite_pass: self._composite_pass = self.getRenderer().getRenderPass("composite") self._old_layer_bindings = self._composite_pass.getLayerBindings()[:] # make a copy so we can restore to it later self._composite_pass.getLayerBindings().append("simulationview") self._old_composite_shader = self._composite_pass.getCompositeShader() self._composite_pass.setCompositeShader(self._simulationview_composite_shader) elif event.type == Event.ViewDeactivateEvent: self._wireprint_warning_message.hide() Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged) if self._global_container_stack: self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged) self._nozzle_node.setParent(None) self.getRenderer().removeRenderPass(self._layer_pass) self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader(self._old_composite_shader)
def __eq__(self, other: "ContainerProvider"): plugin_registry = PluginRegistry.getInstance() my_metadata = plugin_registry.getMetaData(self.getPluginId()) other_metadata = plugin_registry.getMetaData(other.getPluginId()) return my_metadata["container_provider"]["priority"] == other_metadata[ "container_provider"]["priority"]
def _createSocket(self): super()._createSocket(os.path.abspath(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "Cura.proto")))
def _plugin_path(self): return PluginRegistry.getInstance().getPluginPath(self._get_plugin_directory_name())
def registerObjects( self, engine ) -> None: #type: ignore #Don't type engine, because the type depends on the platform you're running on so it always gives an error somewhere. engine.rootContext().setContextProperty("PluginRegistry", PluginRegistry.getInstance())
def __init__(self, serial_port: str, baud_rate: Optional[int] = None) -> None: super().__init__(serial_port, connection_type=ConnectionType.UsbConnection) self.setName(catalog.i18nc("@item:inmenu", "USB printing")) self.setShortDescription( catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print via USB")) self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB")) self.setIconName("print") self._serial = None # type: Optional[Serial] self._serial_port = serial_port self._address = serial_port self._timeout = 3 # List of gcode lines to be printed self._gcode = [] # type: List[str] self._gcode_position = 0 self._use_auto_detect = True self._baud_rate = baud_rate self._all_baud_rates = [ 115200, 250000, 500000, 230400, 57600, 38400, 19200, 9600 ] # Instead of using a timer, we really need the update to be as a thread, as reading from serial can block. self._update_thread = Thread(target=self._update, daemon=True, name="USBPrinterUpdate") self._last_temperature_request = None # type: Optional[int] self._firmware_idle_count = 0 self._is_printing = False # A print is being sent. ## Set when print is started in order to check running time. self._print_start_time = None # type: Optional[float] self._print_estimated_time = None # type: Optional[int] self._accepts_commands = True self._paused = False self._printer_busy = False # When printer is preheating and waiting (M190/M109), or when waiting for action on the printer self.setConnectionText( catalog.i18nc("@info:status", "Connected via USB")) # Queue for commands that need to be sent. self._command_queue = Queue() # type: Queue # Event to indicate that an "ok" was received from the printer after sending a command. self._command_received = Event() self._command_received.set() self._firmware_name_requested = False self._firmware_updater = AvrFirmwareUpdater(self) plugin_path = cast( str, PluginRegistry.getInstance().getPluginPath("USBPrinting")) self._monitor_view_qml_path = os.path.join(plugin_path, "MonitorItem.qml") CuraApplication.getInstance().getOnExitCallbackManager().addCallback( self._checkActivePrintingUponAppExit)
def addProvider(self, provider: "PluginObject"): self._providers.append(provider) #Re-sort every time. It's quadratic, but there shouldn't be that many providers anyway... self._providers.sort(key = lambda provider: PluginRegistry.getInstance().getMetaData(provider.getPluginId())["container_provider"].get("priority", 0))
def registerObjects(self, engine): engine.rootContext().setContextProperty("PluginRegistry", PluginRegistry.getInstance())
def _onDiscrepancies(self, model: SubscribedPackagesModel) -> None: plugin_path = PluginRegistry.getInstance().getPluginPath( self.getPluginId()) self._discrepancies_presenter.present(plugin_path, model)
def spawnFirmwareInterface(self, serial_port): if self._firmware_view is None: path = os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "FirmwareUpdateWindow.qml") self._firmware_view = Application.getInstance().createQmlComponent(path, {"manager": self}) self._firmware_view.show()
def createChangelogWindow(self): path = os.path.join( PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.qml") self._changelog_window = Application.getInstance().createQmlComponent( path, {"manager": self})
def __init__(self, name, version, **kwargs): if (Application._instance != None): raise ValueError("Duplicate singleton creation") # If the constructor is called and there is no instance, set the instance to self. # This is done because we can't make constructor private Application._instance = self self._application_name = name self._version = version os.putenv( "UBUNTU_MENUPROXY", "0" ) #For Ubuntu Unity this makes Qt use its own menu bar rather than pass it on to Unity. Signal._app = self Resources.ApplicationIdentifier = name i18nCatalog.setApplication(self) Resources.addSearchPath(os.path.dirname(sys.executable)) Resources.addSearchPath( os.path.join(Application.getInstallPrefix(), "share", "uranium")) Resources.addSearchPath( os.path.join(Application.getInstallPrefix(), "Resources", "uranium")) Resources.addSearchPath( os.path.join(Application.getInstallPrefix(), "Resources", self.getApplicationName())) if not hasattr(sys, "frozen"): Resources.addSearchPath( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")) self._main_thread = threading.current_thread() super().__init__( **kwargs) # Call super to make multiple inheritence work. self._renderer = None PluginRegistry.addType("backend", self.setBackend) PluginRegistry.addType("logger", Logger.addLogger) PluginRegistry.addType("extension", self.addExtension) preferences = Preferences.getInstance() preferences.addPreference("general/language", "en") try: preferences.readFromFile( Resources.getPath(Resources.Preferences, self._application_name + ".cfg")) except FileNotFoundError: pass self._controller = Controller(self) self._mesh_file_handler = MeshFileHandler() self._extensions = [] self._backend = None self._output_device_manager = OutputDeviceManager() self._machine_manager = MachineManager(self._application_name) self._required_plugins = [] self._operation_stack = OperationStack() self._plugin_registry = PluginRegistry.getInstance() self._plugin_registry.addPluginLocation( os.path.join(Application.getInstallPrefix(), "lib", "uranium")) self._plugin_registry.addPluginLocation( os.path.join(os.path.dirname(sys.executable), "plugins")) self._plugin_registry.addPluginLocation( os.path.join(Application.getInstallPrefix(), "Resources", "uranium", "plugins")) self._plugin_registry.addPluginLocation( os.path.join(Application.getInstallPrefix(), "Resources", self.getApplicationName(), "plugins")) # Locally installed plugins self._plugin_registry.addPluginLocation( os.path.join(Resources.getStoragePath(Resources.Resources), "plugins")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation( os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.setApplication(self) self._parsed_command_line = None self.parseCommandLine() self._visible_messages = [] self._message_lock = threading.Lock() self.showMessageSignal.connect(self.showMessage) self.hideMessageSignal.connect(self.hideMessage)
def _createDialog(self, qml_name): Logger.log("d", "Creating dialog [%s]", qml_name) file_path = os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), qml_name) dialog = Application.getInstance().createQmlComponent(file_path, {"manager": self}) return dialog
def render(self): if not self._layer_shader: if self._compatibility_mode: shader_filename = "layers.shader" shadow_shader_filename = "layers_shadow.shader" else: shader_filename = "layers3d.shader" shadow_shader_filename = "layers3d_shadow.shader" self._layer_shader = OpenGL.getInstance().createShaderProgram( os.path.join( PluginRegistry.getInstance().getPluginPath( "SimulationView"), shader_filename)) self._layer_shadow_shader = OpenGL.getInstance( ).createShaderProgram( os.path.join( PluginRegistry.getInstance().getPluginPath( "SimulationView"), shadow_shader_filename)) self._current_shader = self._layer_shader # Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers) self._layer_shader.setUniformValue( "u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex))) if not self._compatibility_mode: self._layer_shader.setUniformValue( "u_starts_color", Color(*Application.getInstance().getTheme().getColor( "layerview_starts").getRgb())) if self._layer_view: self._layer_shader.setUniformValue( "u_max_feedrate", self._layer_view.getMaxFeedrate()) self._layer_shader.setUniformValue( "u_min_feedrate", self._layer_view.getMinFeedrate()) self._layer_shader.setUniformValue( "u_max_thickness", self._layer_view.getMaxThickness()) self._layer_shader.setUniformValue( "u_min_thickness", self._layer_view.getMinThickness()) self._layer_shader.setUniformValue( "u_max_line_width", self._layer_view.getMaxLineWidth()) self._layer_shader.setUniformValue( "u_min_line_width", self._layer_view.getMinLineWidth()) self._layer_shader.setUniformValue( "u_max_flow_rate", self._layer_view.getMaxFlowRate()) self._layer_shader.setUniformValue( "u_min_flow_rate", self._layer_view.getMinFlowRate()) self._layer_shader.setUniformValue( "u_layer_view_type", self._layer_view.getSimulationViewType()) self._layer_shader.setUniformValue( "u_extruder_opacity", self._layer_view.getExtruderOpacities()) self._layer_shader.setUniformValue( "u_show_travel_moves", self._layer_view.getShowTravelMoves()) self._layer_shader.setUniformValue( "u_show_helpers", self._layer_view.getShowHelpers()) self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin()) self._layer_shader.setUniformValue( "u_show_infill", self._layer_view.getShowInfill()) self._layer_shader.setUniformValue( "u_show_starts", self._layer_view.getShowStarts()) else: #defaults self._layer_shader.setUniformValue("u_max_feedrate", 1) self._layer_shader.setUniformValue("u_min_feedrate", 0) self._layer_shader.setUniformValue("u_max_thickness", 1) self._layer_shader.setUniformValue("u_min_thickness", 0) self._layer_shader.setUniformValue("u_max_flow_rate", 1) self._layer_shader.setUniformValue("u_min_flow_rate", 0) self._layer_shader.setUniformValue("u_max_line_width", 1) self._layer_shader.setUniformValue("u_min_line_width", 0) self._layer_shader.setUniformValue("u_layer_view_type", 1) self._layer_shader.setUniformValue( "u_extruder_opacity", [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) self._layer_shader.setUniformValue("u_show_travel_moves", 0) self._layer_shader.setUniformValue("u_show_helpers", 1) self._layer_shader.setUniformValue("u_show_skin", 1) self._layer_shader.setUniformValue("u_show_infill", 1) self._layer_shader.setUniformValue("u_show_starts", 1) if not self._tool_handle_shader: self._tool_handle_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "toolhandle.shader")) if not self._nozzle_shader: self._nozzle_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "color.shader")) self._nozzle_shader.setUniformValue( "u_color", Color(*Application.getInstance().getTheme().getColor( "layerview_nozzle").getRgb())) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._disabled_shader.setUniformValue( "u_diffuseColor1", Color(*Application.getInstance().getTheme().getColor( "model_unslicable").getRgb())) self._disabled_shader.setUniformValue( "u_diffuseColor2", Color(*Application.getInstance().getTheme().getColor( "model_unslicable_alt").getRgb())) self._disabled_shader.setUniformValue("u_width", 50.0) self._disabled_shader.setUniformValue("u_opacity", 0.6) self.bind() tool_handle_batch = RenderBatch(self._tool_handle_shader, type=RenderBatch.RenderType.Overlay, backface_cull=True) disabled_batch = RenderBatch(self._disabled_shader) head_position = None # Indicates the current position of the print head nozzle_node = None for node in DepthFirstIterator(self._scene.getRoot()): if isinstance(node, ToolHandle): tool_handle_batch.addItem(node.getWorldTransformation(), mesh=node.getSolidMesh()) elif isinstance(node, NozzleNode): nozzle_node = node nozzle_node.setVisible( False) # Don't set to true, we render it separately! elif getattr(node, "_outside_buildarea", False) and isinstance( node, SceneNode) and node.getMeshData() and node.isVisible( ) and not node.callDecoration("isNonPrintingMesh"): disabled_batch.addItem(node.getWorldTransformation(copy=False), node.getMeshData()) elif isinstance(node, SceneNode) and (node.getMeshData( ) or node.callDecoration("isBlockSlicing")) and node.isVisible(): layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._layer_view._current_layer_num > -1 and ( (not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())): start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer in sorted(element_counts.keys()): # In the current layer, we show just the indicated paths if layer == self._layer_view._current_layer_num: # We look for the position of the head, searching the point of the current path index = self._layer_view._current_path_num offset = 0 for polygon in layer_data.getLayer(layer).polygons: # The size indicates all values in the two-dimension array, and the second dimension is # always size 3 because we have 3D points. if index >= polygon.data.size // 3 - offset: index -= polygon.data.size // 3 - offset offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon continue # The head position is calculated and translated head_position = Vector( polygon.data[index + offset][0], polygon.data[index + offset][1], polygon.data[index + offset] [2]) + node.getWorldPosition() break break if self._layer_view._minimum_layer_num > layer: start += element_counts[layer] end += element_counts[layer] # Calculate the range of paths in the last layer current_layer_start = end current_layer_end = end + self._layer_view._current_path_num * 2 # Because each point is used twice # This uses glDrawRangeElements internally to only draw a certain range of lines. # All the layers but the current selected layer are rendered first if self._old_current_path != self._layer_view._current_path_num: self._current_shader = self._layer_shadow_shader self._switching_layers = False if not self._layer_view.isSimulationRunning( ) and self._old_current_layer != self._layer_view._current_layer_num: self._current_shader = self._layer_shader self._switching_layers = True # The first line does not have a previous line: add a MoveCombingType in front for start detection # this way the first start of the layer can also be drawn prev_line_types = numpy.concatenate([ numpy.asarray([LayerPolygon.MoveCombingType], dtype=numpy.float32), layer_data._attributes["line_types"]["value"] ]) # Remove the last element prev_line_types = prev_line_types[ 0:layer_data._attributes["line_types"]["value"].size] layer_data._attributes["prev_line_types"] = { 'opengl_type': 'float', 'value': prev_line_types, 'opengl_name': 'a_prev_line_type' } layers_batch = RenderBatch( self._current_shader, type=RenderBatch.RenderType.Solid, mode=RenderBatch.RenderMode.Lines, range=(start, end), backface_cull=True) layers_batch.addItem(node.getWorldTransformation(), layer_data) layers_batch.render(self._scene.getActiveCamera()) # Current selected layer is rendered current_layer_batch = RenderBatch( self._layer_shader, type=RenderBatch.RenderType.Solid, mode=RenderBatch.RenderMode.Lines, range=(current_layer_start, current_layer_end)) current_layer_batch.addItem(node.getWorldTransformation(), layer_data) current_layer_batch.render(self._scene.getActiveCamera()) self._old_current_layer = self._layer_view._current_layer_num self._old_current_path = self._layer_view._current_path_num # Create a new batch that is not range-limited batch = RenderBatch(self._layer_shader, type=RenderBatch.RenderType.Solid) if self._layer_view.getCurrentLayerMesh(): batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerMesh()) if self._layer_view.getCurrentLayerJumps(): batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerJumps()) if len(batch.items) > 0: batch.render(self._scene.getActiveCamera()) # The nozzle is drawn when once we know the correct position of the head, # but the user is not using the layer slider, and the compatibility mode is not enabled if not self._switching_layers and not self._compatibility_mode and self._layer_view.getActivity( ) and nozzle_node is not None: if head_position is not None: nozzle_node.setPosition(head_position) nozzle_batch = RenderBatch( self._nozzle_shader, type=RenderBatch.RenderType.Transparent) nozzle_batch.addItem(nozzle_node.getWorldTransformation(), mesh=nozzle_node.getMeshData()) nozzle_batch.render(self._scene.getActiveCamera()) if len(disabled_batch.items) > 0: disabled_batch.render(self._scene.getActiveCamera()) # Render toolhandles on top of the layerview if len(tool_handle_batch.items) > 0: tool_handle_batch.render(self._scene.getActiveCamera()) self.release()