Merge branch 'main' into ender3_v2_neo_config

This commit is contained in:
Saumya Jain 2024-03-01 10:58:16 +01:00 committed by GitHub
commit 7a6604d5fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
705 changed files with 2763 additions and 879 deletions

View file

@ -4,7 +4,7 @@ labels: ["Type: Bug", "Status: Triage", "Slicing Error :collision:"]
body:
- type: markdown
attributes:
value: |
value: |
### 💥 Slicing Crash Analysis Tool 💥
We are taking steps to analyze an increase in reported crashes more systematically. We'll need some help with that. 😇
Before filling out the report below, we want you to try a special Cura 5.7 Alpha.

View file

@ -350,6 +350,7 @@ class CuraConan(ConanFile):
self.requires("cpython/3.10.4@ultimaker/stable")
self.requires("clipper/6.4.2@ultimaker/stable")
self.requires("openssl/3.2.0")
self.requires("protobuf/3.21.12")
self.requires("boost/1.82.0")
self.requires("spdlog/1.12.0")
self.requires("fmt/10.1.1")

View file

@ -880,7 +880,7 @@ class BuildVolume(SceneNode):
result[extruder.getId()] = []
# Currently, the only normally printed object is the prime tower.
if self._global_container_stack.getProperty("prime_tower_mode", "value") != 'none':
if self._global_container_stack.getProperty("prime_tower_enable", "value"):
prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value")
machine_width = self._global_container_stack.getProperty("machine_width", "value")
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
@ -1208,7 +1208,7 @@ class BuildVolume(SceneNode):
_raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_layers", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap", "layer_0_z_overlap"]
_extra_z_settings = ["retraction_hop_enabled", "retraction_hop"]
_prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "prime_blob_enable"]
_tower_settings = ["prime_tower_mode", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y", "prime_tower_brim_enable", "prime_tower_base_size", "prime_tower_base_height"]
_tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y", "prime_tower_brim_enable", "prime_tower_base_size", "prime_tower_base_height"]
_ooze_shield_settings = ["ooze_shield_enabled", "ooze_shield_dist"]
_distance_settings = ["infill_wipe_dist", "travel_avoid_distance", "support_offset", "support_enable", "travel_avoid_other_parts", "travel_avoid_supports", "wall_line_count", "wall_line_width_0", "wall_line_width_x"]
_extruder_settings = ["support_enable", "support_bottom_enable", "support_roof_enable", "support_infill_extruder_nr", "support_extruder_nr_layer_0", "support_bottom_extruder_nr", "support_roof_extruder_nr", "brim_line_count", "skirt_brim_extruder_nr", "raft_base_extruder_nr", "raft_interface_extruder_nr", "raft_surface_extruder_nr", "adhesion_type"] #Settings that can affect which extruders are used.

View file

@ -273,7 +273,11 @@ class CuraActions(QObject):
# deselect currently selected nodes, and select the new nodes
for node in Selection.getAllSelectedObjects():
Selection.remove(node)
numberOfFixedNodes = len(fixed_nodes)
for node in nodes:
numberOfFixedNodes += 1
node.printOrder = numberOfFixedNodes
Selection.add(node)
def _openUrl(self, url: QUrl) -> None:

View file

@ -601,7 +601,9 @@ class CuraApplication(QtApplication):
preferences.addPreference("mesh/scale_to_fit", False)
preferences.addPreference("mesh/scale_tiny_meshes", True)
preferences.addPreference("cura/dialog_on_project_save", True)
preferences.addPreference("cura/dialog_on_ucp_project_save", True)
preferences.addPreference("cura/asked_dialog_on_project_save", False)
preferences.addPreference("cura/asked_dialog_on_ucp_project_save", False)
preferences.addPreference("cura/choice_on_profile_override", "always_ask")
preferences.addPreference("cura/choice_on_open_project", "always_ask")
preferences.addPreference("cura/use_multi_build_plate", False)
@ -617,6 +619,7 @@ class CuraApplication(QtApplication):
preferences.addPreference("view/invert_zoom", False)
preferences.addPreference("view/filter_current_build_plate", False)
preferences.addPreference("view/navigation_style", "cura")
preferences.addPreference("cura/sidebar_collapsed", False)
preferences.addPreference("cura/favorite_materials", "")
@ -1082,9 +1085,9 @@ class CuraApplication(QtApplication):
def getTextManager(self, *args) -> "TextManager":
return self._text_manager
@pyqtSlot(bool)
def getWorkplaceDropToBuildplate(self, drop_to_build_plate: bool) ->None:
return self._physics.setAppPerModelDropDown(drop_to_build_plate)
@pyqtSlot()
def setWorkplaceDropToBuildplate(self):
return self._physics.setAppAllModelDropDown()
def getCuraFormulaFunctions(self, *args) -> "CuraFormulaFunctions":
if self._cura_formula_functions is None:
@ -1141,6 +1144,16 @@ class CuraApplication(QtApplication):
self._build_plate_model = BuildPlateModel(self)
return self._build_plate_model
@pyqtSlot()
def exportUcp(self):
writer = self.getMeshFileHandler().getWriter("3MFWriter")
if writer is None:
Logger.warning("3mf writer is not enabled")
return
writer.exportUcp()
def getCuraSceneController(self, *args) -> CuraSceneController:
if self._cura_scene_controller is None:
self._cura_scene_controller = CuraSceneController.createCuraSceneController()

View file

@ -38,14 +38,12 @@ class PlatformPhysics:
self._minimum_gap = 2 # It is a minimum distance (in mm) between two models, applicable for small models
Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", False)
Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", False)
self._app_per_model_drop = Application.getInstance().getPreferences().getValue("physics/automatic_drop_down")
Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", True)
self._app_all_model_drop = False
def getAppPerModelDropDown(self):
return self._app_per_model_drop
def setAppPerModelDropDown(self, drop_to_buildplate):
self._app_per_model_drop = drop_to_buildplate
def setAppAllModelDropDown(self):
self._app_all_model_drop = True
self._onChangeTimerFinished()
def _onSceneChanged(self, source):
if not source.callDecoration("isSliceable"):
@ -78,7 +76,6 @@ class PlatformPhysics:
# We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
# By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
random.shuffle(nodes)
for node in nodes:
if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None:
continue
@ -88,12 +85,9 @@ class PlatformPhysics:
# Move it downwards if bottom is above platform
move_vector = Vector()
# if per model drop is different then app_automatic_drop, in case of 3mf loading when user changes this setting for that model
if (self._app_per_model_drop != app_automatic_drop_down):
node.setSetting(SceneNodeSettings.AutoDropDown, self._app_per_model_drop)
if node.getSetting(SceneNodeSettings.AutoDropDown, self._app_per_model_drop) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled(): #If an object is grouped, don't move it down
if (node.getSetting(SceneNodeSettings.AutoDropDown, app_automatic_drop_down) or self._app_all_model_drop) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled():
z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
move_vector = move_vector.set(y = -bbox.bottom + z_offset)
move_vector = move_vector.set(y=-bbox.bottom + z_offset)
# If there is no convex hull for the node, start calculating it and continue.
if not node.getDecorator(ConvexHullDecorator) and not node.callDecoration("isNonPrintingMesh") and node.callDecoration("getLayerData") is None:
@ -180,7 +174,7 @@ class PlatformPhysics:
op.push()
# setting this drop to model same as app_automatic_drop_down
self._app_per_model_drop = app_automatic_drop_down
self._app_all_model_drop = False
# After moving, we have to evaluate the boundary checks for nodes
build_volume.updateNodeBoundaryCheck()

View file

@ -116,6 +116,9 @@ class PrintOrderManager(QObject):
) -> (Optional[CuraSceneNode], Optional[CuraSceneNode], Optional[CuraSceneNode]):
nodes = self._get_nodes()
ordered_nodes = sorted(nodes, key=lambda n: n.printOrder)
for i, node in enumerate(ordered_nodes, 1):
node.printOrder = i
selected_node = PrintOrderManager._getSingleSelectedNode()
if selected_node and selected_node in ordered_nodes:
selected_node_index = ordered_nodes.index(selected_node)

View file

@ -11,6 +11,7 @@ from UM.Scene.SceneNode import SceneNode
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator # To cast the deepcopy of every decorator back to SceneNodeDecorator.
import cura.CuraApplication # To get the build plate.
from UM.Scene.SceneNodeSettings import SceneNodeSettings
from cura.Settings.ExtruderStack import ExtruderStack # For typing.
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator # For per-object settings.
@ -41,6 +42,10 @@ class CuraSceneNode(SceneNode):
def isOutsideBuildArea(self) -> bool:
return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0
@property
def isDropDownEnabled(self) ->bool:
return self.getSetting(SceneNodeSettings.AutoDropDown, Application.getInstance().getPreferences().getValue("physics/automatic_drop_down"))
def isVisible(self) -> bool:
return super().isVisible() and self.callDecoration("getBuildPlateNumber") == cura.CuraApplication.CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate

View file

@ -0,0 +1,38 @@
# Copyright (c) 2024 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt6.QtCore import Qt
from UM.Settings.SettingDefinition import SettingDefinition
from UM.Qt.ListModel import ListModel
class SpecificSettingsModel(ListModel):
CategoryRole = Qt.ItemDataRole.UserRole + 1
LabelRole = Qt.ItemDataRole.UserRole + 2
ValueRole = Qt.ItemDataRole.UserRole + 3
def __init__(self, parent = None):
super().__init__(parent = parent)
self.addRoleName(self.CategoryRole, "category")
self.addRoleName(self.LabelRole, "label")
self.addRoleName(self.ValueRole, "value")
self._i18n_catalog = None
def addSettingsFromStack(self, stack, category, settings):
for setting, value in settings.items():
unit = stack.getProperty(setting, "unit")
setting_type = stack.getProperty(setting, "type")
if setting_type is not None:
# This is not very good looking, but will do for now
value = SettingDefinition.settingValueToString(setting_type, value) + " " + unit
else:
value = str(value)
self.appendItem({
"category": category,
"label": stack.getProperty(setting, "label"),
"value": value
})

View file

@ -16,6 +16,7 @@ from UM.Mesh.MeshReader import MeshReader
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
from UM.Scene.GroupDecorator import GroupDecorator
from UM.Scene.SceneNode import SceneNode # For typing.
from UM.Scene.SceneNodeSettings import SceneNodeSettings
from cura.CuraApplication import CuraApplication
from cura.Machines.ContainerTree import ContainerTree
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
@ -41,7 +42,7 @@ class ThreeMFReader(MeshReader):
MimeTypeDatabase.addMimeType(
MimeType(
name = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
name="application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
comment="3MF",
suffixes=["3mf"]
)
@ -180,6 +181,9 @@ class ThreeMFReader(MeshReader):
if key == "print_order":
um_node.printOrder = int(setting_value)
continue
if key =="drop_to_buildplate":
um_node.setSetting(SceneNodeSettings.AutoDropDown, eval(setting_value))
continue
if key in known_setting_keys:
setting_container.setProperty(key, "value", setting_value)
else:

View file

@ -5,6 +5,7 @@ from configparser import ConfigParser
import zipfile
import os
import json
import re
from typing import cast, Dict, List, Optional, Tuple, Any, Set
import xml.etree.ElementTree as ET
@ -57,6 +58,7 @@ _ignored_machine_network_metadata: Set[str] = {
"is_abstract_machine"
}
USER_SETTINGS_PATH = "Cura/user-settings.json"
class ContainerInfo:
def __init__(self, file_name: Optional[str], serialized: Optional[str], parser: Optional[ConfigParser]) -> None:
@ -141,10 +143,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._old_new_materials: Dict[str, str] = {}
self._machine_info = None
self._load_profile = False
self._user_settings: Dict[str, Dict[str, Any]] = {}
def _clearState(self):
self._id_mapping = {}
self._old_new_materials = {}
self._machine_info = None
self._load_profile = False
self._user_settings = {}
def getNewId(self, old_id: str):
"""Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
@ -228,11 +235,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._resolve_strategies = {k: None for k in resolve_strategy_keys}
containers_found_dict = {k: False for k in resolve_strategy_keys}
# Check whether the file is a UCP, which changes some import options
is_ucp = USER_SETTINGS_PATH in cura_file_names
#
# Read definition containers
#
machine_definition_id = None
updatable_machines = []
updatable_machines = None if is_ucp else []
machine_definition_container_count = 0
extruder_definition_container_count = 0
definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
@ -250,7 +260,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if definition_container_type == "machine":
machine_definition_id = container_id
machine_definition_containers = self._container_registry.findDefinitionContainers(id = machine_definition_id)
if machine_definition_containers:
if machine_definition_containers and updatable_machines is not None:
updatable_machines = [machine for machine in self._container_registry.findContainerStacks(type = "machine") if machine.definition == machine_definition_containers[0]]
machine_type = definition_container["name"]
variant_type_name = definition_container.get("variants_name", variant_type_name)
@ -597,6 +607,37 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
package_metadata = self._parse_packages_metadata(archive)
missing_package_metadata = self._filter_missing_package_metadata(package_metadata)
# Load the user specifically exported settings
self._dialog.exportedSettingModel.clear()
if is_ucp:
try:
self._user_settings = json.loads(archive.open("Cura/user-settings.json").read().decode("utf-8"))
any_extruder_stack = ExtruderManager.getInstance().getExtruderStack(0)
actual_global_stack = CuraApplication.getInstance().getGlobalContainerStack()
for stack_name, settings in self._user_settings.items():
if stack_name == 'global':
self._dialog.exportedSettingModel.addSettingsFromStack(actual_global_stack, i18n_catalog.i18nc("@label", "Global"), settings)
else:
extruder_match = re.fullmatch('extruder_([0-9]+)', stack_name)
if extruder_match is not None:
extruder_nr = int(extruder_match.group(1))
self._dialog.exportedSettingModel.addSettingsFromStack(any_extruder_stack,
i18n_catalog.i18nc("@label",
"Extruder {0}", extruder_nr + 1),
settings)
except KeyError as e:
# If there is no user settings file, it's not a UCP, so notify user of failure.
Logger.log("w", "File %s is not a valid UCP.", file_name)
message = Message(
i18n_catalog.i18nc("@info:error Don't translate the XML tags <filename> or <message>!",
"Project file <filename>{0}</filename> is corrupt: <message>{1}</message>.",
file_name, str(e)),
title=i18n_catalog.i18nc("@info:title", "Can't Open Project File"),
message_type=Message.MessageType.ERROR)
message.show()
return WorkspaceReader.PreReadResult.failed
# Show the dialog, informing the user what is about to happen.
self._dialog.setMachineConflict(machine_conflict)
self._dialog.setIsPrinterGroup(is_printer_group)
@ -617,8 +658,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setVariantType(variant_type_name)
self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity)
self._dialog.setMissingPackagesMetadata(missing_package_metadata)
self._dialog.setHasVisibleSelectSameProfileChanged(is_ucp)
self._dialog.setAllowCreatemachine(not is_ucp)
self._dialog.show()
# Choosing the initially selected printer in MachineSelector
is_networked_machine = False
is_abstract_machine = False
@ -648,6 +692,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setIsNetworkedMachine(is_networked_machine)
self._dialog.setIsAbstractMachine(is_abstract_machine)
self._dialog.setMachineName(machine_name)
self._dialog.updateCompatibleMachine()
self._dialog.setSelectSameProfileChecked(self._dialog.isCompatibleMachine)
# Block until the dialog is closed.
self._dialog.waitForClose()
@ -655,6 +701,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if self._dialog.getResult() == {}:
return WorkspaceReader.PreReadResult.cancelled
self._load_profile = not is_ucp or (self._dialog.selectSameProfileChecked and self._dialog.isCompatibleMachine)
self._resolve_strategies = self._dialog.getResult()
#
# There can be 3 resolve strategies coming from the dialog:
@ -690,16 +738,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
except EnvironmentError as e:
message = Message(i18n_catalog.i18nc("@info:error Don't translate the XML tags <filename> or <message>!",
"Project file <filename>{0}</filename> is suddenly inaccessible: <message>{1}</message>.", file_name, str(e)),
title = i18n_catalog.i18nc("@info:title", "Can't Open Project File"),
message_type = Message.MessageType.ERROR)
title = i18n_catalog.i18nc("@info:title", "Can't Open Project File"),
message_type = Message.MessageType.ERROR)
message.show()
self.setWorkspaceName("")
return [], {}
except zipfile.BadZipFile as e:
message = Message(i18n_catalog.i18nc("@info:error Don't translate the XML tags <filename> or <message>!",
"Project file <filename>{0}</filename> is corrupt: <message>{1}</message>.", file_name, str(e)),
title = i18n_catalog.i18nc("@info:title", "Can't Open Project File"),
message_type = Message.MessageType.ERROR)
title = i18n_catalog.i18nc("@info:title", "Can't Open Project File"),
message_type = Message.MessageType.ERROR)
message.show()
self.setWorkspaceName("")
return [], {}
@ -761,9 +809,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# Find the machine which will be overridden
global_stacks = self._container_registry.findContainerStacks(id = self._dialog.getMachineToOverride(), type = "machine")
if not global_stacks:
message = Message(i18n_catalog.i18nc("@info:error Don't translate the XML tag <filename>!",
message = Message(i18n_catalog.i18nc("@info:error Don't translate the XML tag <filename>!",
"Project file <filename>{0}</filename> is made using profiles that are unknown to this version of UltiMaker Cura.", file_name),
message_type = Message.MessageType.ERROR)
message_type = Message.MessageType.ERROR)
message.show()
self.setWorkspaceName("")
return [], {}
@ -777,84 +825,89 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
for stack in extruder_stacks:
stack.setNextStack(global_stack, connect_signals = False)
Logger.log("d", "Workspace loading is checking definitions...")
# Get all the definition files & check if they exist. If not, add them.
definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
for definition_container_file in definition_container_files:
container_id = self._stripFileToId(definition_container_file)
if self._load_profile:
Logger.log("d", "Workspace loading is checking definitions...")
# Get all the definition files & check if they exist. If not, add them.
definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
for definition_container_file in definition_container_files:
container_id = self._stripFileToId(definition_container_file)
definitions = self._container_registry.findDefinitionContainersMetadata(id = container_id)
if not definitions:
definition_container = DefinitionContainer(container_id)
try:
definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8"),
file_name = definition_container_file)
except ContainerFormatError:
# We cannot just skip the definition file because everything else later will just break if the
# machine definition cannot be found.
Logger.logException("e", "Failed to deserialize definition file %s in project file %s",
definition_container_file, file_name)
definition_container = self._container_registry.findDefinitionContainers(id = "fdmprinter")[0] #Fall back to defaults.
self._container_registry.addContainer(definition_container)
Job.yieldThread()
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
Logger.log("d", "Workspace loading is checking materials...")
# Get all the material files and check if they exist. If not, add them.
xml_material_profile = self._getXmlProfileClass()
if self._material_container_suffix is None:
self._material_container_suffix = ContainerRegistry.getMimeTypeForContainer(xml_material_profile).suffixes[0]
if xml_material_profile:
material_container_files = [name for name in cura_file_names if name.endswith(self._material_container_suffix)]
for material_container_file in material_container_files:
to_deserialize_material = False
container_id = self._stripFileToId(material_container_file)
need_new_name = False
materials = self._container_registry.findInstanceContainers(id = container_id)
if not materials:
# No material found, deserialize this material later and add it
to_deserialize_material = True
else:
material_container = materials[0]
old_material_root_id = material_container.getMetaDataEntry("base_file")
if old_material_root_id is not None and not self._container_registry.isReadOnly(old_material_root_id): # Only create new materials if they are not read only.
to_deserialize_material = True
if self._resolve_strategies["material"] == "override":
# Remove the old materials and then deserialize the one from the project
root_material_id = material_container.getMetaDataEntry("base_file")
application.getContainerRegistry().removeContainer(root_material_id)
elif self._resolve_strategies["material"] == "new":
# Note that we *must* deserialize it with a new ID, as multiple containers will be
# auto created & added.
container_id = self.getNewId(container_id)
self._old_new_materials[old_material_root_id] = container_id
need_new_name = True
if to_deserialize_material:
material_container = xml_material_profile(container_id)
definitions = self._container_registry.findDefinitionContainersMetadata(id = container_id)
if not definitions:
definition_container = DefinitionContainer(container_id)
try:
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"),
file_name = container_id + "." + self._material_container_suffix)
definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8"),
file_name = definition_container_file)
except ContainerFormatError:
Logger.logException("e", "Failed to deserialize material file %s in project file %s",
material_container_file, file_name)
continue
if need_new_name:
new_name = ContainerRegistry.getInstance().uniqueName(material_container.getName())
material_container.setName(new_name)
material_container.setDirty(True)
self._container_registry.addContainer(material_container)
# We cannot just skip the definition file because everything else later will just break if the
# machine definition cannot be found.
Logger.logException("e", "Failed to deserialize definition file %s in project file %s",
definition_container_file, file_name)
definition_container = self._container_registry.findDefinitionContainers(id = "fdmprinter")[0] #Fall back to defaults.
self._container_registry.addContainer(definition_container)
Job.yieldThread()
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
if global_stack:
# Handle quality changes if any
self._processQualityChanges(global_stack)
Logger.log("d", "Workspace loading is checking materials...")
# Get all the material files and check if they exist. If not, add them.
xml_material_profile = self._getXmlProfileClass()
if self._material_container_suffix is None:
self._material_container_suffix = ContainerRegistry.getMimeTypeForContainer(xml_material_profile).suffixes[0]
if xml_material_profile:
material_container_files = [name for name in cura_file_names if name.endswith(self._material_container_suffix)]
for material_container_file in material_container_files:
to_deserialize_material = False
container_id = self._stripFileToId(material_container_file)
need_new_name = False
materials = self._container_registry.findInstanceContainers(id = container_id)
# Prepare the machine
self._applyChangesToMachine(global_stack, extruder_stack_dict)
if not materials:
# No material found, deserialize this material later and add it
to_deserialize_material = True
else:
material_container = materials[0]
old_material_root_id = material_container.getMetaDataEntry("base_file")
if old_material_root_id is not None and not self._container_registry.isReadOnly(old_material_root_id): # Only create new materials if they are not read only.
to_deserialize_material = True
if self._resolve_strategies["material"] == "override":
# Remove the old materials and then deserialize the one from the project
root_material_id = material_container.getMetaDataEntry("base_file")
application.getContainerRegistry().removeContainer(root_material_id)
elif self._resolve_strategies["material"] == "new":
# Note that we *must* deserialize it with a new ID, as multiple containers will be
# auto created & added.
container_id = self.getNewId(container_id)
self._old_new_materials[old_material_root_id] = container_id
need_new_name = True
if to_deserialize_material:
material_container = xml_material_profile(container_id)
try:
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"),
file_name = container_id + "." + self._material_container_suffix)
except ContainerFormatError:
Logger.logException("e", "Failed to deserialize material file %s in project file %s",
material_container_file, file_name)
continue
if need_new_name:
new_name = ContainerRegistry.getInstance().uniqueName(material_container.getName())
material_container.setName(new_name)
material_container.setDirty(True)
self._container_registry.addContainer(material_container)
Job.yieldThread()
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
if global_stack:
if self._load_profile:
# Handle quality changes if any
self._processQualityChanges(global_stack)
# Prepare the machine
self._applyChangesToMachine(global_stack, extruder_stack_dict)
else:
# Just clear the settings now, so that we can change the active machine without conflicts
self._clearMachineSettings(global_stack, extruder_stack_dict)
Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
# Actually change the active machine.
@ -866,6 +919,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# To solve this, we schedule _updateActiveMachine() for later so it will have the latest data.
self._updateActiveMachine(global_stack)
if not self._load_profile:
# Now we have switched, apply the user settings
self._applyUserSettings(global_stack, extruder_stack_dict, self._user_settings)
# Load all the nodes / mesh data of the workspace
nodes = self._3mf_mesh_reader.read(file_name)
if nodes is None:
@ -1177,21 +1234,44 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
extruder_stack.material = material_node.container
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
# Clear all first
def _clearMachineSettings(self, global_stack, extruder_stack_dict):
self._clearStack(global_stack)
for extruder_stack in extruder_stack_dict.values():
self._clearStack(extruder_stack)
self._quality_changes_to_apply = None
self._quality_type_to_apply = None
self._intent_category_to_apply = None
self._user_settings_to_apply = None
def _applyUserSettings(self, global_stack, extruder_stack_dict, user_settings):
for stack_name, settings in user_settings.items():
if stack_name == 'global':
ThreeMFWorkspaceReader._applyUserSettingsOnStack(global_stack, settings)
else:
extruder_match = re.fullmatch('extruder_([0-9]+)', stack_name)
if extruder_match is not None:
extruder_nr = extruder_match.group(1)
if extruder_nr in extruder_stack_dict:
ThreeMFWorkspaceReader._applyUserSettingsOnStack(extruder_stack_dict[extruder_nr], settings)
@staticmethod
def _applyUserSettingsOnStack(stack, user_settings):
user_settings_container = stack.userChanges
for setting_to_import, setting_value in user_settings.items():
user_settings_container.setProperty(setting_to_import, 'value', setting_value)
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
# Clear all first
self._clearMachineSettings(global_stack, extruder_stack_dict)
self._applyDefinitionChanges(global_stack, extruder_stack_dict)
self._applyUserChanges(global_stack, extruder_stack_dict)
self._applyVariants(global_stack, extruder_stack_dict)
self._applyMaterials(global_stack, extruder_stack_dict)
# prepare the quality to select
self._quality_changes_to_apply = None
self._quality_type_to_apply = None
self._intent_category_to_apply = None
if self._machine_info.quality_changes_info is not None:
self._quality_changes_to_apply = self._machine_info.quality_changes_info.name
else:

View file

@ -22,6 +22,8 @@ import time
from cura.CuraApplication import CuraApplication
from .SpecificSettingsModel import SpecificSettingsModel
i18n_catalog = i18nCatalog("cura")
@ -71,6 +73,11 @@ class WorkspaceDialog(QObject):
self._install_missing_package_dialog: Optional[QObject] = None
self._is_abstract_machine = False
self._is_networked_machine = False
self._is_compatible_machine = False
self._has_visible_select_same_profile = False
self._select_same_profile_checked = True
self._allow_create_machine = True
self._exported_settings_model = SpecificSettingsModel()
machineConflictChanged = pyqtSignal()
qualityChangesConflictChanged = pyqtSignal()
@ -94,6 +101,9 @@ class WorkspaceDialog(QObject):
extrudersChanged = pyqtSignal()
isPrinterGroupChanged = pyqtSignal()
missingPackagesChanged = pyqtSignal()
isCompatibleMachineChanged = pyqtSignal()
hasVisibleSelectSameProfileChanged = pyqtSignal()
selectSameProfileCheckedChanged = pyqtSignal()
@pyqtProperty(bool, notify = isPrinterGroupChanged)
def isPrinterGroup(self) -> bool:
@ -292,6 +302,50 @@ class WorkspaceDialog(QObject):
@pyqtSlot(str)
def setMachineToOverride(self, machine_name: str) -> None:
self._override_machine = machine_name
self.updateCompatibleMachine()
def updateCompatibleMachine(self):
registry = ContainerRegistry.getInstance()
containers_expected = registry.findDefinitionContainers(name=self._machine_type)
containers_selected = registry.findContainerStacks(id=self._override_machine)
if len(containers_expected) == 1 and len(containers_selected) == 1:
new_compatible_machine = (containers_expected[0] == containers_selected[0].definition)
if new_compatible_machine != self._is_compatible_machine:
self._is_compatible_machine = new_compatible_machine
self.isCompatibleMachineChanged.emit()
@pyqtProperty(bool, notify = isCompatibleMachineChanged)
def isCompatibleMachine(self) -> bool:
return self._is_compatible_machine
def setHasVisibleSelectSameProfileChanged(self, has_visible_select_same_profile):
if has_visible_select_same_profile != self._has_visible_select_same_profile:
self._has_visible_select_same_profile = has_visible_select_same_profile
self.hasVisibleSelectSameProfileChanged.emit()
@pyqtProperty(bool, notify = hasVisibleSelectSameProfileChanged)
def hasVisibleSelectSameProfile(self):
return self._has_visible_select_same_profile
def setSelectSameProfileChecked(self, select_same_profile_checked):
if select_same_profile_checked != self._select_same_profile_checked:
self._select_same_profile_checked = select_same_profile_checked
self.selectSameProfileCheckedChanged.emit()
@pyqtProperty(bool, notify = selectSameProfileCheckedChanged, fset = setSelectSameProfileChecked)
def selectSameProfileChecked(self):
return self._select_same_profile_checked
def setAllowCreatemachine(self, allow_create_machine):
self._allow_create_machine = allow_create_machine
@pyqtProperty(bool, constant = True)
def allowCreateMachine(self):
return self._allow_create_machine
@pyqtProperty(QObject, constant = True)
def exportedSettingModel(self):
return self._exported_settings_model
@pyqtSlot()
def closeBackend(self) -> None:
@ -299,11 +353,6 @@ class WorkspaceDialog(QObject):
Application.getInstance().getBackend().close()
@pyqtSlot(bool)
def setDropToBuildPlateForModel(self, drop_to_buildplate: bool) -> None:
CuraApplication.getInstance().getWorkplaceDropToBuildplate(drop_to_buildplate)
def setMaterialConflict(self, material_conflict: bool) -> None:
if self._has_material_conflict != material_conflict:
self._has_material_conflict = material_conflict

View file

@ -6,7 +6,7 @@ import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import UM 1.5 as UM
import UM 1.6 as UM
import Cura 1.1 as Cura
UM.Dialog
@ -120,13 +120,17 @@ UM.Dialog
minDropDownWidth: machineSelector.width
buttons: [
Component
{
id: componentNewPrinter
Cura.SecondaryButton
{
id: createNewPrinter
text: catalog.i18nc("@button", "Create new")
fixedWidthMode: true
width: parent.width - leftPadding * 1.5
visible: manager.allowCreateMachine
onClicked:
{
toggleContent()
@ -136,7 +140,9 @@ UM.Dialog
manager.setIsNetworkedMachine(false)
}
}
]
}
buttons: manager.allowCreateMachine ? [componentNewPrinter.createObject()] : []
onSelectPrinter: function(machine)
{
@ -165,26 +171,71 @@ UM.Dialog
{
leftLabelText: catalog.i18nc("@action:label", "Name")
rightLabelText: manager.qualityName
visible: manager.isCompatibleMachine
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Intent")
rightLabelText: manager.intentName
visible: manager.isCompatibleMachine
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Not in profile")
rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
visible: manager.numUserSettings != 0
visible: manager.numUserSettings != 0 && manager.selectSameProfileChecked && manager.isCompatibleMachine
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Derivative from")
rightLabelText: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
visible: manager.numSettingsOverridenByQualityChanges != 0
visible: manager.numSettingsOverridenByQualityChanges != 0 && manager.selectSameProfileChecked && manager.isCompatibleMachine
}
WorkspaceRow
{
leftLabelText: catalog.i18nc("@action:label", "Specific settings")
rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.exportedSettingModel.rowCount()).arg(manager.exportedSettingModel.rowCount())
buttonText: tableViewSpecificSettings.shouldBeVisible ? catalog.i18nc("@action:button", "Hide settings") : catalog.i18nc("@action:button", "Show settings")
visible: !manager.selectSameProfileChecked || !manager.isCompatibleMachine
onButtonClicked: tableViewSpecificSettings.shouldBeVisible = !tableViewSpecificSettings.shouldBeVisible
}
Cura.TableView
{
id: tableViewSpecificSettings
width: parent.width - parent.leftPadding - UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("card").height
visible: shouldBeVisible && (!manager.selectSameProfileChecked || !manager.isCompatibleMachine)
property bool shouldBeVisible: false
columnHeaders:
[
catalog.i18nc("@title:column", "Applies on"),
catalog.i18nc("@title:column", "Setting"),
catalog.i18nc("@title:column", "Value")
]
model: UM.TableModel
{
id: tableModel
headers: ["category", "label", "value"]
rows: manager.exportedSettingModel.items
}
}
UM.CheckBox
{
text: catalog.i18nc("@action:checkbox", "Select the same profile")
onEnabledChanged: manager.selectSameProfileChecked = enabled
tooltip: enabled ? "" : catalog.i18nc("@tooltip", "You can use the same profile only if you have the same printer as the project was published with")
visible: manager.hasVisibleSelectSameProfile && manager.isCompatibleMachine
checked: manager.selectSameProfileChecked
onCheckedChanged: manager.selectSameProfileChecked = checked
}
}
@ -300,25 +351,6 @@ UM.Dialog
}
}
Row
{
id: dropToBuildPlate
width: parent.width
height: childrenRect.height
spacing: UM.Theme.getSize("default_margin").width
UM.CheckBox
{
id: checkDropModels
text: catalog.i18nc("@text:window", "Drop models to buildplate")
checked: UM.Preferences.getValue("physics/automatic_drop_down")
onCheckedChanged: manager.setDropToBuildPlateForModel(checked)
}
function reloadValue()
{
checkDropModels.checked = UM.Preferences.getValue("physics/automatic_drop_down")
}
}
Row
{
id: clearBuildPlateWarning
@ -441,7 +473,6 @@ UM.Dialog
materialSection.reloadValues()
profileSection.reloadValues()
printerSection.reloadValues()
dropToBuildPlate.reloadValue()
}
}
}

View file

@ -9,26 +9,38 @@ import QtQuick.Window 2.2
import UM 1.5 as UM
import Cura 1.1 as Cura
Row
RowLayout
{
id: root
property alias leftLabelText: leftLabel.text
property alias rightLabelText: rightLabel.text
property alias buttonText: button.text
signal buttonClicked
width: parent.width
height: visible ? childrenRect.height : 0
UM.Label
{
id: leftLabel
text: catalog.i18nc("@action:label", "Type")
width: Math.round(parent.width / 4)
Layout.preferredWidth: Math.round(parent.width / 4)
wrapMode: Text.WordWrap
}
UM.Label
{
id: rightLabel
text: manager.machineType
width: Math.round(parent.width / 3)
wrapMode: Text.WordWrap
}
Cura.TertiaryButton
{
id: button
visible: !text.isEmpty
Layout.maximumHeight: leftLabel.implicitHeight
Layout.fillWidth: true
onClicked: root.buttonClicked()
}
}

View file

@ -5,7 +5,7 @@ import QtQuick 2.10
import QtQuick.Controls 2.3
import UM 1.5 as UM
import UM 1.8 as UM
Item
@ -80,34 +80,13 @@ Item
sourceComponent: combobox
}
MouseArea
UM.HelpIcon
{
id: helpIconMouseArea
anchors.right: parent.right
anchors.verticalCenter: comboboxLabel.verticalCenter
width: childrenRect.width
height: childrenRect.height
hoverEnabled: true
UM.ColorImage
{
width: UM.Theme.getSize("section_icon").width
height: width
visible: comboboxTooltipText != ""
source: UM.Theme.getIcon("Help")
color: UM.Theme.getColor("text")
UM.ToolTip
{
text: comboboxTooltipText
visible: helpIconMouseArea.containsMouse
targetPoint: Qt.point(parent.x + Math.round(parent.width / 2), parent.y)
x: 0
y: parent.y + parent.height + UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("tooltip").width
}
}
text: comboboxTooltipText
visible: comboboxTooltipText != ""
}
}

View file

@ -0,0 +1,38 @@
# Copyright (c) 2024 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt6.QtCore import QObject, pyqtProperty, pyqtSignal
class SettingExport(QObject):
def __init__(self, id, name, value, selectable):
super().__init__()
self.id = id
self._name = name
self._value = value
self._selected = selectable
self._selectable = selectable
@pyqtProperty(str, constant=True)
def name(self):
return self._name
@pyqtProperty(str, constant=True)
def value(self):
return self._value
selectedChanged = pyqtSignal(bool)
def setSelected(self, selected):
if selected != self._selected:
self._selected = selected
self.selectedChanged.emit(self._selected)
@pyqtProperty(bool, fset = setSelected, notify = selectedChanged)
def selected(self):
return self._selected
@pyqtProperty(bool, constant=True)
def selectable(self):
return self._selectable

View file

@ -0,0 +1,38 @@
// Copyright (c) 2024 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import UM 1.8 as UM
import Cura 1.1 as Cura
RowLayout
{
id: settingSelection
UM.CheckBox
{
text: modelData.name
Layout.preferredWidth: UM.Theme.getSize("setting").width
checked: modelData.selected
onClicked: modelData.selected = checked
enabled: modelData.selectable
}
UM.Label
{
text: modelData.value
}
UM.HelpIcon
{
UM.I18nCatalog { id: catalog; name: "cura" }
text: catalog.i18nc("@tooltip",
"This setting can't be exported because it depends on the used printer capacities")
visible: !modelData.selectable
}
}

View file

@ -0,0 +1,49 @@
# Copyright (c) 2024 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from enum import IntEnum
from PyQt6.QtCore import QObject, pyqtProperty, pyqtEnum
class SettingsExportGroup(QObject):
@pyqtEnum
class Category(IntEnum):
Global = 0
Extruder = 1
Model = 2
def __init__(self, stack, name, category, settings, category_details = '', extruder_index = 0, extruder_color = ''):
super().__init__()
self.stack = stack
self._name = name
self._settings = settings
self._category = category
self._category_details = category_details
self._extruder_index = extruder_index
self._extruder_color = extruder_color
@pyqtProperty(str, constant=True)
def name(self):
return self._name
@pyqtProperty(list, constant=True)
def settings(self):
return self._settings
@pyqtProperty(int, constant=True)
def category(self):
return self._category
@pyqtProperty(str, constant=True)
def category_details(self):
return self._category_details
@pyqtProperty(int, constant=True)
def extruder_index(self):
return self._extruder_index
@pyqtProperty(str, constant=True)
def extruder_color(self):
return self._extruder_color

View file

@ -0,0 +1,130 @@
# Copyright (c) 2024 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from dataclasses import asdict
from typing import Optional, cast, List, Dict, Pattern, Set
from PyQt6.QtCore import QObject, pyqtProperty
from UM.Settings.SettingDefinition import SettingDefinition
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
from cura.CuraApplication import CuraApplication
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.GlobalStack import GlobalStack
from .SettingsExportGroup import SettingsExportGroup
from .SettingExport import SettingExport
class SettingsExportModel(QObject):
EXPORTABLE_SETTINGS = {'infill_sparse_density',
'adhesion_type',
'support_enable',
'infill_pattern',
'support_type',
'support_structure',
'support_angle',
'support_infill_rate',
'ironing_enabled',
'fill_outline_gaps',
'coasting_enable',
'skin_monotonic',
'z_seam_position',
'infill_before_walls',
'ironing_only_highest_layer',
'xy_offset',
'adaptive_layer_height_enabled',
'brim_gap',
'support_offset',
'brim_outside_only',
'magic_spiralize',
'slicing_tolerance',
'outer_inset_first',
'magic_fuzzy_skin_outside_only',
'conical_overhang_enabled',
'min_infill_area',
'small_hole_max_size',
'magic_mesh_surface_mode',
'carve_multiple_volumes',
'meshfix_union_all_remove_holes',
'support_tree_rest_preference',
'small_feature_max_length',
'draft_shield_enabled',
'brim_smart_ordering',
'ooze_shield_enabled',
'bottom_skin_preshrink',
'skin_edge_support_thickness',
'alternate_carve_order',
'top_skin_preshrink',
'interlocking_enable'}
def __init__(self, parent = None):
super().__init__(parent)
self._settings_groups = []
application = CuraApplication.getInstance()
# Display global settings
global_stack = application.getGlobalContainerStack()
self._settings_groups.append(SettingsExportGroup(global_stack,
"Global settings",
SettingsExportGroup.Category.Global,
self._exportSettings(global_stack)))
# Display per-extruder settings
extruders_stacks = ExtruderManager.getInstance().getUsedExtruderStacks()
for extruder_stack in extruders_stacks:
color = ""
if extruder_stack.material:
color = extruder_stack.material.getMetaDataEntry("color_code")
self._settings_groups.append(SettingsExportGroup(extruder_stack,
"Extruder settings",
SettingsExportGroup.Category.Extruder,
self._exportSettings(extruder_stack),
extruder_index=extruder_stack.position,
extruder_color=color))
# Display per-model settings
scene_root = application.getController().getScene().getRoot()
for scene_node in scene_root.getChildren():
per_model_stack = scene_node.callDecoration("getStack")
if per_model_stack is not None:
self._settings_groups.append(SettingsExportGroup(per_model_stack,
"Model settings",
SettingsExportGroup.Category.Model,
self._exportSettings(per_model_stack),
scene_node.getName()))
@pyqtProperty(list, constant=True)
def settingsGroups(self) -> List[SettingsExportGroup]:
return self._settings_groups
@staticmethod
def _exportSettings(settings_stack):
user_settings_container = settings_stack.userChanges
user_keys = user_settings_container.getAllKeys()
settings_export = []
for setting_to_export in user_keys:
label = settings_stack.getProperty(setting_to_export, "label")
value = settings_stack.getProperty(setting_to_export, "value")
unit = settings_stack.getProperty(setting_to_export, "unit")
setting_type = settings_stack.getProperty(setting_to_export, "type")
if setting_type is not None:
# This is not very good looking, but will do for now
value = f"{str(SettingDefinition.settingValueToString(setting_type, value))} {unit}"
else:
value = str(value)
settings_export.append(SettingExport(setting_to_export,
label,
value,
setting_to_export in SettingsExportModel.EXPORTABLE_SETTINGS))
return settings_export

View file

@ -0,0 +1,87 @@
// Copyright (c) 2024 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import UM 1.5 as UM
import Cura 1.1 as Cura
import ThreeMFWriter 1.0 as ThreeMFWriter
ColumnLayout
{
id: settingsGroup
spacing: UM.Theme.getSize("narrow_margin").width
RowLayout
{
id: settingsGroupTitleRow
spacing: UM.Theme.getSize("default_margin").width
Item
{
id: icon
height: UM.Theme.getSize("medium_button_icon").height
width: height
UM.ColorImage
{
id: settingsMainImage
anchors.fill: parent
source:
{
switch(modelData.category)
{
case ThreeMFWriter.SettingsExportGroup.Global:
return UM.Theme.getIcon("Sliders")
case ThreeMFWriter.SettingsExportGroup.Model:
return UM.Theme.getIcon("View3D")
default:
return ""
}
}
color: UM.Theme.getColor("text")
}
Cura.ExtruderIcon
{
id: settingsExtruderIcon
anchors.fill: parent
visible: modelData.category === ThreeMFWriter.SettingsExportGroup.Extruder
text: (modelData.extruder_index + 1).toString()
font: UM.Theme.getFont("tiny_emphasis")
materialColor: modelData.extruder_color
}
}
UM.Label
{
id: settingsTitle
text: modelData.name + (modelData.category_details ? ' (%1)'.arg(modelData.category_details) : '')
font: UM.Theme.getFont("default_bold")
}
}
ListView
{
id: settingsExportList
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
spacing: 0
model: modelData.settings
visible: modelData.settings.length > 0
delegate: SettingSelection { }
}
UM.Label
{
UM.I18nCatalog { id: catalog; name: "cura" }
text: catalog.i18nc("@label", "No specific value has been set")
visible: modelData.settings.length === 0
}
}

View file

@ -1,9 +1,13 @@
# Copyright (c) 2020 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
import configparser
from io import StringIO
from threading import Lock
import zipfile
from typing import Dict, Any
from UM.Application import Application
from UM.Logger import Logger
@ -13,15 +17,23 @@ from UM.Workspace.WorkspaceWriter import WorkspaceWriter
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
from cura.Utils.Threading import call_on_qt_thread
from .ThreeMFWriter import ThreeMFWriter
from .SettingsExportModel import SettingsExportModel
from .SettingsExportGroup import SettingsExportGroup
USER_SETTINGS_PATH = "Cura/user-settings.json"
class ThreeMFWorkspaceWriter(WorkspaceWriter):
def __init__(self):
super().__init__()
self._ucp_model: Optional[SettingsExportModel] = None
@call_on_qt_thread
def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode):
def setExportModel(self, model: SettingsExportModel) -> None:
if self._ucp_model != model:
self._ucp_model = model
def _write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode):
application = Application.getInstance()
machine_manager = application.getMachineManager()
@ -34,20 +46,20 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
global_stack = machine_manager.activeMachine
if global_stack is None:
self.setInformation(catalog.i18nc("@error", "There is no workspace yet to write. Please add a printer first."))
self.setInformation(
catalog.i18nc("@error", "There is no workspace yet to write. Please add a printer first."))
Logger.error("Tried to write a 3MF workspace before there was a global stack.")
return False
# Indicate that the 3mf mesh writer should not close the archive just yet (we still need to add stuff to it).
mesh_writer.setStoreArchive(True)
if not mesh_writer.write(stream, nodes, mode):
if not mesh_writer.write(stream, nodes, mode, self._ucp_model):
self.setInformation(mesh_writer.getInformation())
return False
archive = mesh_writer.getArchive()
if archive is None: # This happens if there was no mesh data to write.
archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED)
archive = zipfile.ZipFile(stream, "w", compression=zipfile.ZIP_DEFLATED)
try:
# Add global container stack data to the archive.
@ -62,15 +74,21 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
self._writeContainerToArchive(extruder_stack, archive)
for container in extruder_stack.getContainers():
self._writeContainerToArchive(container, archive)
# Write user settings data
if self._ucp_model is not None:
user_settings_data = self._getUserSettings(self._ucp_model)
ThreeMFWriter._storeMetadataJson(user_settings_data, archive, USER_SETTINGS_PATH)
except PermissionError:
self.setInformation(catalog.i18nc("@error:zip", "No permission to write the workspace here."))
Logger.error("No permission to write workspace to this stream.")
return False
# Write preferences to archive
original_preferences = Application.getInstance().getPreferences() #Copy only the preferences that we use to the workspace.
original_preferences = Application.getInstance().getPreferences() # Copy only the preferences that we use to the workspace.
temp_preferences = Preferences()
for preference in {"general/visible_settings", "cura/active_mode", "cura/categories_expanded", "metadata/setting_version"}:
for preference in {"general/visible_settings", "cura/active_mode", "cura/categories_expanded",
"metadata/setting_version"}:
temp_preferences.addPreference(preference, None)
temp_preferences.setValue(preference, original_preferences.getValue(preference))
preferences_string = StringIO()
@ -81,7 +99,7 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
# Save Cura version
version_file = zipfile.ZipInfo("Cura/version.ini")
version_config_parser = configparser.ConfigParser(interpolation = None)
version_config_parser = configparser.ConfigParser(interpolation=None)
version_config_parser.add_section("versions")
version_config_parser.set("versions", "cura_version", application.getVersion())
version_config_parser.set("versions", "build_type", application.getBuildType())
@ -101,11 +119,17 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
return False
except EnvironmentError as e:
self.setInformation(catalog.i18nc("@error:zip", str(e)))
Logger.error("EnvironmentError when writing workspace to this stream: {err}".format(err = str(e)))
Logger.error("EnvironmentError when writing workspace to this stream: {err}".format(err=str(e)))
return False
mesh_writer.setStoreArchive(False)
return True
def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode):
success = self._write(stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode)
self._ucp_model = None
return success
@staticmethod
def _writePluginMetadataToArchive(archive: zipfile.ZipFile) -> None:
file_name_template = "%s/plugin_metadata.json"
@ -165,4 +189,27 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
archive.writestr(file_in_archive, serialized_data)
except (FileNotFoundError, EnvironmentError):
Logger.error("File became inaccessible while writing to it: {archive_filename}".format(archive_filename = archive.fp.name))
return
return
@staticmethod
def _getUserSettings(model: SettingsExportModel) -> Dict[str, Dict[str, Any]]:
user_settings = {}
for group in model.settingsGroups:
category = ''
if group.category == SettingsExportGroup.Category.Global:
category = 'global'
elif group.category == SettingsExportGroup.Category.Extruder:
category = f"extruder_{group.extruder_index}"
if len(category) > 0:
settings_values = {}
stack = group.stack
for setting in group.settings:
if setting.selected:
settings_values[setting.id] = stack.getProperty(setting.id, "value")
user_settings[category] = settings_values
return user_settings

View file

@ -10,6 +10,9 @@ from UM.Math.Vector import Vector
from UM.Logger import Logger
from UM.Math.Matrix import Matrix
from UM.Application import Application
from UM.OutputDevice import OutputDeviceError
from UM.Message import Message
from UM.Resources import Resources
from UM.Scene.SceneNode import SceneNode
from UM.Settings.ContainerRegistry import ContainerRegistry
@ -20,10 +23,11 @@ from cura.Utils.Threading import call_on_qt_thread
from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.Snapshot import Snapshot
from PyQt6.QtCore import QBuffer
from PyQt6.QtCore import Qt, QBuffer
from PyQt6.QtGui import QImage, QPainter
import pySavitar as Savitar
from .UCPDialog import UCPDialog
import numpy
import datetime
@ -38,6 +42,9 @@ except ImportError:
import zipfile
import UM.Application
from .SettingsExportModel import SettingsExportModel
from .SettingsExportGroup import SettingsExportGroup
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -85,7 +92,9 @@ class ThreeMFWriter(MeshWriter):
self._store_archive = store_archive
@staticmethod
def _convertUMNodeToSavitarNode(um_node, transformation=Matrix()):
def _convertUMNodeToSavitarNode(um_node,
transformation = Matrix(),
exported_settings: Optional[Dict[str, Set[str]]] = None):
"""Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode
:returns: Uranium Scene node.
@ -127,16 +136,26 @@ class ThreeMFWriter(MeshWriter):
if stack is not None:
changed_setting_keys = stack.getTop().getAllKeys()
# Ensure that we save the extruder used for this object in a multi-extrusion setup
if stack.getProperty("machine_extruder_count", "value") > 1:
changed_setting_keys.add("extruder_nr")
if exported_settings is None:
# Ensure that we save the extruder used for this object in a multi-extrusion setup
if stack.getProperty("machine_extruder_count", "value") > 1:
changed_setting_keys.add("extruder_nr")
# Get values for all changed settings & save them.
for key in changed_setting_keys:
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
# Get values for all changed settings & save them.
for key in changed_setting_keys:
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
else:
# We want to export only the specified settings
if um_node.getName() in exported_settings:
model_exported_settings = exported_settings[um_node.getName()]
# Get values for all exported settings & save them.
for key in model_exported_settings:
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
if isinstance(um_node, CuraSceneNode):
savitar_node.setSetting("cura:print_order", str(um_node.printOrder))
savitar_node.setSetting("cura:drop_to_buildplate", str(um_node.isDropDownEnabled))
# Store the metadata.
for key, value in um_node.metadata.items():
@ -146,7 +165,8 @@ class ThreeMFWriter(MeshWriter):
# only save the nodes on the active build plate
if child_node.callDecoration("getBuildPlateNumber") != active_build_plate_nr:
continue
savitar_child_node = ThreeMFWriter._convertUMNodeToSavitarNode(child_node)
savitar_child_node = ThreeMFWriter._convertUMNodeToSavitarNode(child_node,
exported_settings = exported_settings)
if savitar_child_node is not None:
savitar_node.addChild(savitar_child_node)
@ -155,7 +175,24 @@ class ThreeMFWriter(MeshWriter):
def getArchive(self):
return self._archive
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode) -> bool:
def _addLogoToThumbnail(self, primary_image, logo_name):
# Load the icon png image
icon_image = QImage(Resources.getPath(Resources.Images, logo_name))
# Resize icon_image to be 1/4 of primary_image size
new_width = int(primary_image.width() / 4)
new_height = int(primary_image.height() / 4)
icon_image = icon_image.scaled(new_width, new_height, Qt.AspectRatioMode.KeepAspectRatio)
# Create a QPainter to draw on the image
painter = QPainter(primary_image)
# Draw the icon in the top-left corner (adjust coordinates as needed)
icon_position = (10, 10)
painter.drawImage(icon_position[0], icon_position[1], icon_image)
painter.end()
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode, export_settings_model = None) -> bool:
self._archive = None # Reset archive
archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED)
try:
@ -179,6 +216,10 @@ class ThreeMFWriter(MeshWriter):
# Attempt to add a thumbnail
snapshot = self._createSnapshot()
if snapshot:
if export_settings_model != None:
self._addLogoToThumbnail(snapshot, "cura-share.png")
elif export_settings_model == None and self._store_archive:
self._addLogoToThumbnail(snapshot, "cura-icon.png")
thumbnail_buffer = QBuffer()
thumbnail_buffer.open(QBuffer.OpenModeFlag.ReadWrite)
snapshot.save(thumbnail_buffer, "PNG")
@ -233,14 +274,20 @@ class ThreeMFWriter(MeshWriter):
transformation_matrix.preMultiply(translation_matrix)
root_node = UM.Application.Application.getInstance().getController().getScene().getRoot()
exported_model_settings = ThreeMFWriter._extractModelExportedSettings(export_settings_model) if export_settings_model != None else None
for node in nodes:
if node == root_node:
for root_child in node.getChildren():
savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(root_child, transformation_matrix)
savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(root_child,
transformation_matrix,
exported_model_settings)
if savitar_node:
savitar_scene.addSceneNode(savitar_node)
else:
savitar_node = self._convertUMNodeToSavitarNode(node, transformation_matrix)
savitar_node = self._convertUMNodeToSavitarNode(node,
transformation_matrix,
exported_model_settings)
if savitar_node:
savitar_scene.addSceneNode(savitar_node)
@ -396,3 +443,59 @@ class ThreeMFWriter(MeshWriter):
parser = Savitar.ThreeMFParser()
scene_string = parser.sceneToString(savitar_scene)
return scene_string
@staticmethod
def _extractModelExportedSettings(model: Optional[SettingsExportModel]) -> Dict[str, Set[str]]:
extra_settings = {}
if model is not None:
for group in model.settingsGroups:
if group.category == SettingsExportGroup.Category.Model:
exported_model_settings = set()
for exported_setting in group.settings:
if exported_setting.selected:
exported_model_settings.add(exported_setting.id)
extra_settings[group.category_details] = exported_model_settings
return extra_settings
def exportUcp(self):
preferences = CuraApplication.getInstance().getPreferences()
if preferences.getValue("cura/dialog_on_ucp_project_save"):
self._config_dialog = UCPDialog()
self._config_dialog.show()
else:
application = CuraApplication.getInstance()
workspace_handler = application.getInstance().getWorkspaceFileHandler()
# Set the model to the workspace writer
mesh_writer = workspace_handler.getWriter("3MFWriter")
mesh_writer.setExportModel(SettingsExportModel())
# Open file dialog and write the file
device = application.getOutputDeviceManager().getOutputDevice("local_file")
nodes = [application.getController().getScene().getRoot()]
file_name = CuraApplication.getInstance().getPrintInformation().baseName
try:
device.requestWrite(
nodes,
file_name,
["application/vnd.ms-package.3dmanufacturing-3dmodel+xml"],
workspace_handler,
preferred_mimetype_list="application/vnd.ms-package.3dmanufacturing-3dmodel+xml"
)
except OutputDeviceError.UserCanceledError:
self._onRejected()
except Exception as e:
message = Message(
catalog.i18nc("@info:error", "Unable to write to file: {0}", file_name),
title=catalog.i18nc("@info:title", "Error"),
message_type=Message.MessageType.ERROR
)
message.show()
Logger.logException("e", "Unable to write to file %s: %s", file_name, e)
self._onRejected()

View file

@ -0,0 +1,114 @@
# Copyright (c) 2024 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os
from PyQt6.QtCore import pyqtSignal, QObject
import UM
from UM.FlameProfiler import pyqtSlot
from UM.OutputDevice import OutputDeviceError
from UM.Workspace.WorkspaceWriter import WorkspaceWriter
from UM.i18n import i18nCatalog
from UM.Logger import Logger
from UM.Message import Message
from cura.CuraApplication import CuraApplication
from .SettingsExportModel import SettingsExportModel
i18n_catalog = i18nCatalog("cura")
class UCPDialog(QObject):
finished = pyqtSignal(bool)
def __init__(self, parent = None) -> None:
super().__init__(parent)
plugin_path = os.path.dirname(__file__)
dialog_path = os.path.join(plugin_path, 'UCPDialog.qml')
self._model = SettingsExportModel()
self._view = CuraApplication.getInstance().createQmlComponent(
dialog_path,
{
"manager": self,
"settingsExportModel": self._model
}
)
self._view.accepted.connect(self._onAccepted)
self._view.rejected.connect(self._onRejected)
self._finished = False
self._accepted = False
def show(self) -> None:
self._finished = False
self._accepted = False
self._view.show()
def getModel(self) -> SettingsExportModel:
return self._model
@pyqtSlot()
def notifyClosed(self):
self._onFinished()
def save3mf(self):
application = CuraApplication.getInstance()
workspace_handler = application.getInstance().getWorkspaceFileHandler()
# Set the model to the workspace writer
mesh_writer = workspace_handler.getWriter("3MFWriter")
mesh_writer.setExportModel(self._model)
# Open file dialog and write the file
device = application.getOutputDeviceManager().getOutputDevice("local_file")
nodes = [application.getController().getScene().getRoot()]
device.writeError.connect(lambda: self._onRejected())
device.writeSuccess.connect(lambda: self._onSuccess())
device.writeFinished.connect(lambda: self._onFinished())
file_name = CuraApplication.getInstance().getPrintInformation().baseName
try:
device.requestWrite(
nodes,
file_name,
["application/vnd.ms-package.3dmanufacturing-3dmodel+xml"],
workspace_handler,
preferred_mimetype_list="application/vnd.ms-package.3dmanufacturing-3dmodel+xml"
)
except OutputDeviceError.UserCanceledError:
self._onRejected()
except Exception as e:
message = Message(
i18n_catalog.i18nc("@info:error", "Unable to write to file: {0}", file_name),
title=i18n_catalog.i18nc("@info:title", "Error"),
message_type=Message.MessageType.ERROR
)
message.show()
Logger.logException("e", "Unable to write to file %s: %s", file_name, e)
self._onRejected()
def _onAccepted(self):
self.save3mf()
def _onRejected(self):
self._onFinished()
def _onSuccess(self):
self._accepted = True
self._onFinished()
def _onFinished(self):
# Make sure we don't send the finished signal twice, whatever happens
if self._finished:
return
self._finished = True
# Reset the model to the workspace writer
mesh_writer = CuraApplication.getInstance().getInstance().getWorkspaceFileHandler().getWriter("3MFWriter")
mesh_writer.setExportModel(None)
self.finished.emit(self._accepted)

View file

@ -0,0 +1,125 @@
// Copyright (c) 2024 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import QtQuick.Window 2.2
import UM 1.5 as UM
import Cura 1.1 as Cura
UM.Dialog
{
id: exportDialog
title: catalog.i18nc("@title:window", "Export Universal Cura Project")
margin: UM.Theme.getSize("default_margin").width
minimumWidth: UM.Theme.getSize("modal_window_minimum").width
minimumHeight: UM.Theme.getSize("modal_window_minimum").height
backgroundColor: UM.Theme.getColor("detail_background")
property bool dontShowAgain: false
function storeDontShowAgain()
{
UM.Preferences.setValue("cura/dialog_on_ucp_project_save", !dontShowAgainCheckbox.checked)
UM.Preferences.setValue("cura/asked_dialog_on_ucp_project_save", false)
}
onVisibleChanged:
{
if(visible && UM.Preferences.getValue("cura/asked_dialog_on_ucp_project_save"))
{
dontShowAgain = !UM.Preferences.getValue("cura/dialog_on_ucp_project_save")
}
}
headerComponent: Rectangle
{
height: childrenRect.height + 2 * UM.Theme.getSize("default_margin").height
color: UM.Theme.getColor("main_background")
ColumnLayout
{
id: headerColumn
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.rightMargin: anchors.leftMargin
UM.Label
{
id: titleLabel
text: catalog.i18nc("@action:title", "Summary - Universal Cura Project")
font: UM.Theme.getFont("large")
}
UM.Label
{
id: descriptionLabel
text: catalog.i18nc("@action:description", "When exporting a Universal Cura Project, all the models present on the build plate will be included with their current position, orientation and scale. You can also select which per-extruder or per-model settings should be included to ensure a proper printing of the batch, even on different printers.")
font: UM.Theme.getFont("default")
wrapMode: Text.Wrap
Layout.maximumWidth: headerColumn.width
}
}
}
Rectangle
{
anchors.fill: parent
color: UM.Theme.getColor("main_background")
UM.I18nCatalog { id: catalog; name: "cura" }
ListView
{
id: settingsExportList
anchors.fill: parent
anchors.margins: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("thick_margin").height
model: settingsExportModel.settingsGroups
clip: true
ScrollBar.vertical: UM.ScrollBar { id: verticalScrollBar }
delegate: SettingsSelectionGroup { Layout.margins: 0 }
}
}
leftButtons:
[
UM.CheckBox
{
id: dontShowAgainCheckbox
text: catalog.i18nc("@action:label", "Don't show project summary on save again")
checked: dontShowAgain
}
]
rightButtons:
[
Cura.TertiaryButton
{
text: catalog.i18nc("@action:button", "Cancel")
onClicked: reject()
},
Cura.PrimaryButton
{
text: catalog.i18nc("@action:button", "Save project")
onClicked: accept()
}
]
buttonSpacing: UM.Theme.getSize("wide_margin").width
onClosing:
{
storeDontShowAgain()
manager.notifyClosed()
}
onRejected: storeDontShowAgain()
onAccepted: storeDontShowAgain()
}

View file

@ -2,9 +2,12 @@
# Uranium is released under the terms of the LGPLv3 or higher.
import sys
from PyQt6.QtQml import qmlRegisterType
from UM.Logger import Logger
try:
from . import ThreeMFWriter
from .SettingsExportGroup import SettingsExportGroup
threemf_writer_was_imported = True
except ImportError:
Logger.log("w", "Could not import ThreeMFWriter; libSavitar may be missing")
@ -23,20 +26,24 @@ def getMetaData():
if threemf_writer_was_imported:
metaData["mesh_writer"] = {
"output": [{
"extension": "3mf",
"description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"),
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode
}]
"output": [
{
"extension": "3mf",
"description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"),
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode
}
]
}
metaData["workspace_writer"] = {
"output": [{
"extension": workspace_extension,
"description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"),
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
}]
"output": [
{
"extension": workspace_extension,
"description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"),
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
}
]
}
return metaData
@ -44,6 +51,8 @@ def getMetaData():
def register(app):
if "3MFWriter.ThreeMFWriter" in sys.modules:
qmlRegisterType(SettingsExportGroup, "ThreeMFWriter", 1, 0, "SettingsExportGroup")
return {"mesh_writer": ThreeMFWriter.ThreeMFWriter(),
"workspace_writer": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter()}
else:

View file

@ -2,7 +2,7 @@
"name": "3MF Writer",
"author": "Ultimaker B.V.",
"version": "1.0.1",
"description": "Provides support for writing 3MF files.",
"description": "Provides support for writing 3MF and UCP files.",
"api": 8,
"i18n-catalog": "cura"
}

View file

@ -181,7 +181,10 @@ class CuraEngineBackend(QObject, Backend):
application.getPreferences().preferenceChanged.connect(self._onPreferencesChanged)
self._slicing_error_message = Message(
text = catalog.i18nc("@message", "Slicing failed with an unexpected error. Please consider reporting a bug on our issue tracker."),
text = catalog.i18nc("@message", "Oops! We encountered an unexpected error during your slicing process. "
"Rest assured, we've automatically received the crash logs for analysis, "
"if you have not disabled data sharing in your preferences. To assist us "
"further, consider sharing your project details on our issue tracker."),
title = catalog.i18nc("@message:title", "Slicing failed"),
message_type = Message.MessageType.ERROR
)

View file

@ -68,7 +68,7 @@
"meshfix_keep_open_polygons": "fix_horrible_use_open_bits",
"magic_mesh_surface_mode": "\"surface\" if simple_mode else \"normal\"",
"magic_spiralize": "spiralize",
"prime_tower_mode": "\"normal\" if wipe_tower else \"none\"",
"prime_tower_enable": "wipe_tower",
"prime_tower_size": "math.sqrt(float(wipe_tower_volume) / float(layer_height))",
"ooze_shield_enabled": "ooze_shield",
"skin_overlap": "fill_overlap"

View file

@ -263,6 +263,7 @@ class SliceInfo(QObject, Extension):
print_settings["retraction_enable"] = global_stack.getProperty("retraction_enable", "value")
# Prime tower settings
print_settings["prime_tower_enable"] = global_stack.getProperty("prime_tower_enable", "value")
print_settings["prime_tower_mode"] = global_stack.getProperty("prime_tower_mode", "value")
# Infill settings

View file

@ -42,7 +42,7 @@
"machine_max_jerk_xy": { "value": 10 },
"machine_max_jerk_z": { "value": 2 },
"machine_name": { "default_value": "Anycubic Kobra 2" },
"machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ; use absolute coordinates\nM82 ; use absolute distances for extrusion\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 ; home all axes\nM300 S1318 P266\nG1 Z5 F5000 ; lift nozzle\nG1 X5 Y0 F3000\nG1 Z0.3 ; set nozzle height\nG92 E0\nG1 X50 Y0 E20 F500 ; Extrude 20mm of filament in a 5cm line \nG92 E0 ; zero the extruded length again \nG1 E-4.5 F4800 ; Retract a little \nG92 E0\nG1 X120 F4000 ; Quickly wipe away from the filament line\nM117 ; Printing\u2026\nG5" },
"machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ; use absolute coordinates\nM82 ; use absolute distances for extrusion\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\nG28 ; home all axes\nM300 S1318 P266\nG1 Z5 F5000 ; lift nozzle\nG1 X5 Y0 F3000\nG1 Z0.3 ; set nozzle height\nG92 E0\nG1 X50 Y0 E20 F500 ; Extrude 20mm of filament in a 5cm line \nG92 E0 ; zero the extruded length again \nG1 E-4.5 F4800 ; Retract a little \nG92 E0\nG1 X120 F4000 ; Quickly wipe away from the filament line\nM117 ; Printing\u2026\nG5" },
"machine_width": { "default_value": 220 },
"material_bed_temperature": { "maximum_value_warning": 110 },
"material_bed_temperature_layer_0": { "maximum_value_warning": 110 },

View file

@ -23,7 +23,7 @@
"machine_heated_bed": { "default_value": true },
"machine_height": { "default_value": 250 },
"machine_name": { "default_value": "Anycubic Kobra Go" },
"machine_start_gcode": { "default_value": "M140 S[first_layer_bed_temperature]; Heat bed\nM104 S[first_layer_temperature\n ]; Heat extruder\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nG28 ; Home all axes\nG92 E0 ; Reset Extruder\nM420 S1 ; Enable Bed Levelling Mesh\nM190 S[first_layer_bed_temperature\n ]; Wait for bed to get up to temperature\nM109 S[first_layer_temperature\n ]; Wait for extruder to get up to temperature\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X2 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X2 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X2.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X2.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 F2400 E-1\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish" },
"machine_start_gcode": { "default_value": "M140 S{material_bed_temperature_layer_0}; Heat bed\nM104 S{material_print_temperature_layer_0}; Heat extruder\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nG28 ; Home all axes\nG92 E0 ; Reset Extruder\nM420 S1 ; Enable Bed Levelling Mesh\nM190 S{material_bed_temperature_layer_0}; Wait for bed to get up to temperature\nM109 S{material_print_temperature_layer_0}; Wait for extruder to get up to temperature\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X2 Y20 Z0.3 F5000.0 ; Move to start position\nG1 X2 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line\nG1 X2.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X2.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 F2400 E-1\nG1 X5 Y20 Z0.3 F5000.0 ; Move over to prevent blob squish" },
"machine_width": { "default_value": 222 }
}
}

View file

@ -110,7 +110,7 @@
"min_infill_area": { "value": "5.0" },
"minimum_polygon_circumference": { "value": "0.2" },
"optimize_wall_printing_order": { "value": "True" },
"prime_tower_mode": { "value": "normal" },
"prime_tower_enable": { "value": "True" },
"retraction_amount": { "value": "1" },
"retraction_combing": { "value": "'noskin'" },
"retraction_combing_max_distance": { "value": "10" },

View file

@ -45,7 +45,7 @@
"machine_max_feedrate_y": { "value": 500 },
"machine_max_feedrate_z": { "value": 30 },
"machine_name": { "default_value": "Creality Ender-3 V3 SE" },
"machine_start_gcode": { "default_value": "M220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\n\nG28 ;Home\n\nM420 S1; Enable mesh leveling\n\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM109 S[material_print_temperature_layer_0]\nG1 X10.1 Y145.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y145.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 E-1.0000 F1800 ;Retract a bit\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 E0.0000 F1800 \n" },
"machine_start_gcode": { "default_value": "M220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\n\nG28 ;Home\n\nM420 S1; Use saved mesh leveling data\n\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nM190 S{material_bed_temperature_layer_0} ; Set bed temperature and wait\nM109 S{material_print_temperature_layer_0} ; Set hotend temperature and wait\nG1 X10.1 Y145.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y145.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 E-1.0000 F1800 ;Retract a bit\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 E0.0000 F1800 \n" },
"machine_width": { "default_value": 220 },
"retraction_amount": { "value": 0.8 },
"retraction_speed": { "default_value": 40 },

View file

@ -23,7 +23,7 @@
},
"machine_height": { "default_value": 400 },
"machine_name": { "default_value": "Creality Ender-5 Plus" },
"machine_start_gcode": { "default_value": "M201 X500.00 Y500.00 Z100.00 E5000.00 ;Setup machine max acceleration\nM203 X500.00 Y500.00 Z10.00 E50.00 ;Setup machine max feedrate\nM204 P500.00 R1000.00 T500.00 ;Setup Print/Retract/Travel acceleration\nM205 X8.00 Y8.00 Z0.40 E5.00 ;Setup Jerk\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\n\nG28 ;Home\nM420 S1 Z2 ;Enable ABL using saved Mesh and Fade Height\n\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\n" },
"machine_start_gcode": { "default_value": "M201 X500.00 Y500.00 Z100.00 E5000.00 ;Setup machine max acceleration\nM203 X500.00 Y500.00 Z10.00 E50.00 ;Setup machine max feedrate\nM204 P500.00 R1000.00 T500.00 ;Setup Print/Retract/Travel acceleration\nM205 X8.00 Y8.00 Z0.40 E5.00 ;Setup Jerk\nM220 S100 ;Reset Feedrate\nM221 S100 ;Reset Flowrate\n\nG28 ;Home\nG29 ;Auto bed level\n\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\nG1 X10.1 Y20 Z0.28 F5000.0 ;Move to start position\nG1 X10.1 Y200.0 Z0.28 F1500.0 E15 ;Draw the first line\nG1 X10.4 Y200.0 Z0.28 F5000.0 ;Move to side a little\nG1 X10.4 Y20 Z0.28 F1500.0 E30 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up\n" },
"machine_width": { "default_value": 350 },
"speed_print": { "value": 80.0 }
}

View file

@ -31,8 +31,8 @@
"material_final_print_temperature": { "value": "material_print_temperature" },
"material_initial_print_temperature": { "value": "material_print_temperature" },
"material_standby_temperature": { "value": "material_print_temperature" },
"prime_tower_enable": { "value": true },
"prime_tower_min_volume": { "value": "50" },
"prime_tower_mode": { "value": "normal" },
"switch_extruder_retraction_amount": { "value": "0" }
}
}

View file

@ -31,8 +31,8 @@
"material_final_print_temperature": { "value": "material_print_temperature" },
"material_initial_print_temperature": { "value": "material_print_temperature" },
"material_standby_temperature": { "value": "material_print_temperature" },
"prime_tower_enable": { "value": true },
"prime_tower_min_volume": { "value": "50" },
"prime_tower_mode": { "value": "normal" },
"switch_extruder_retraction_amount": { "value": "0" }
}
}

View file

@ -31,8 +31,8 @@
"material_final_print_temperature": { "value": "material_print_temperature" },
"material_initial_print_temperature": { "value": "material_print_temperature" },
"material_standby_temperature": { "value": "material_print_temperature" },
"prime_tower_enable": { "value": "True" },
"prime_tower_min_volume": { "value": "50" },
"prime_tower_mode": { "value": "normal" },
"switch_extruder_retraction_amount": { "value": "0" }
}
}

View file

@ -5,6 +5,7 @@
"overrides":
{
"machine_end_gcode": { "value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"G90 ;absolute positioning\\nM104 S0 T0 ;extruder heater off\\nM104 S0 T1\\nM140 S0 ;turn off bed\\nT0 ; move to the first head\\nM107 ;fan off\"" },
"machine_start_gcode": { "value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \";material_bed_temperature={material_bed_temperature} material_print_temperature={material_print_temperature} material_print_temperature_layer_0={material_print_temperature_layer_0}\\nM190 S{material_bed_temperature_layer_0}\\nM104 T0 S{material_standby_temperature, 0}\\nM104 T0 S{material_print_temperature_layer_0, 0}\\nG21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nM200 D0 T0 ;reset filament diameter\\nM200 D0 T1\\nG28 ;home all\\nT1 ; move to the nozzle 2\\nG0 Z20 F2400 ;move the platform to 30mm\\nM109 T1 S{material_print_temperature_layer_0, 1}\\nG0 X210 Y20 F7200\\nG92 E0\\nG92 E-7.0 ;prime distance\\nG1 E0 F45 ;purge nozzle\\nG1 E-6.5 F1500 ; retract\\nT0 ; move to the nozzle 1\\nM104 T1 S{material_standby_temperature, 1}\\nG0 Z20 F2400\\nM109 T0 S{material_print_temperature_layer_0, 0}\\nG0 X210 Y20 F7200\\nG92 E0\\nG92 E-7.0\\nG1 E0 F45 ;purge nozzle\\nG1 E-6.5 F1500\\nM104 T0 S{material_standby_temperature, 0}\\nT{initial_extruder_nr} ;switch to the first nozzle used for print\\nM109 T{initial_extruder_nr} S{material_print_temperature_layer_0, initial_extruder_nr}\\nM400 ;finish all moves\\nG1 E0 F1500\\nG92 E0\\n;end of startup sequence\\n\"" }
"machine_start_gcode": { "value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \";material_bed_temperature={material_bed_temperature} material_print_temperature={material_print_temperature} material_print_temperature_layer_0={material_print_temperature_layer_0}\\nM190 S{material_bed_temperature_layer_0}\\nM104 T0 S{material_standby_temperature, 0}\\nM104 T0 S{material_print_temperature_layer_0, 0}\\nG21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nM200 D0 T0 ;reset filament diameter\\nM200 D0 T1\\nG28 ;home all\\nT1 ; move to the nozzle 2\\nG0 Z20 F2400 ;move the platform to 30mm\\nM109 T1 S{material_print_temperature_layer_0, 1}\\nG0 X210 Y20 F7200\\nG92 E0\\nG92 E-7.0 ;prime distance\\nG1 E0 F45 ;purge nozzle\\nG1 E-6.5 F1500 ; retract\\nT0 ; move to the nozzle 1\\nM104 T1 S{material_standby_temperature, 1}\\nG0 Z20 F2400\\nM109 T0 S{material_print_temperature_layer_0, 0}\\nG0 X210 Y20 F7200\\nG92 E0\\nG92 E-7.0\\nG1 E0 F45 ;purge nozzle\\nG1 E-6.5 F1500\\nM104 T0 S{material_standby_temperature, 0}\\nT{initial_extruder_nr} ;switch to the first nozzle used for print\\nM109 T{initial_extruder_nr} S{material_print_temperature_layer_0, initial_extruder_nr}\\nM400 ;finish all moves\\nG1 E0 F1500\\nG92 E0\\n;end of startup sequence\\n\"" },
"prime_tower_enable": { "default_value": true }
}
}

View file

@ -55,6 +55,7 @@
"settable_per_extruder": false
},
"prime_blob_enable": { "default_value": false },
"prime_tower_enable": { "default_value": true },
"prime_tower_min_volume": { "default_value": 90 },
"prime_tower_size": { "default_value": 30 },
"raft_airgap": { "default_value": 0.25 },

View file

@ -979,7 +979,7 @@
"description": "Width of a single prime tower line.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"default_value": 0.4,
"value": "line_width",
"minimum_value": "0.001",
@ -3363,7 +3363,7 @@
"description": "The speed at which the prime tower is printed. Printing the prime tower slower can make it more stable when the adhesion between the different filaments is suboptimal.",
"type": "float",
"unit": "mm/s",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"default_value": 60,
"value": "speed_print",
"minimum_value": "0.1",
@ -3741,7 +3741,7 @@
"maximum_value_warning": "10000",
"default_value": 3000,
"value": "acceleration_print",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and resolveOrValue('acceleration_enabled')",
"enabled": "prime_tower_enable and resolveOrValue('acceleration_enabled')",
"settable_per_mesh": false
}
}
@ -4060,7 +4060,7 @@
"maximum_value_warning": "50",
"default_value": 20,
"value": "jerk_print",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and resolveOrValue('jerk_enabled')",
"enabled": "prime_tower_enable and resolveOrValue('jerk_enabled')",
"settable_per_mesh": false
}
}
@ -6794,20 +6794,30 @@
"description": "Settings used for printing with multiple extruders.",
"children":
{
"prime_tower_enable":
{
"label": "Enable Prime Tower",
"description": "Print a tower next to the print which serves to prime the material after each nozzle switch.",
"type": "bool",
"enabled": "extruders_enabled_count > 1",
"default_value": false,
"resolve": "(extruders_enabled_count > 1) and any(extruderValues('prime_tower_enable'))",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"prime_tower_mode":
{
"label": "Prime Tower",
"description": "<html>Print a tower next to the model, which serves to prime the material after each nozzle switch.<ul><li><b>None:</b> do not generate a prime tower</li><li><b>Normal:</b> generate a bucket in which secondary materials are primed</li><li><b>Interleaved:</b> generate a prime tower as sparse as possible. This will save time and filament, but is only possible if the used materials adhere to each other.</li></ul></html>",
"label": "Prime Tower Type",
"description": "<html>How to generate the prime tower:<ul><li><b>Normal:</b> create a bucket in which secondary materials are primed</li><li><b>Interleaved:</b> create a prime tower as sparse as possible. This will save time and filament, but is only possible if the used materials adhere to each other.</li></ul></html>",
"type": "enum",
"value": "'none' if (extruders_enabled_count < 2) else ('interleaved' if (all(material_type_var == extruderValues('material_type')[0] for material_type_var in extruderValues('material_type')) and all(material_brand_var == extruderValues('material_brand')[0] for material_brand_var in extruderValues('material_brand'))) else 'normal')",
"value": "'interleaved' if (all(material_type_var == extruderValues('material_type')[0] for material_type_var in extruderValues('material_type')) and all(material_brand_var == extruderValues('material_brand')[0] for material_brand_var in extruderValues('material_brand'))) else 'normal'",
"options":
{
"none": "None",
"normal": "Normal",
"interleaved": "Interleaved"
},
"default_value": "none",
"enabled": "extruders_enabled_count > 1",
"default_value": "normal",
"enabled": "prime_tower_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
},
@ -6817,7 +6827,7 @@
"description": "The width of the prime tower.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"default_value": 20,
"resolve": "max(extruderValues('prime_tower_size'))",
"minimum_value": "0",
@ -6836,7 +6846,7 @@
"default_value": 6,
"minimum_value": "0",
"maximum_value_warning": "(resolveOrValue('prime_tower_size') * 0.5) ** 2 * 3.14159 * resolveOrValue('layer_height') - sum(extruderValues('prime_tower_min_volume')) + prime_tower_min_volume",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -6849,7 +6859,7 @@
"default_value": 5,
"minimum_value": "line_width",
"maximum_value_warning": "10.0",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -6859,9 +6869,9 @@
"description": "The x coordinate of the position of the prime tower.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"default_value": 200,
"value": "(resolveOrValue('machine_width') / 2 + resolveOrValue('prime_tower_size') / 2) if resolveOrValue('machine_shape') == 'elliptic' else (resolveOrValue('machine_width') - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('machine_nozzle_offset_x')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_x'))), 1)) - (resolveOrValue('machine_width') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"value": "((resolveOrValue('machine_width') / 2 + resolveOrValue('prime_tower_size') / 2) if resolveOrValue('machine_shape') == 'elliptic' else (resolveOrValue('machine_width') - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('machine_nozzle_offset_x')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_x'))), 1))) - (resolveOrValue('machine_width') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"maximum_value": "(machine_width / 2 if machine_center_is_zero else machine_width) - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0)",
"minimum_value": "resolveOrValue('prime_tower_size') + (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - (machine_width / 2 if machine_center_is_zero else 0)",
"settable_per_mesh": false,
@ -6873,7 +6883,7 @@
"description": "The y coordinate of the position of the prime tower.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"default_value": 200,
"value": "machine_depth - prime_tower_size - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0) - max(max(extruderValues('travel_avoid_distance')) + max(extruderValues('machine_nozzle_offset_y')) + max(extruderValues('support_offset')) + (extruderValue(skirt_brim_extruder_nr, 'skirt_brim_line_width') * extruderValue(skirt_brim_extruder_nr, 'skirt_line_count') * extruderValue(skirt_brim_extruder_nr, 'initial_layer_line_width_factor') / 100 + extruderValue(skirt_brim_extruder_nr, 'skirt_gap') if resolveOrValue('adhesion_type') == 'skirt' else 0) + (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0), max(map(abs, extruderValues('machine_nozzle_offset_y'))), 1) - (resolveOrValue('machine_depth') / 2 if resolveOrValue('machine_center_is_zero') else 0)",
"maximum_value": "(machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')) - (resolveOrValue('prime_tower_base_size') if (resolveOrValue('adhesion_type') == 'raft' or resolveOrValue('prime_tower_brim_enable')) else 0)",
@ -6886,7 +6896,7 @@
"label": "Wipe Inactive Nozzle on Prime Tower",
"description": "After printing the prime tower with one nozzle, wipe the oozed material from the other nozzle off on the prime tower.",
"type": "bool",
"enabled": "resolveOrValue('prime_tower_mode') != 'none'",
"enabled": "prime_tower_enable",
"default_value": true,
"settable_per_mesh": false,
"settable_per_extruder": true
@ -6897,7 +6907,7 @@
"label": "Prime Tower Base",
"description": "By enabling this setting, your prime-tower will get a brim, even if the model doesn't. If you want a sturdier base for a high tower, you can increase the base height.",
"type": "bool",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and resolveOrValue('adhesion_type') != 'raft'",
"enabled": "prime_tower_enable and resolveOrValue('adhesion_type') != 'raft'",
"default_value": false,
"settable_per_mesh": false,
"settable_per_extruder": false
@ -6909,7 +6919,7 @@
"description": "The width of the prime tower brim/base. A larger base enhances adhesion to the build plate, but also reduces the effective print area.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"enabled": "prime_tower_enable and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"default_value": 1.2,
"minimum_value": "0",
"maximum_value": "min(0.5 * machine_width, 0.5 * machine_depth)",
@ -6923,7 +6933,7 @@
"description": "The height of the prime tower base. Increasing this value will result in a more sturdy prime tower because the base will be wider. If this setting is too low, the prime tower will not have a sturdy base.",
"type": "float",
"unit": "mm",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"enabled": "prime_tower_enable and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"default_value": 0,
"minimum_value": "0",
"maximum_value": "machine_height",
@ -6935,7 +6945,7 @@
"label": "Prime Tower Base Slope",
"description": "The magnitude factor used for the slope of the prime tower base. If you increase this value, the base will become slimmer. If you decrease it, the base will become thicker.",
"type": "float",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"enabled": "prime_tower_enable and (resolveOrValue('prime_tower_brim_enable') or resolveOrValue('adhesion_type') == 'raft')",
"default_value": 4,
"minimum_value": "0",
"maximum_value": "10",
@ -6953,7 +6963,7 @@
"minimum_value": "0",
"minimum_value_warning": "raft_base_line_width",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('prime_tower_mode') != 'none' and resolveOrValue('adhesion_type') == 'raft'",
"enabled": "prime_tower_enable and resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
"limit_to_extruder": "raft_base_extruder_nr"

View file

@ -80,7 +80,7 @@
"material_final_print_temperature": { "value": "default_material_print_temperature" },
"material_initial_print_temperature": { "value": "default_material_print_temperature" },
"material_standby_temperature": { "enabled": false },
"prime_tower_mode": { "resolve": "'normal' if extruders_enabled_count > 1 else 'none'" },
"prime_tower_enable": { "resolve": "extruders_enabled_count > 1" },
"retraction_amount": { "default_value": 2 },
"retraction_combing": { "value": "'all'" },
"skirt_line_count": { "default_value": 3 },

View file

@ -44,8 +44,8 @@
"machine_width": { "default_value": 235 },
"meshfix_maximum_resolution": { "value": 0.25 },
"optimize_wall_printing_order": { "value": true },
"prime_tower_enable": { "value": true },
"prime_tower_min_volume": { "value": 30 },
"prime_tower_mode": { "value": "normal" },
"retract_at_layer_change": { "value": false },
"retraction_amount": { "value": 4.5 },
"roofing_layer_count": { "value": 1 },

View file

@ -8,7 +8,7 @@
"platform": "ratrig_vcore3_200.stl",
"platform_offset": [
0,
5,
0,
0
],
"weight": 16

View file

@ -11,7 +11,7 @@
"machine_extruder_trains": { "0": "ratrig_base_extruder_0" },
"platform_offset": [
0,
5,
0,
0
],
"preferred_variant_name": "0.4mm Nozzle",

View file

@ -112,6 +112,7 @@
"machine_use_extruder_offset_to_offset_coords": { "default_value": false },
"machine_width": { "default_value": 420 },
"material_diameter": { "default_value": 1.75 },
"prime_tower_enable": { "default_value": true },
"prime_tower_min_volume": { "default_value": 35.6 },
"raft_acceleration": { "value": "machine_acceleration" },
"raft_base_acceleration": { "value": "machine_acceleration" },

View file

@ -96,12 +96,9 @@
"raft_interface_thickness": { "value": "(raft_base_thickness + raft_surface_thickness) / 2" },
"raft_speed": { "value": 15 },
"raft_surface_fan_speed": { "value": "cool_fan_speed_min" },
"raft_surface_monotonic": { "value": true },
"raft_surface_speed": { "value": "speed_topbottom" },
"relative_extrusion":
{
"enabled": false,
"value": false
},
"relative_extrusion": { "enabled": false },
"retraction_combing": { "value": "'no_outer_surfaces'" },
"retraction_combing_max_distance": { "value": 15 },
"retraction_count_max": { "value": 25 },

View file

@ -149,6 +149,7 @@
"enabled": true,
"value": "resolveOrValue('print_sequence') != 'one_at_a_time'"
},
"prime_tower_enable": { "default_value": true },
"prime_tower_position_x": { "value": "185" },
"prime_tower_wipe_enabled": { "default_value": false },
"retraction_amount": { "value": "6.5" },

View file

@ -28,7 +28,6 @@
"generic_hips_175",
"generic_pc_175",
"ultimaker_rapidrinse_175",
"ultimaker_sr30_175",
"generic_tpu_175",
"goofoo_",
"ideagen3D_",
@ -346,9 +345,9 @@
"prime_tower_base_curve_magnitude": { "value": 2 },
"prime_tower_base_height": { "value": 6 },
"prime_tower_base_size": { "value": 10 },
"prime_tower_enable": { "value": false },
"prime_tower_flow": { "value": "material_flow" },
"prime_tower_line_width": { "value": 1 },
"prime_tower_mode": { "value": "none" },
"prime_tower_raft_base_line_spacing": { "value": "raft_base_line_width" },
"prime_tower_wipe_enabled": { "value": true },
"print_sequence": { "enabled": false },
@ -376,10 +375,8 @@
"retraction_prime_speed": { "value": "retraction_speed" },
"retraction_speed": { "value": 5 },
"roofing_layer_count": { "value": 2 },
"roofing_material_flow": { "value": "material_flow" },
"roofing_monotonic": { "value": true },
"skin_material_flow": { "value": "0.95*material_flow" },
"skin_monotonic": { "value": true },
"skin_outline_count": { "value": 0 },
"skin_overlap": { "value": 0 },
"skin_preshrink": { "value": 0 },

View file

@ -35,7 +35,6 @@
"generic_nylon_175",
"generic_hips_175",
"generic_pc_175",
"ultimaker_sr30_175",
"generic_tpu_175",
"goofoo_",
"ideagen3D_",

View file

@ -103,7 +103,7 @@
"default_value": false,
"enabled": true
},
"prime_tower_mode": { "value": "normal" },
"prime_tower_enable": { "value": "True" },
"retraction_amount": { "value": "6.5" },
"retraction_hop": { "value": "2" },
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },

View file

@ -104,7 +104,7 @@
"default_value": false,
"enabled": true
},
"prime_tower_mode": { "value": "normal" },
"prime_tower_enable": { "value": "True" },
"retraction_amount": { "value": "6.5" },
"retraction_combing": { "value": "'no_outer_surfaces'" },
"retraction_hop": { "value": "2" },

View file

@ -0,0 +1,16 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata":
{
"machine": "geeetech_A20",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodx
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_asa_175
quality_type = draft
setting_version = 22
type = intent
variant = 1C
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodx
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_nylon12-cf_175
quality_type = draft
setting_version = 22
type = intent
variant = 1C
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodx
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_asa_175
quality_type = draft
setting_version = 22
type = intent
variant = 1XA
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,17 @@
[general]
definition = ultimaker_methodx
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_sr30_175
quality_type = draft
setting_version = 22
type = intent
variant = 2XA
[values]
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodx
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_asa_175
quality_type = draft
setting_version = 22
type = intent
variant = LABS
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodx
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_nylon12-cf_175
quality_type = draft
setting_version = 22
type = intent
variant = LABS
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodxl
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_asa_175
quality_type = draft
setting_version = 22
type = intent
variant = 1C
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodxl
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_nylon12-cf_175
quality_type = draft
setting_version = 22
type = intent
variant = 1C
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodxl
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_asa_175
quality_type = draft
setting_version = 22
type = intent
variant = 1XA
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,17 @@
[general]
definition = ultimaker_methodxl
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_sr30_175
quality_type = draft
setting_version = 22
type = intent
variant = 2XA
[values]
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodxl
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_asa_175
quality_type = draft
setting_version = 22
type = intent
variant = LABS
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -0,0 +1,18 @@
[general]
definition = ultimaker_methodxl
name = Solid
version = 4
[metadata]
intent_category = solid
is_experimental = True
material = ultimaker_nylon12-cf_175
quality_type = draft
setting_version = 22
type = intent
variant = LABS
[values]
infill_pattern = lines
infill_sparse_density = 100

View file

@ -39,7 +39,7 @@ Item
property alias printObjectAfterNext: printObjectAfterNextAction
property alias multiplyObject: multiplyObjectAction
property alias dropAll: dropAllAction
property alias selectAll: selectAllAction
property alias deleteAll: deleteAllAction
property alias reloadAll: reloadAllAction
@ -490,6 +490,14 @@ Item
shortcut: "Shift+Ctrl+R"
}
Action
{
id: dropAllAction
text: catalog.i18nc("@action:inmenu menubar:edit","Drop All Models to buildplate")
shortcut: "Ctrl+B"
onTriggered: CuraApplication.setWorkplaceDropToBuildplate()
}
Action
{
id: resetAllTranslationAction

View file

@ -25,7 +25,7 @@ UM.Dialog
function storeDontShowAgain()
{
UM.Preferences.setValue("cura/dialog_on_project_save", !dontShowAgainCheckbox.checked)
UM.Preferences.setValue("asked_dialog_on_project_save", true)
UM.Preferences.setValue("cura/asked_dialog_on_project_save", true)
}
onClosing: storeDontShowAgain()

View file

@ -15,6 +15,7 @@ Item
property int iconSize: UM.Theme.getSize("extruder_icon").width
property string iconVariant: "medium"
property alias font: extruderNumberText.font
property alias text: extruderNumberText.text
implicitWidth: iconSize
implicitHeight: iconSize

View file

@ -71,6 +71,7 @@ Cura.Menu
Cura.MenuItem { action: Cura.Actions.reloadAll }
Cura.MenuItem { action: Cura.Actions.resetAllTranslation }
Cura.MenuItem { action: Cura.Actions.resetAll }
Cura.MenuItem { action: Cura.Actions.dropAll }
// Group actions
Cura.MenuSeparator {}

View file

@ -21,6 +21,7 @@ Cura.Menu
Cura.MenuItem { action: Cura.Actions.deleteAll }
Cura.MenuItem { action: Cura.Actions.resetAllTranslation }
Cura.MenuItem { action: Cura.Actions.resetAll }
Cura.MenuItem { action: Cura.Actions.dropAll }
Cura.MenuSeparator { }
Cura.MenuItem { action: Cura.Actions.groupObjects }
Cura.MenuItem { action: Cura.Actions.mergeObjects }

View file

@ -47,8 +47,12 @@ Cura.Menu
enabled: UM.WorkspaceFileHandler.enabled && saveProjectMenu.model.count == 1
onTriggered:
{
var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" };
if(UM.Preferences.getValue("cura/dialog_on_project_save"))
const args = {
"filter_by_machine": false,
"file_type": "workspace",
"preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
};
if (UM.Preferences.getValue("cura/dialog_on_project_save"))
{
saveWorkspaceDialog.args = args
saveWorkspaceDialog.open()
@ -70,6 +74,14 @@ Cura.Menu
enabled: UM.WorkspaceFileHandler.enabled
}
Cura.MenuItem
{
id: saveUCPMenu
text: catalog.i18nc("@title:menu menubar:file", "&Save Universal Cura Project...")
enabled: UM.WorkspaceFileHandler.enabled && CuraApplication.getPackageManager().allEnabledPackages.includes("3MFWriter")
onTriggered: CuraApplication.exportUcp()
}
Cura.MenuSeparator { }
Cura.MenuItem
@ -78,8 +90,11 @@ Cura.Menu
text: catalog.i18nc("@title:menu menubar:file", "&Export...")
onTriggered:
{
var localDeviceId = "local_file"
UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"})
const args = {
"filter_by_machine": false,
"preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
};
UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args);
}
}
@ -89,7 +104,13 @@ Cura.Menu
text: catalog.i18nc("@action:inmenu menubar:file", "Export Selection...")
enabled: UM.Selection.hasSelection
icon.name: "document-save-as"
onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"})
onTriggered: {
const args = {
"filter_by_machine": false,
"preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
};
UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, args);
}
}
Cura.MenuSeparator { }

View file

@ -101,6 +101,7 @@ UM.PreferencesPage
centerOnSelectCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select"))
UM.Preferences.resetPreference("view/invert_zoom");
invertZoomCheckbox.checked = boolCheck(UM.Preferences.getValue("view/invert_zoom"))
UM.Preferences.resetPreference("view/navigation_style");
UM.Preferences.resetPreference("view/zoom_to_mouse");
zoomToMouseCheckbox.checked = boolCheck(UM.Preferences.getValue("view/zoom_to_mouse"))
//UM.Preferences.resetPreference("view/top_layer_count");
@ -512,7 +513,6 @@ UM.PreferencesPage
onCheckedChanged:
{
UM.Preferences.setValue("physics/automatic_drop_down", checked)
CuraApplication.getWorkplaceDropToBuildplate(checked)
}
}
}
@ -614,6 +614,55 @@ UM.PreferencesPage
}
}
UM.TooltipArea
{
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "What type of camera navigation should be used?")
Column
{
spacing: UM.Theme.getSize("narrow_margin").height
UM.Label
{
text: catalog.i18nc("@window:text", "Camera navigation:")
}
ListModel
{
id: navigationStylesList
Component.onCompleted:
{
append({ text: catalog.i18n("Cura"), code: "cura" })
append({ text: catalog.i18n("FreeCAD trackpad"), code: "freecad_trackpad" })
}
}
Cura.ComboBox
{
id: cameraNavigationComboBox
model: navigationStylesList
textRole: "text"
width: UM.Theme.getSize("combobox").width
height: UM.Theme.getSize("combobox").height
currentIndex:
{
var code = UM.Preferences.getValue("view/navigation_style");
for(var i = 0; i < comboBoxList.count; ++i)
{
if(model.get(i).code == code)
{
return i
}
}
return 0
}
onActivated: UM.Preferences.setValue("view/navigation_style", model.get(index).code)
}
}
}
Item
{
//: Spacer
@ -735,6 +784,20 @@ UM.PreferencesPage
}
}
UM.TooltipArea
{
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should a summary be shown when saving a UCP project file?")
UM.CheckBox
{
text: catalog.i18nc("@option:check", "Show summary dialog when saving a UCP project")
checked: boolCheck(UM.Preferences.getValue("cura/dialog_on_ucp_project_save"))
onCheckedChanged: UM.Preferences.setValue("cura/dialog_on_ucp_project_save", checked)
}
}
UM.TooltipArea
{
width: childrenRect.width

View file

@ -38,8 +38,8 @@ line_width = 0.4
min_infill_area = 0
optimize_wall_printing_order = True
prime_tower_brim_enable = True
prime_tower_enable = True
prime_tower_min_volume = 6
prime_tower_mode = normal
prime_tower_size = 20
prime_tower_wipe_enabled = True
retract_at_layer_change = False

View file

@ -38,8 +38,8 @@ line_width = 0.4
min_infill_area = 0
optimize_wall_printing_order = True
prime_tower_brim_enable = True
prime_tower_enable = True
prime_tower_min_volume = 6
prime_tower_mode = normal
prime_tower_size = 20
prime_tower_wipe_enabled = True
retract_at_layer_change = False

View file

@ -36,8 +36,8 @@ line_width = 0.4
min_infill_area = 0
optimize_wall_printing_order = True
prime_tower_brim_enable = True
prime_tower_enable = True
prime_tower_min_volume = 6
prime_tower_mode = normal
prime_tower_size = 20
prime_tower_wipe_enabled = True
retract_at_layer_change = False

View file

@ -36,8 +36,8 @@ line_width = 0.4
min_infill_area = 0
optimize_wall_printing_order = True
prime_tower_brim_enable = True
prime_tower_enable = True
prime_tower_min_volume = 6
prime_tower_mode = normal
prime_tower_size = 20
prime_tower_wipe_enabled = True
retract_at_layer_change = False

View file

@ -35,8 +35,8 @@ line_width = 0.4
min_infill_area = 0
optimize_wall_printing_order = True
prime_tower_brim_enable = True
prime_tower_enable = True
prime_tower_min_volume = 6
prime_tower_mode = normal
prime_tower_size = 20
prime_tower_wipe_enabled = True
retract_at_layer_change = False

View file

@ -35,8 +35,8 @@ line_width = 0.4
min_infill_area = 0
optimize_wall_printing_order = True
prime_tower_brim_enable = True
prime_tower_enable = True
prime_tower_min_volume = 6
prime_tower_mode = normal
prime_tower_size = 20
prime_tower_wipe_enabled = True
retract_at_layer_change = False

View file

@ -13,7 +13,7 @@ variant = DBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = DBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.40mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = FBE 0.60mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = V-DBE 0.80mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = V-DBE 0.80mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = V-DBE 0.80mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

View file

@ -13,7 +13,7 @@ variant = V-DBE 0.80mm
[values]
brim_replaces_support = False
material_standby_temperature = 100
prime_tower_mode = none
prime_tower_enable = False
support_bottom_distance = =support_z_distance
support_bottom_stair_step_height = 0
support_bottom_stair_step_width = 0

Some files were not shown because too many files have changed in this diff Show more