diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 6c5bc61cbe..0000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,16 +0,0 @@ -image: registry.gitlab.com/ultimaker/cura/cura-build-environment:centos7 - -stages: - - build - -build and test linux: - stage: build - tags: - - cura - - docker - - linux - script: - - docker/build.sh - artifacts: - paths: - - build diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index 427cc77e65..8da64beead 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -22,13 +22,6 @@ try: except ImportError: CuraAppName = DEFAULT_CURA_APP_NAME -try: - from cura.CuraVersion import CuraAppDisplayName # type: ignore - if CuraAppDisplayName == "": - CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME -except ImportError: - CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME - try: from cura.CuraVersion import CuraVersion # type: ignore if CuraVersion == "": @@ -53,3 +46,13 @@ except ImportError: # Various convenience flags indicating what kind of Cura build it is. __ENTERPRISE_VERSION_TYPE = "enterprise" IsEnterpriseVersion = CuraBuildType.lower() == __ENTERPRISE_VERSION_TYPE + +try: + from cura.CuraVersion import CuraAppDisplayName # type: ignore + if CuraAppDisplayName == "": + CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME + if IsEnterpriseVersion: + CuraAppDisplayName = CuraAppDisplayName + " Enterprise" + +except ImportError: + CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index ef5f987b85..93f7fa97ff 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -67,11 +67,9 @@ from cura.Scene.BuildPlateDecorator import BuildPlateDecorator from cura.Scene.ConvexHullDecorator import ConvexHullDecorator from cura.Scene.CuraSceneController import CuraSceneController from cura.Scene.CuraSceneNode import CuraSceneNode -from cura.Scene.GCodeListDecorator import GCodeListDecorator + from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene import ZOffsetDecorator - -from cura.Machines.ContainerTree import ContainerTree from cura.Machines.MachineErrorChecker import MachineErrorChecker from cura.Machines.Models.BuildPlateModel import BuildPlateModel @@ -170,7 +168,7 @@ class CuraApplication(QtApplication): app_display_name = ApplicationMetadata.CuraAppDisplayName, version = ApplicationMetadata.CuraVersion, api_version = ApplicationMetadata.CuraSDKVersion, - buildtype = ApplicationMetadata.CuraBuildType, + build_type = ApplicationMetadata.CuraBuildType, is_debug_mode = ApplicationMetadata.CuraDebugMode, tray_icon_name = "cura-icon-32.png", **kwargs) diff --git a/cura/Machines/MachineNode.py b/cura/Machines/MachineNode.py index 92f71b409b..cee71160d2 100644 --- a/cura/Machines/MachineNode.py +++ b/cura/Machines/MachineNode.py @@ -162,6 +162,7 @@ class MachineNode(ContainerNode): container_registry = ContainerRegistry.getInstance() if not self.has_variants: self.variants["empty"] = VariantNode("empty_variant", machine = self) + self.variants["empty"].materialsChanged.connect(self.materialsChanged) else: # Find all the variants for this definition ID. variants = container_registry.findInstanceContainersMetadata(type = "variant", definition = self.container_id, hardware_type = "nozzle") diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index de6e270a86..0138d68a61 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1008,9 +1008,9 @@ class MachineManager(QObject): # Set quality and quality_changes for each ExtruderStack for position, node in quality_group.nodes_for_extruders.items(): - self._global_container_stack.extruders[str(position)].quality = node.container + self._global_container_stack.extruderList[position].quality = node.container if empty_quality_changes: - self._global_container_stack.extruders[str(position)].qualityChanges = empty_quality_changes_container + self._global_container_stack.extruderList[position].qualityChanges = empty_quality_changes_container self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() @@ -1241,6 +1241,7 @@ class MachineManager(QObject): if not new_machine: new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id) if not new_machine: + Logger.log("e", "Failed to create new machine when switching configuration.") return for metadata_key in self._global_container_stack.getMetaData(): @@ -1256,8 +1257,22 @@ class MachineManager(QObject): new_machine.setMetaDataEntry("hidden", False) self._global_container_stack.setMetaDataEntry("hidden", True) + # The new_machine does not contain user changes (global or per-extruder user changes). + # Keep a temporary copy of the global and per-extruder user changes and transfer them to the user changes + # of the new machine after the new_machine becomes active. + global_user_changes = self._global_container_stack.userChanges + per_extruder_user_changes = {} + for extruder_name, extruder_stack in self._global_container_stack.extruders.items(): + per_extruder_user_changes[extruder_name] = extruder_stack.userChanges + self.setActiveMachine(new_machine.getId()) + # Apply the global and per-extruder userChanges to the new_machine (which is of different type than the + # previous one). + self._global_container_stack.setUserChanges(global_user_changes) + for extruder_name in self._global_container_stack.extruders.keys(): + self._global_container_stack.extruders[extruder_name].setUserChanges(per_extruder_user_changes[extruder_name]) + @pyqtSlot(QObject) def applyRemoteConfiguration(self, configuration: PrinterConfigurationModel) -> None: if self._global_container_stack is None: diff --git a/cura/UI/CuraSplashScreen.py b/cura/UI/CuraSplashScreen.py index 05231c106d..70df454e7d 100644 --- a/cura/UI/CuraSplashScreen.py +++ b/cura/UI/CuraSplashScreen.py @@ -7,14 +7,21 @@ from PyQt5.QtWidgets import QSplashScreen from UM.Resources import Resources from UM.Application import Application +from cura import ApplicationMetadata class CuraSplashScreen(QSplashScreen): def __init__(self): super().__init__() self._scale = 0.7 + self._version_y_offset = 0 # when extra visual elements are in the background image, move version text down + + if ApplicationMetadata.IsEnterpriseVersion: + splash_image = QPixmap(Resources.getPath(Resources.Images, "cura_enterprise.png")) + self._version_y_offset = 26 + else: + splash_image = QPixmap(Resources.getPath(Resources.Images, "cura.png")) - splash_image = QPixmap(Resources.getPath(Resources.Images, "cura.png")) self.setPixmap(splash_image) self._current_message = "" @@ -52,20 +59,17 @@ class CuraSplashScreen(QSplashScreen): painter.setRenderHint(QPainter.Antialiasing, True) version = Application.getInstance().getVersion().split("-") - buildtype = Application.getInstance().getBuildType() - if buildtype: - version[0] += " (%s)" % buildtype # Draw version text font = QFont() # Using system-default font here - font.setPixelSize(37) + font.setPixelSize(18) painter.setFont(font) - painter.drawText(60, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0]) + painter.drawText(60, 70 + self._version_y_offset, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0]) if len(version) > 1: font.setPixelSize(16) painter.setFont(font) painter.setPen(QColor(200, 200, 200, 255)) - painter.drawText(247, 105, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1]) + painter.drawText(247, 105 + self._version_y_offset, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1]) painter.setPen(QColor(255, 255, 255, 255)) # Draw the loading image diff --git a/plugins/PostProcessingPlugin/scripts/ColorMix.py b/plugins/PostProcessingPlugin/scripts/ColorMix.py new file mode 100644 index 0000000000..1152ba70da --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/ColorMix.py @@ -0,0 +1,190 @@ +# ColorMix script - 2-1 extruder color mix and blending +# This script is specific for the Geeetech A10M dual extruder but should work with other Marlin printers. +# It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher. +# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms + +#Authors of the 2-1 ColorMix plug-in / script: +# Written by John Hryb - john.hryb.4@gmail.com + +##history / change-log: +##V1.0.0 + +## Uses - +## M163 - Set Mix Factor +## M164 - Save Mix - saves to T3 as a unique mix + +import re #To perform the search and replace. +from ..Script import Script + +class ColorMix(Script): + def __init__(self): + super().__init__() + + def getSettingDataString(self): + return """{ + "name":"ColorMix 2-1", + "key":"ColorMix 2-1", + "metadata": {}, + "version": 2, + "settings": + { + "measurement_units": + { + "label": "Units of measurement", + "description": "Input value as mm or layer number.", + "type": "enum", + "options": {"mm":"mm","layer":"Layer"}, + "default_value": "layer" + }, + "start_height": + { + "label": "Start Height", + "description": "Value to start at (mm or layer)", + "type": "float", + "default_value": 0, + "minimum_value": "0" + }, + "behavior": + { + "label": "Fixed or blend", + "description": "Select Fixed (set new mixture) or Blend mode (dynamic mix)", + "type": "enum", + "options": {"fixed_value":"Fixed","blend_value":"Blend"}, + "default_value": "fixed_value" + }, + "finish_height": + { + "label": "Finish Height", + "description": "Value to stop at (mm or layer)", + "type": "float", + "default_value": 0, + "minimum_value": "0", + "minimum_value_warning": "0.1", + "enabled": "c_behavior == 'blend_value'" + }, + "mix_start_ratio": + { + "label": "Start mix ratio", + "description": "First extruder percentage 0-100", + "type": "float", + "default_value": 100, + "minimum_value": "0", + "minimum_value_warning": "0", + "maximum_value_warning": "100" + }, + "mix_finish_ratio": + { + "label": "End mix ratio", + "description": "First extruder percentage 0-100 to finish blend", + "type": "float", + "default_value": 0, + "minimum_value": "0", + "minimum_value_warning": "0", + "maximum_value_warning": "100", + "enabled": "c_behavior == 'blend_value'" + }, + "notes": + { + "label": "Notes", + "description": "A spot to put a note", + "type": "str", + "default_value": "" + } + } + }""" + def getValue(self, line, key, default = None): #replace default getvalue due to comment-reading feature + if not key in line or (";" in line and line.find(key) > line.find(";") and + not ";ChangeAtZ" in key and not ";LAYER:" in key): + return default + subPart = line[line.find(key) + len(key):] #allows for string lengths larger than 1 + if ";ChangeAtZ" in key: + m = re.search("^[0-4]", subPart) + elif ";LAYER:" in key: + m = re.search("^[+-]?[0-9]*", subPart) + else: + #the minus at the beginning allows for negative values, e.g. for delta printers + m = re.search("^[-]?[0-9]*\.?[0-9]*", subPart) + if m == None: + return default + try: + return float(m.group(0)) + except: + return default + + def execute(self, data): + #get user variables + firstHeight = 0.0 + secondHeight = 0.0 + firstMix = 0.0 + SecondMix = 0.0 + + firstHeight = self.getSettingValueByKey("start_height") + secondHeight = self.getSettingValueByKey("finish_height") + firstMix = self.getSettingValueByKey("mix_start_ratio") + SecondMix = self.getSettingValueByKey("mix_finish_ratio") + + #locals + layer = 0 + + #get layer height + layerHeight = .2 + for active_layer in data: + lines = active_layer.split("\n") + for line in lines: + if ";Layer height: " in line: + layerHeight = self.getValue(line, ";Layer height: ", layerHeight) + break + #get layers to use + startLayer = 0 + endLayer = 0 + if self.getSettingValueByKey("measurement_units") == "mm": + if firstHeight == 0: + startLayer = 0 + else: + startLayer = firstHeight / layerHeight + if secondHeight == 0: + endLayer = 0 + else: + endLayer = secondHeight / layerHeight + else: #layer height + startLayer = firstHeight + endLayer = secondHeight + #see if one-shot + if self.getSettingValueByKey("behavior") == "fixed_value": + endLayer = startLayer + firstExtruderIncrements = 0 + else: #blend + firstExtruderIncrements = (SecondMix - firstMix) / (endLayer - startLayer) + firstExtruderValue = 0 + index = 0 + #start scanning + for active_layer in data: + modified_gcode = "" + lineIndex = 0; + lines = active_layer.split("\n") + for line in lines: + #dont leave blanks + if line != "": + modified_gcode += line + "\n" + # find current layer + if ";LAYER:" in line: + layer = self.getValue(line, ";LAYER:", layer) + if (layer >= startLayer) and (layer <= endLayer): #find layers of interest + if lines[lineIndex + 4] == "T2": #check if needing to delete old data + del lines[(lineIndex + 1):(lineIndex + 5)] + firstExtruderValue = int(((layer - startLayer) * firstExtruderIncrements) + firstMix) + if firstExtruderValue == 100: + modified_gcode += "M163 S0 P1\n" + modified_gcode += "M163 S1 P0\n" + elif firstExtruderValue == 0: + modified_gcode += "M163 S0 P0\n" + modified_gcode += "M163 S1 P1\n" + else: + modified_gcode += "M163 S0 P0.{:02d}\n".format(firstExtruderValue) + modified_gcode += "M163 S1 P0.{:02d}\n".format(100 - firstExtruderValue) + modified_gcode += "M164 S2\n" + modified_gcode += "T2\n" + lineIndex += 1 #for deleting index + data[index] = modified_gcode + index += 1 + return data diff --git a/plugins/UM3NetworkPrinting/src/Network/ZeroConfClient.py b/plugins/UM3NetworkPrinting/src/Network/ZeroConfClient.py index 421246fb95..bfc2725fb0 100644 --- a/plugins/UM3NetworkPrinting/src/Network/ZeroConfClient.py +++ b/plugins/UM3NetworkPrinting/src/Network/ZeroConfClient.py @@ -125,11 +125,11 @@ class ZeroConfClient: if not info.address: info = zero_conf.get_service_info(service_type, name) - if info: + if info and info.address: type_of_device = info.properties.get(b"type", None) if type_of_device: if type_of_device == b"printer": - address = '.'.join(map(lambda n: str(n), info.address)) + address = '.'.join(map(str, info.address)) self.addedNetworkCluster.emit(str(name), address, info.properties) else: Logger.log("w", "The type of the found device is '%s', not 'printer'." % type_of_device) diff --git a/resources/images/cura_enterprise.png b/resources/images/cura_enterprise.png new file mode 100644 index 0000000000..789e0ae215 Binary files /dev/null and b/resources/images/cura_enterprise.png differ diff --git a/resources/qml/Dialogs/AboutDialog.qml b/resources/qml/Dialogs/AboutDialog.qml index a5622aa2c9..aa0a58aa8d 100644 --- a/resources/qml/Dialogs/AboutDialog.qml +++ b/resources/qml/Dialogs/AboutDialog.qml @@ -12,7 +12,7 @@ UM.Dialog id: base //: About dialog title - title: catalog.i18nc("@title:window","About Cura") + title: catalog.i18nc("@title:window","About " + catalog.i18nc("@title:window", CuraApplication.applicationDisplayName)) minimumWidth: 500 * screenScaleFactor minimumHeight: 650 * screenScaleFactor