diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4d58dcee34..5a18199e3c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -154,6 +154,11 @@ jobs: - name: Create the Packages (Bash) run: conan install $CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$ENTERPRISE -o cura:staging=$STAGING --json "cura_inst/conan_install_info.json" + - name: Upload the Package(s) + if: always() + run: | + conan upload "*" -r cura --all -c + - name: Set Environment variables for Cura (bash) run: | . ./cura_inst/bin/activate_github_actions_env.sh diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 4690d27878..af1fc3d12b 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -154,6 +154,11 @@ jobs: - name: Create the Packages (Bash) run: conan install $CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$ENTERPRISE -o cura:staging=$STAGING --json "cura_inst/conan_install_info.json" + - name: Upload the Package(s) + if: always() + run: | + conan upload "*" -r cura --all -c + - name: Set Environment variables for Cura (bash) run: | . ./cura_inst/bin/activate_github_actions_env.sh diff --git a/.github/workflows/requirements-conan-package.txt b/.github/workflows/requirements-conan-package.txt index 48121932b8..6b4d4cffc8 100644 --- a/.github/workflows/requirements-conan-package.txt +++ b/.github/workflows/requirements-conan-package.txt @@ -1,2 +1,2 @@ -conan==1.56.0 -sip==6.7.1 +conan==1.60.2 +sip diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 88d9d84e94..df9056d454 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -124,6 +124,11 @@ jobs: - name: Create the Packages (Powershell) run: conan install $Env:CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$Env:ENTERPRISE -o cura:staging=$Env:STAGING --json "cura_inst/conan_install_info.json" + - name: Upload the Package(s) + if: always() + run: | + conan upload "*" -r cura --all -c + - name: Set Environment variables for Cura (Powershell) run: | echo "${Env:WIX}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append @@ -262,4 +267,4 @@ jobs: success_body: "Installers for ${{ inputs.cura_conan_version }}" failure_title: "Failed to create the Cura distributions" failure_body: "Failed to create at least 1 installer for ${{ inputs.cura_conan_version }}" - secrets: inherit \ No newline at end of file + secrets: inherit diff --git a/conanfile.py b/conanfile.py index 7725ade370..a06cd9a8e9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -10,7 +10,7 @@ from conan.tools.env import VirtualRunEnv, Environment, VirtualBuildEnv from conan.tools.scm import Version from conan.errors import ConanInvalidConfiguration, ConanException -required_conan_version = ">=1.54 <=1.56.0 || >=1.58.0 <2.0.0" +required_conan_version = ">=1.58.0 <2.0.0" class CuraConan(ConanFile): @@ -301,7 +301,7 @@ class CuraConan(ConanFile): raise ConanInvalidConfiguration("Only versions 5+ are support") def requirements(self): - self.requires("boost/1.81.0") + self.requires("boost/1.82.0") self.requires("pyarcus/(latest)@ultimaker/cura_10951") self.requires("curaengine/(latest)@ultimaker/cura_10446") self.requires("pysavitar/(latest)@ultimaker/cura_10951") @@ -340,7 +340,38 @@ class CuraConan(ConanFile): vr.generate() self._generate_cura_version(os.path.join(self.source_folder, "cura")) + self._generate_about_versions(os.path.join(self.source_folder, "resources","qml", "Dialogs")) + if not self.in_local_cache: + # Copy CuraEngine.exe to bindirs of Virtual Python Environment + curaengine = self.dependencies["curaengine"].cpp_info + copy(self, "CuraEngine.exe", curaengine.bindirs[0], self.source_folder, keep_path = False) + copy(self, "CuraEngine", curaengine.bindirs[0], self.source_folder, keep_path = False) + + # Copy resources of cura_binary_data + cura_binary_data = self.dependencies["cura_binary_data"].cpp_info + copy(self, "*", cura_binary_data.resdirs[0], str(self._share_dir.joinpath("cura")), keep_path = True) + copy(self, "*", cura_binary_data.resdirs[1], str(self._share_dir.joinpath("uranium")), keep_path = True) + if self.settings.os == "Windows": + copy(self, "*", cura_binary_data.resdirs[2], str(self._share_dir.joinpath("windows")), keep_path = True) + + for dependency in self.dependencies.host.values(): + for bindir in dependency.cpp_info.bindirs: + copy(self, "*.dll", bindir, str(self._site_packages), keep_path = False) + for libdir in dependency.cpp_info.libdirs: + copy(self, "*.pyd", libdir, str(self._site_packages), keep_path = False) + copy(self, "*.pyi", libdir, str(self._site_packages), keep_path = False) + copy(self, "*.dylib", libdir, str(self._base_dir.joinpath("lib")), keep_path = False) + + # Copy materials (flat) + rmdir(self, os.path.join(self.source_folder, "resources", "materials")) + fdm_materials = self.dependencies["fdm_materials"].cpp_info + copy(self, "*", fdm_materials.resdirs[0], self.source_folder) + + # Copy internal resources + if self.options.internal: + cura_private_data = self.dependencies["cura_private_data"].cpp_info + copy(self, "*", cura_private_data.resdirs[0], str(self._share_dir.joinpath("cura"))) if self.options.devtools: entitlements_file = "'{}'".format(os.path.join(self.source_folder, "packaging", "MacOS", "cura.entitlements")) @@ -359,8 +390,6 @@ class CuraConan(ConanFile): pot = self.python_requires["translationextractor"].module.ExtractTranslations(self, cpp_info.bindirs[0]) pot.generate() - self._generate_about_versions(os.path.join(self.source_folder, "resources","qml", "Dialogs")) - def build(self): if self.options.devtools: if self.settings.os != "Windows" or self.conf.get("tools.microsoft.bash:path", check_type = str): @@ -372,29 +401,6 @@ class CuraConan(ConanFile): cpp_info = self.dependencies["gettext"].cpp_info self.run(f"{cpp_info.bindirs[0]}/msgfmt {po_file} -o {mo_file} -f", env="conanbuild", ignore_errors=True) - def imports(self): - self.copy("CuraEngine.exe", root_package = "curaengine", src = "@bindirs", dst = "", keep_path = False) - self.copy("CuraEngine", root_package = "curaengine", src = "@bindirs", dst = "", keep_path = False) - - rmdir(self, os.path.join(self.source_folder, "resources", "materials")) - self.copy("*.fdm_material", root_package = "fdm_materials", src = "@resdirs", dst = "resources/materials", keep_path = False) - self.copy("*.sig", root_package = "fdm_materials", src = "@resdirs", dst = "resources/materials", keep_path = False) - - if self.options.internal: - self.copy("*", root_package = "cura_private_data", src = self.deps_cpp_info["cura_private_data"].resdirs[0], - dst = self._share_dir.joinpath("cura", "resources"), keep_path = True) - - # Copy resources of cura_binary_data - self.copy("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[0], - dst = self._share_dir.joinpath("cura", "resources"), keep_path = True) - self.copy("*", root_package = "cura_binary_data", src = self.deps_cpp_info["cura_binary_data"].resdirs[1], - dst =self._share_dir.joinpath("uranium", "resources"), keep_path = True) - - self.copy("*.dll", src = "@bindirs", dst = self._site_packages) - self.copy("*.pyd", src = "@libdirs", dst = self._site_packages) - self.copy("*.pyi", src = "@libdirs", dst = self._site_packages) - self.copy("*.dylib", src = "@libdirs", dst = self._script_dir) - def deploy(self): # Copy CuraEngine.exe to bindirs of Virtual Python Environment curaengine = self.dependencies["curaengine"].cpp_info diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 0cce9ffbc1..baad82f5a2 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -411,7 +411,9 @@ class CuraApplication(QtApplication): SettingFunction.registerOperator("extruderValue", self._cura_formula_functions.getValueInExtruder) SettingFunction.registerOperator("extruderValues", self._cura_formula_functions.getValuesInAllExtruders) - SettingFunction.registerOperator("anyExtruderNrWithOrDefault", self._cura_formula_functions.getAnyExtruderPositionWithOrDefault) + SettingFunction.registerOperator("anyExtruderWithMaterial", self._cura_formula_functions.getExtruderPositionWithMaterial) + SettingFunction.registerOperator("anyExtruderNrWithOrDefault", + self._cura_formula_functions.getAnyExtruderPositionWithOrDefault) SettingFunction.registerOperator("resolveOrValue", self._cura_formula_functions.getResolveOrValue) SettingFunction.registerOperator("defaultExtruderPosition", self._cura_formula_functions.getDefaultExtruderPosition) SettingFunction.registerOperator("valueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndex) diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index fd6555e679..d7b6228e09 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -99,12 +99,21 @@ class CuraFormulaFunctions: # Get the first extruder that adheres to a specific (boolean) property, like 'material_is_support_material'. def getAnyExtruderPositionWithOrDefault(self, filter_key: str, - context: Optional["PropertyEvaluationContext"] = None) -> str: + context: Optional["PropertyEvaluationContext"] = None) -> str: for extruder in self._getActiveExtruders(context): value = extruder.getRawProperty(filter_key, "value", context=context) if value is None or not value: continue return str(extruder.position) + + # Get the first extruder with material that adheres to a specific (boolean) property, like 'material_is_support_material'. + def getExtruderPositionWithMaterial(self, filter_key: str, + context: Optional["PropertyEvaluationContext"] = None) -> str: + for extruder in self._getActiveExtruders(context): + material_container = extruder.material + value = material_container.getProperty(filter_key, "value", context) + if value is not None: + return str(extruder.position) return self.getDefaultExtruderPosition() # Get the resolve value or value for a given key. diff --git a/docs/profiles/getting_a_setting_value.md b/docs/profiles/getting_a_setting_value.md index bd106eb2da..7cd912ac45 100644 --- a/docs/profiles/getting_a_setting_value.md +++ b/docs/profiles/getting_a_setting_value.md @@ -54,7 +54,10 @@ There are also a few extra things that can be used in these expressions: * The function `extruderValue(extruder, key)` will evaluate a particular setting for a particular extruder. * The function `resolveOrValue(key)` will perform the full setting evaluation as described in this document for the current context (so if this setting is being evaluated for the second extruder it would perform it as if coming from the second extruder). * The function `defaultExtruderPosition()` will get the first extruder that is not disabled. For instance, if a printer has three extruders but the first is disabled, this would return `1` to indicate the second extruder (0-indexed). -* The function `anyExtruderNrWithOrDefault(key)` will filter the list of extruders on the key, and then give the first index for which it is true, or if none of them are, the default one as specified by the 'default extruder position' function above. +* The function `anyExtruderNrWithOrDefault(key)` will filter the list of extruders on the key, and then give the first + index for which it is true, or if none of them are, the default one as specified by the 'default extruder position' + function above. +* The function `anyExtruderWithMaterial(key)` will filter the list of extruders on the key of material quality, and then give the first index for which it is true, or if none of them are, the default one as specified by the 'default extruder position' function above. * The function `valueFromContainer(key, index)` will get a setting value from the global stack, but skip the first few containers in that stack. It will skip until it reaches a particular index in the container stack. * The function `extruderValueFromContainer(key, index)` will get a setting value from the current extruder stack, but skip the first few containers in that stack. It will skip until it reaches a particular index in the container stack. diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ccd92c9ba3..40d1eb3b1c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -4500,7 +4500,7 @@ "type": "extruder", "default_value": "0", "enabled": "(support_enable or support_meshes_present) and extruders_enabled_count > 1", - "value": "int(defaultExtruderPosition())", + "value": "int(anyExtruderWithMaterial('material_is_support_material'))", "settable_per_mesh": false, "settable_per_extruder": false, "children": diff --git a/resources/definitions/matterhackers_pulsexe_e444m.def.json b/resources/definitions/matterhackers_pulsexe_e444m.def.json new file mode 100644 index 0000000000..fc5d4f6dda --- /dev/null +++ b/resources/definitions/matterhackers_pulsexe_e444m.def.json @@ -0,0 +1,60 @@ +{ + "version": 2, + "name": "Pulse XE E-444M", + "inherits": "fdmprinter", + "metadata": + { + "visible": true, + "author": "Zwitch Guitars", + "manufacturer": "MatterHackers", + "file_formats": "text/x-gcode", + "first_start_actions": [ "MachineSettingsAction" ], + "has_machine_quality": false, + "has_materials": true, + "has_variants": false, + "machine_extruder_trains": { "0": "matterhackers_extruder" }, + "preferred_material": "generic_pla", + "preferred_quality_type": "normal" + }, + "overrides": + { + "adhesion_type": { "value": "skirt" }, + "cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" }, + "cool_min_layer_time": { "value": 10 }, + "gantry_height": { "value": 23 }, + "machine_acceleration": { "value": 1300 }, + "machine_depth": { "default_value": 220 }, + "machine_end_gcode": { "default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y{machine_depth}; home X axis and push Y forward\nG28 Z0\nM84 ; disable motors" }, + "machine_gcode_flavor": { "default_value": "Marlin" }, + "machine_head_with_fans_polygon": + { + "default_value": [ + [-28, 45], + [-28, -18], + [40, 45], + [40, -18] + ] + }, + "machine_heated_bed": { "default_value": true }, + "machine_height": { "default_value": 215 }, + "machine_max_feedrate_e": { "value": 75 }, + "machine_max_feedrate_x": { "value": 300 }, + "machine_max_feedrate_y": { "value": 300 }, + "machine_max_feedrate_z": { "value": 30 }, + "machine_name": { "default_value": "Pulse XE E-444M" }, + "machine_start_gcode": { "default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nG28 ; home axes\nM104 S{material_print_temperature_layer_0} ; set extruder temp\nM140 S{material_bed_temperature_layer_0} ; set bed temp\nM190 S{material_bed_temperature_layer_0} ; wait for bed temp\nM109 S{material_print_temperature_layer_0} ; wait for extruder temp\nG29 ; mesh bed leveling\n\nG92 E0\nG1 X5 Y5 Z0.8 F1800\nG1 X100 Z0.3 E25 F900\nG92 E0\nG1 E-2 F2400" }, + "machine_steps_per_mm_e": { "value": 415 }, + "machine_steps_per_mm_x": { "value": 80 }, + "machine_steps_per_mm_y": { "value": 80 }, + "machine_steps_per_mm_z": { "value": 400 }, + "machine_width": { "default_value": 250 }, + "material_diameter": { "value": 1.75 }, + "optimize_wall_printing_order": { "value": true }, + "speed_layer_0": { "value": 20.0 }, + "speed_print": { "value": 50 }, + "top_bottom_thickness": { "value": "layer_height_0 + layer_height * 3" }, + "travel_retract_before_outer_wall": { "value": true }, + "wall_thickness": { "value": "line_width * 2" }, + "z_seam_type": { "value": "back" } + } +} \ No newline at end of file diff --git a/resources/extruders/matterhackers_extruder.def.json b/resources/extruders/matterhackers_extruder.def.json new file mode 100644 index 0000000000..f05e4b4e20 --- /dev/null +++ b/resources/extruders/matterhackers_extruder.def.json @@ -0,0 +1,16 @@ +{ + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": + { + "machine": "matterhackers_pulsexe_e444m", + "position": "0" + }, + "overrides": + { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} \ No newline at end of file