mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 03:25:56 +08:00
Merge branch 'master' of github.com:ultimaker/Cura into transparent_limit_to_extruder
* 'master' of github.com:ultimaker/Cura: (94 commits) Re-enable Japanese from language selection menu Add Japanese translations for setting descriptions Update PVA profiles Changed profile names Simplified some code Changed final spot where we still used findContainer when looking for container with specific type Directly use property instead of searching Added a type hinting to QualityManager JSON description fix: warn users when not to use spiralize (CURA-3636) Add setting_version every time we create InstanceContainer Increase warning value for gradual infill steps Convert all metadata fields to string cleanup: prime => prime blob and lil doc (CURA-3634) fix: don't make disallowed area if blob is disabled (CURA-3634) Be robust against older specification version numbers Read setting_version from version attribute on root Added bunch of typing to extruder manager Fix resolve strategy "new" for user instance container Added missing typehinting Row element was not used ...
This commit is contained in:
commit
c5c67ee8be
4
.gitignore
vendored
4
.gitignore
vendored
@ -11,6 +11,10 @@ resources/firmware
|
||||
resources/materials
|
||||
LC_MESSAGES
|
||||
.cache
|
||||
*.qmlc
|
||||
|
||||
#MacOS
|
||||
.DS_Store
|
||||
|
||||
# Editors and IDEs.
|
||||
*kdev*
|
||||
|
@ -562,7 +562,7 @@ class BuildVolume(SceneNode):
|
||||
used_extruders = [self._global_container_stack]
|
||||
|
||||
result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) #Normal machine disallowed areas can always be added.
|
||||
prime_areas = self._computeDisallowedAreasPrime(disallowed_border_size, used_extruders)
|
||||
prime_areas = self._computeDisallowedAreasPrimeBlob(disallowed_border_size, used_extruders)
|
||||
prime_disallowed_areas = self._computeDisallowedAreasStatic(0, used_extruders) #Where the priming is not allowed to happen. This is not added to the result, just for collision checking.
|
||||
|
||||
#Check if prime positions intersect with disallowed areas.
|
||||
@ -658,7 +658,7 @@ class BuildVolume(SceneNode):
|
||||
|
||||
return result
|
||||
|
||||
## Computes the disallowed areas for the prime locations.
|
||||
## Computes the disallowed areas for the prime blobs.
|
||||
#
|
||||
# These are special because they are not subject to things like brim or
|
||||
# travel avoidance. They do get a dilute with the border size though
|
||||
@ -669,17 +669,18 @@ class BuildVolume(SceneNode):
|
||||
# \param used_extruders The extruder stacks to generate disallowed areas
|
||||
# for.
|
||||
# \return A dictionary with for each used extruder ID the prime areas.
|
||||
def _computeDisallowedAreasPrime(self, border_size, used_extruders):
|
||||
def _computeDisallowedAreasPrimeBlob(self, border_size, used_extruders):
|
||||
result = {}
|
||||
|
||||
machine_width = self._global_container_stack.getProperty("machine_width", "value")
|
||||
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
|
||||
for extruder in used_extruders:
|
||||
prime_blob_enabled = extruder.getProperty("prime_blob_enable", "value")
|
||||
prime_x = extruder.getProperty("extruder_prime_pos_x", "value")
|
||||
prime_y = - extruder.getProperty("extruder_prime_pos_y", "value")
|
||||
|
||||
#Ignore extruder prime position if it is not set
|
||||
if prime_x == 0 and prime_y == 0:
|
||||
#Ignore extruder prime position if it is not set or if blob is disabled
|
||||
if (prime_x == 0 and prime_y == 0) or not prime_blob_enabled:
|
||||
result[extruder.getId()] = []
|
||||
continue
|
||||
|
||||
@ -952,7 +953,7 @@ class BuildVolume(SceneNode):
|
||||
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist"]
|
||||
_raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"]
|
||||
_extra_z_settings = ["retraction_hop_enabled", "retraction_hop"]
|
||||
_prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "extruder_prime_pos_z"]
|
||||
_prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "extruder_prime_pos_z", "prime_blob_enable"]
|
||||
_tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"]
|
||||
_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"]
|
||||
|
@ -294,6 +294,7 @@ class CuraApplication(QtApplication):
|
||||
z_seam_y
|
||||
infill
|
||||
infill_sparse_density
|
||||
gradual_infill_steps
|
||||
material
|
||||
material_print_temperature
|
||||
material_bed_temperature
|
||||
|
@ -31,8 +31,8 @@ catalog = i18nCatalog("cura")
|
||||
# - This triggers a new slice with the current settings - this is the "current settings pass".
|
||||
# - When the slice is done, we update the current print time and material amount.
|
||||
# - If the source of the slice was not a Setting change, we start the second slice pass, the "low quality settings pass". Otherwise we stop here.
|
||||
# - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass".
|
||||
# - When the high quality pass is done, we update the maximum print time.
|
||||
# - When that is done, we update the minimum print time and start the final slice pass, the "Extra Fine settings pass".
|
||||
# - When the Extra Fine pass is done, we update the maximum print time.
|
||||
#
|
||||
# This class also mangles the current machine name and the filename of the first loaded mesh into a job name.
|
||||
# This job name is requested by the JobSpecs qml file.
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
# This collects a lot of quality and quality changes related code which was split between ContainerManager
|
||||
# and the MachineManager and really needs to usable from both.
|
||||
from typing import List
|
||||
from typing import List, Optional, Dict, TYPE_CHECKING
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
@ -11,6 +11,10 @@ from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
from cura.Settings.ExtruderStack import ExtruderStack
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainerInterface
|
||||
|
||||
class QualityManager:
|
||||
|
||||
@ -27,12 +31,12 @@ class QualityManager:
|
||||
## Find a quality by name for a specific machine definition and materials.
|
||||
#
|
||||
# \param quality_name
|
||||
# \param machine_definition (Optional) \type{ContainerInstance} If nothing is
|
||||
# \param machine_definition (Optional) \type{DefinitionContainerInterface} If nothing is
|
||||
# specified then the currently selected machine definition is used.
|
||||
# \param material_containers (Optional) \type{List[ContainerInstance]} If nothing is specified then
|
||||
# \param material_containers (Optional) \type{List[InstanceContainer]} If nothing is specified then
|
||||
# the current set of selected materials is used.
|
||||
# \return the matching quality container \type{ContainerInstance}
|
||||
def findQualityByName(self, quality_name, machine_definition=None, material_containers=None):
|
||||
# \return the matching quality container \type{InstanceContainer}
|
||||
def findQualityByName(self, quality_name: str, machine_definition: Optional["DefinitionContainerInterface"] = None, material_containers: List[InstanceContainer] = None) -> Optional[InstanceContainer]:
|
||||
criteria = {"type": "quality", "name": quality_name}
|
||||
result = self._getFilteredContainersForStack(machine_definition, material_containers, **criteria)
|
||||
|
||||
@ -46,12 +50,10 @@ class QualityManager:
|
||||
## Find a quality changes container by name.
|
||||
#
|
||||
# \param quality_changes_name \type{str} the name of the quality changes container.
|
||||
# \param machine_definition (Optional) \type{ContainerInstance} If nothing is
|
||||
# specified then the currently selected machine definition is used.
|
||||
# \param material_containers (Optional) \type{List[ContainerInstance]} If nothing is specified then
|
||||
# the current set of selected materials is used.
|
||||
# \return the matching quality changes containers \type{List[ContainerInstance]}
|
||||
def findQualityChangesByName(self, quality_changes_name, machine_definition=None):
|
||||
# \param machine_definition (Optional) \type{DefinitionContainer} If nothing is
|
||||
# specified then the currently selected machine definition is used..
|
||||
# \return the matching quality changes containers \type{List[InstanceContainer]}
|
||||
def findQualityChangesByName(self, quality_changes_name: str, machine_definition: Optional["DefinitionContainerInterface"] = None):
|
||||
criteria = {"type": "quality_changes", "name": quality_changes_name}
|
||||
result = self._getFilteredContainersForStack(machine_definition, [], **criteria)
|
||||
|
||||
@ -62,7 +64,7 @@ class QualityManager:
|
||||
# \param machine_definition \type{DefinitionContainer}
|
||||
# \param material_containers \type{List[InstanceContainer]}
|
||||
# \return \type{List[str]}
|
||||
def findAllQualityTypesForMachineAndMaterials(self, machine_definition, material_containers):
|
||||
def findAllQualityTypesForMachineAndMaterials(self, machine_definition: "DefinitionContainerInterface", material_containers: List[InstanceContainer]) -> List[str]:
|
||||
# Determine the common set of quality types which can be
|
||||
# applied to all of the materials for this machine.
|
||||
quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_containers[0])
|
||||
@ -76,9 +78,9 @@ class QualityManager:
|
||||
## Fetches a dict of quality types names to quality profiles for a combination of machine and material.
|
||||
#
|
||||
# \param machine_definition \type{DefinitionContainer} the machine definition.
|
||||
# \param material \type{ContainerInstance} the material.
|
||||
# \return \type{Dict[str, ContainerInstance]} the dict of suitable quality type names mapping to qualities.
|
||||
def __fetchQualityTypeDictForMaterial(self, machine_definition, material):
|
||||
# \param material \type{InstanceContainer} the material.
|
||||
# \return \type{Dict[str, InstanceContainer]} the dict of suitable quality type names mapping to qualities.
|
||||
def __fetchQualityTypeDictForMaterial(self, machine_definition: "DefinitionContainerInterface", material: InstanceContainer) -> Dict[str, InstanceContainer]:
|
||||
qualities = self.findAllQualitiesForMachineMaterial(machine_definition, material)
|
||||
quality_type_dict = {}
|
||||
for quality in qualities:
|
||||
@ -88,12 +90,12 @@ class QualityManager:
|
||||
## Find a quality container by quality type.
|
||||
#
|
||||
# \param quality_type \type{str} the name of the quality type to search for.
|
||||
# \param machine_definition (Optional) \type{ContainerInstance} If nothing is
|
||||
# \param machine_definition (Optional) \type{InstanceContainer} If nothing is
|
||||
# specified then the currently selected machine definition is used.
|
||||
# \param material_containers (Optional) \type{List[ContainerInstance]} If nothing is specified then
|
||||
# \param material_containers (Optional) \type{List[InstanceContainer]} If nothing is specified then
|
||||
# the current set of selected materials is used.
|
||||
# \return the matching quality container \type{ContainerInstance}
|
||||
def findQualityByQualityType(self, quality_type, machine_definition=None, material_containers=None, **kwargs):
|
||||
# \return the matching quality container \type{InstanceContainer}
|
||||
def findQualityByQualityType(self, quality_type: str, machine_definition: Optional["DefinitionContainerInterface"] = None, material_containers: List[InstanceContainer] = None, **kwargs) -> InstanceContainer:
|
||||
criteria = kwargs
|
||||
criteria["type"] = "quality"
|
||||
if quality_type:
|
||||
@ -110,9 +112,9 @@ class QualityManager:
|
||||
## Find all suitable qualities for a combination of machine and material.
|
||||
#
|
||||
# \param machine_definition \type{DefinitionContainer} the machine definition.
|
||||
# \param material_container \type{ContainerInstance} the material.
|
||||
# \return \type{List[ContainerInstance]} the list of suitable qualities.
|
||||
def findAllQualitiesForMachineMaterial(self, machine_definition, material_container):
|
||||
# \param material_container \type{InstanceContainer} the material.
|
||||
# \return \type{List[InstanceContainer]} the list of suitable qualities.
|
||||
def findAllQualitiesForMachineMaterial(self, machine_definition: "DefinitionContainerInterface", material_container: InstanceContainer) -> List[InstanceContainer]:
|
||||
criteria = {"type": "quality" }
|
||||
result = self._getFilteredContainersForStack(machine_definition, [material_container], **criteria)
|
||||
if not result:
|
||||
@ -125,7 +127,7 @@ class QualityManager:
|
||||
#
|
||||
# \param machine_definition \type{DefinitionContainer} the machine definition.
|
||||
# \return \type{List[InstanceContainer]} the list of quality changes
|
||||
def findAllQualityChangesForMachine(self, machine_definition: DefinitionContainer) -> List[InstanceContainer]:
|
||||
def findAllQualityChangesForMachine(self, machine_definition: "DefinitionContainerInterface") -> List[InstanceContainer]:
|
||||
if machine_definition.getMetaDataEntry("has_machine_quality"):
|
||||
definition_id = machine_definition.getId()
|
||||
else:
|
||||
@ -141,19 +143,19 @@ class QualityManager:
|
||||
# Only one quality per quality type is returned. i.e. if there are 2 qualities with quality_type=normal
|
||||
# then only one of then is returned (at random).
|
||||
#
|
||||
# \param global_container_stack \type{ContainerStack} the global machine definition
|
||||
# \param extruder_stacks \type{List[ContainerStack]} the list of extruder stacks
|
||||
# \param global_container_stack \type{GlobalStack} the global machine definition
|
||||
# \param extruder_stacks \type{List[ExtruderStack]} the list of extruder stacks
|
||||
# \return \type{List[InstanceContainer]} the list of the matching qualities. The quality profiles
|
||||
# return come from the first extruder in the given list of extruders.
|
||||
def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack, extruder_stacks):
|
||||
def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack: "GlobalStack", extruder_stacks: List["ExtruderStack"]) -> List[InstanceContainer]:
|
||||
global_machine_definition = global_container_stack.getBottom()
|
||||
|
||||
if extruder_stacks:
|
||||
# Multi-extruder machine detected.
|
||||
materials = [stack.findContainer(type="material") for stack in extruder_stacks]
|
||||
materials = [stack.material for stack in extruder_stacks]
|
||||
else:
|
||||
# Machine with one extruder.
|
||||
materials = [global_container_stack.findContainer(type="material")]
|
||||
materials = [global_container_stack.material]
|
||||
|
||||
quality_types = self.findAllQualityTypesForMachineAndMaterials(global_machine_definition, materials)
|
||||
|
||||
@ -170,7 +172,7 @@ class QualityManager:
|
||||
# This tries to find a generic or basic version of the given material.
|
||||
# \param material_container \type{InstanceContainer} the material
|
||||
# \return \type{List[InstanceContainer]} a list of the basic materials or an empty list if one could not be found.
|
||||
def _getBasicMaterials(self, material_container):
|
||||
def _getBasicMaterials(self, material_container: InstanceContainer):
|
||||
base_material = material_container.getMetaDataEntry("material")
|
||||
material_container_definition = material_container.getDefinition()
|
||||
if material_container_definition and material_container_definition.getMetaDataEntry("has_machine_quality"):
|
||||
@ -192,7 +194,7 @@ class QualityManager:
|
||||
def _getFilteredContainers(self, **kwargs):
|
||||
return self._getFilteredContainersForStack(None, None, **kwargs)
|
||||
|
||||
def _getFilteredContainersForStack(self, machine_definition=None, material_containers=None, **kwargs):
|
||||
def _getFilteredContainersForStack(self, machine_definition: "DefinitionContainerInterface" = None, material_containers: List[InstanceContainer] = None, **kwargs):
|
||||
# Fill in any default values.
|
||||
if machine_definition is None:
|
||||
machine_definition = Application.getInstance().getGlobalContainerStack().getBottom()
|
||||
@ -202,7 +204,8 @@ class QualityManager:
|
||||
|
||||
if material_containers is None:
|
||||
active_stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
|
||||
material_containers = [stack.findContainer(type="material") for stack in active_stacks]
|
||||
if active_stacks:
|
||||
material_containers = [stack.material for stack in active_stacks]
|
||||
|
||||
criteria = kwargs
|
||||
filter_by_material = False
|
||||
@ -216,12 +219,11 @@ class QualityManager:
|
||||
filter_by_material = whole_machine_definition.getMetaDataEntry("has_materials")
|
||||
else:
|
||||
criteria["definition"] = "fdmprinter"
|
||||
|
||||
material_ids = set()
|
||||
# Stick the material IDs in a set
|
||||
if material_containers is None or len(material_containers) == 0:
|
||||
filter_by_material = False
|
||||
else:
|
||||
material_ids = set()
|
||||
for material_instance in material_containers:
|
||||
if material_instance is not None:
|
||||
# Add the parent material too.
|
||||
@ -245,7 +247,7 @@ class QualityManager:
|
||||
# an extruder definition.
|
||||
# \return \type{DefinitionContainer} the parent machine definition. If the given machine
|
||||
# definition doesn't have a parent then it is simply returned.
|
||||
def getParentMachineDefinition(self, machine_definition: DefinitionContainer) -> DefinitionContainer:
|
||||
def getParentMachineDefinition(self, machine_definition: "DefinitionContainerInterface") -> "DefinitionContainerInterface":
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
|
||||
machine_entry = machine_definition.getMetaDataEntry("machine")
|
||||
@ -274,8 +276,8 @@ class QualityManager:
|
||||
#
|
||||
# \param machine_definition \type{DefinitionContainer} This may be a normal machine definition or
|
||||
# an extruder definition.
|
||||
# \return \type{DefinitionContainer}
|
||||
def getWholeMachineDefinition(self, machine_definition):
|
||||
# \return \type{DefinitionContainerInterface}
|
||||
def getWholeMachineDefinition(self, machine_definition: "DefinitionContainerInterface") -> "DefinitionContainerInterface":
|
||||
machine_entry = machine_definition.getMetaDataEntry("machine")
|
||||
if machine_entry is None:
|
||||
# This already is a 'global' machine definition.
|
||||
|
@ -1,13 +1,15 @@
|
||||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import os.path
|
||||
import urllib
|
||||
import uuid
|
||||
from typing import Dict, Union
|
||||
|
||||
from PyQt5.QtCore import QObject, QUrl, QVariant
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from UM.Util import parseBool
|
||||
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.SaveFile import SaveFile
|
||||
@ -671,6 +673,9 @@ class ContainerManager(QObject):
|
||||
|
||||
return new_change_instances
|
||||
|
||||
## Create a duplicate of a material, which has the same GUID and base_file metadata
|
||||
#
|
||||
# \return \type{str} the id of the newly created container.
|
||||
@pyqtSlot(str, result = str)
|
||||
def duplicateMaterial(self, material_id: str) -> str:
|
||||
containers = self._container_registry.findInstanceContainers(id=material_id)
|
||||
@ -693,6 +698,104 @@ class ContainerManager(QObject):
|
||||
duplicated_container.deserialize(f.read())
|
||||
duplicated_container.setDirty(True)
|
||||
self._container_registry.addContainer(duplicated_container)
|
||||
return self._getMaterialContainerIdForActiveMachine(new_id)
|
||||
|
||||
## Create a new material by cloning Generic PLA and setting the GUID to something unqiue
|
||||
#
|
||||
# \return \type{str} the id of the newly created container.
|
||||
@pyqtSlot(result = str)
|
||||
def createMaterial(self) -> str:
|
||||
# Ensure all settings are saved.
|
||||
Application.getInstance().saveSettings()
|
||||
|
||||
containers = self._container_registry.findInstanceContainers(id="generic_pla")
|
||||
if not containers:
|
||||
Logger.log("d", "Unable to create a new material by cloning generic_pla, because it doesn't exist.")
|
||||
return ""
|
||||
|
||||
# Create a new ID & container to hold the data.
|
||||
new_id = self._container_registry.uniqueName("custom_material")
|
||||
container_type = type(containers[0]) # Could be either a XMLMaterialProfile or a InstanceContainer
|
||||
duplicated_container = container_type(new_id)
|
||||
|
||||
# Instead of duplicating we load the data from the basefile again.
|
||||
# This ensures that the inheritance goes well and all "cut up" subclasses of the xmlMaterial profile
|
||||
# are also correctly created.
|
||||
with open(containers[0].getPath(), encoding="utf-8") as f:
|
||||
duplicated_container.deserialize(f.read())
|
||||
|
||||
duplicated_container.setMetaDataEntry("GUID", str(uuid.uuid4()))
|
||||
duplicated_container.setMetaDataEntry("brand", catalog.i18nc("@label", "Custom"))
|
||||
duplicated_container.setMetaDataEntry("material", catalog.i18nc("@label", "Custom"))
|
||||
duplicated_container.setName(catalog.i18nc("@label", "Custom Material"))
|
||||
|
||||
self._container_registry.addContainer(duplicated_container)
|
||||
return self._getMaterialContainerIdForActiveMachine(new_id)
|
||||
|
||||
## Find the id of a material container based on the new material
|
||||
# Utilty function that is shared between duplicateMaterial and createMaterial
|
||||
#
|
||||
# \param base_file \type{str} the id of the created container.
|
||||
def _getMaterialContainerIdForActiveMachine(self, base_file):
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return base_file
|
||||
|
||||
has_machine_materials = parseBool(global_stack.getMetaDataEntry("has_machine_materials", default = False))
|
||||
has_variant_materials = parseBool(global_stack.getMetaDataEntry("has_variant_materials", default = False))
|
||||
has_variants = parseBool(global_stack.getMetaDataEntry("has_variants", default = False))
|
||||
if has_machine_materials or has_variant_materials:
|
||||
if has_variants:
|
||||
materials = self._container_registry.findInstanceContainers(type = "material", base_file = base_file, definition = global_stack.getBottom().getId(), variant = self._machine_manager.activeVariantId)
|
||||
else:
|
||||
materials = self._container_registry.findInstanceContainers(type = "material", base_file = base_file, definition = global_stack.getBottom().getId())
|
||||
|
||||
if materials:
|
||||
return materials[0].getId()
|
||||
|
||||
Logger.log("w", "Unable to find a suitable container based on %s for the current machine .", base_file)
|
||||
return "" # do not activate a new material if a container can not be found
|
||||
|
||||
return base_file
|
||||
|
||||
## Get a list of materials that have the same GUID as the reference material
|
||||
#
|
||||
# \param material_id \type{str} the id of the material for which to get the linked materials.
|
||||
# \return \type{list} a list of names of materials with the same GUID
|
||||
@pyqtSlot(str, result = "QStringList")
|
||||
def getLinkedMaterials(self, material_id: str):
|
||||
containers = self._container_registry.findInstanceContainers(id=material_id)
|
||||
if not containers:
|
||||
Logger.log("d", "Unable to find materials linked to material with id %s, because it doesn't exist.", material_id)
|
||||
return []
|
||||
|
||||
material_container = containers[0]
|
||||
material_base_file = material_container.getMetaDataEntry("base_file", "")
|
||||
material_guid = material_container.getMetaDataEntry("GUID", "")
|
||||
if not material_guid:
|
||||
Logger.log("d", "Unable to find materials linked to material with id %s, because it doesn't have a GUID.", material_id)
|
||||
return []
|
||||
|
||||
containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_guid)
|
||||
linked_material_names = []
|
||||
for container in containers:
|
||||
if container.getId() in [material_id, material_base_file] or container.getMetaDataEntry("base_file") != container.getId():
|
||||
continue
|
||||
|
||||
linked_material_names.append(container.getName())
|
||||
return linked_material_names
|
||||
|
||||
## Unlink a material from all other materials by creating a new GUID
|
||||
# \param material_id \type{str} the id of the material to create a new GUID for.
|
||||
@pyqtSlot(str)
|
||||
def unlinkMaterial(self, material_id: str):
|
||||
containers = self._container_registry.findInstanceContainers(id=material_id)
|
||||
if not containers:
|
||||
Logger.log("d", "Unable to make the material with id %s unique, because it doesn't exist.", material_id)
|
||||
return ""
|
||||
|
||||
containers[0].setMetaDataEntry("GUID", str(uuid.uuid4()))
|
||||
|
||||
|
||||
## Get the singleton instance for this class.
|
||||
@classmethod
|
||||
@ -815,6 +918,7 @@ class ContainerManager(QObject):
|
||||
quality_changes.setDefinition(self._container_registry.findContainers(id = "fdmprinter")[0])
|
||||
else:
|
||||
quality_changes.setDefinition(QualityManager.getInstance().getParentMachineDefinition(machine_definition))
|
||||
quality_changes.addMetaDataEntry("setting_version", quality_changes.getDefinition().getMetaDataEntry("setting_version", default = 0))
|
||||
return quality_changes
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import os
|
||||
@ -41,6 +41,14 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||
if type(container) == ContainerStack:
|
||||
container = self._convertContainerStack(container)
|
||||
|
||||
if isinstance(container, InstanceContainer) and type(container) != type(self.getEmptyInstanceContainer()):
|
||||
#Check against setting version of the definition.
|
||||
required_setting_version = int(container.getDefinition().getMetaDataEntry("setting_version", default = 0))
|
||||
actual_setting_version = int(container.getMetaDataEntry("setting_version", default = 0))
|
||||
if required_setting_version != actual_setting_version:
|
||||
Logger.log("w", "Instance container {container_id} is outdated. Its setting version is {actual_setting_version} but it should be {required_setting_version}.".format(container_id = container.getId(), actual_setting_version = actual_setting_version, required_setting_version = required_setting_version))
|
||||
return #Don't add.
|
||||
|
||||
super().addContainer(container)
|
||||
|
||||
## Create a name that is not empty and unique
|
||||
|
@ -254,6 +254,14 @@ class CuraContainerStack(ContainerStack):
|
||||
def definition(self) -> DefinitionContainer:
|
||||
return self._containers[_ContainerIndexes.Definition]
|
||||
|
||||
@override(ContainerStack)
|
||||
def getBottom(self) -> "DefinitionContainer":
|
||||
return self.definition
|
||||
|
||||
@override(ContainerStack)
|
||||
def getTop(self) -> "InstanceContainer":
|
||||
return self.userChanges
|
||||
|
||||
## Check whether the specified setting has a 'user' value.
|
||||
#
|
||||
# A user value here is defined as the setting having a value in either
|
||||
|
@ -76,6 +76,7 @@ class CuraStackBuilder:
|
||||
user_container = InstanceContainer(new_stack_id + "_user")
|
||||
user_container.addMetaDataEntry("type", "user")
|
||||
user_container.addMetaDataEntry("extruder", new_stack_id)
|
||||
user_container.addMetaDataEntry("setting_version", machine_definition.getMetaDataEntry("setting_version", default = 0))
|
||||
user_container.setDefinition(machine_definition)
|
||||
|
||||
stack.setUserChanges(user_container)
|
||||
@ -124,6 +125,7 @@ class CuraStackBuilder:
|
||||
user_container = InstanceContainer(new_stack_id + "_user")
|
||||
user_container.addMetaDataEntry("type", "user")
|
||||
user_container.addMetaDataEntry("machine", new_stack_id)
|
||||
user_container.addMetaDataEntry("setting_version", definition.getMetaDataEntry("setting_version", default = 0))
|
||||
user_container.setDefinition(definition)
|
||||
|
||||
stack.setUserChanges(user_container)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant #For communicating data and events to Qt.
|
||||
@ -16,7 +16,11 @@ from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.SettingFunction import SettingFunction
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
from typing import Optional, List
|
||||
from typing import Optional, List, TYPE_CHECKING, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.Settings.ExtruderStack import ExtruderStack
|
||||
|
||||
|
||||
## Manages all existing extruder stacks.
|
||||
#
|
||||
@ -81,7 +85,7 @@ class ExtruderManager(QObject):
|
||||
for position in self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()]:
|
||||
extruder = self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][position]
|
||||
if extruder.getId() == id:
|
||||
return extruder.findContainer(type = "quality_changes").getId()
|
||||
return extruder.qualityChanges.getId()
|
||||
|
||||
## The instance of the singleton pattern.
|
||||
#
|
||||
@ -166,7 +170,7 @@ class ExtruderManager(QObject):
|
||||
self._selected_object_extruders = []
|
||||
self.selectedObjectExtrudersChanged.emit()
|
||||
|
||||
def getActiveExtruderStack(self) -> ContainerStack:
|
||||
def getActiveExtruderStack(self) -> Optional["ExtruderStack"]:
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
|
||||
if global_container_stack:
|
||||
@ -176,7 +180,7 @@ class ExtruderManager(QObject):
|
||||
return None
|
||||
|
||||
## Get an extruder stack by index
|
||||
def getExtruderStack(self, index):
|
||||
def getExtruderStack(self, index) -> Optional["ExtruderStack"]:
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
if global_container_stack.getId() in self._extruder_trains:
|
||||
@ -185,7 +189,7 @@ class ExtruderManager(QObject):
|
||||
return None
|
||||
|
||||
## Get all extruder stacks
|
||||
def getExtruderStacks(self):
|
||||
def getExtruderStacks(self) -> List["ExtruderStack"]:
|
||||
result = []
|
||||
for i in range(self.extruderCount):
|
||||
result.append(self.getExtruderStack(i))
|
||||
@ -358,6 +362,7 @@ class ExtruderManager(QObject):
|
||||
user_profile = InstanceContainer(extruder_stack_id + "_current_settings") # Add an empty user profile.
|
||||
user_profile.addMetaDataEntry("type", "user")
|
||||
user_profile.addMetaDataEntry("extruder", extruder_stack_id)
|
||||
user_profile.addMetaDataEntry("setting_version", machine_definition.getMetaDataEntry("setting_version", default = 0))
|
||||
user_profile.setDefinition(machine_definition)
|
||||
container_registry.addContainer(user_profile)
|
||||
container_stack.addContainer(user_profile)
|
||||
@ -397,7 +402,7 @@ class ExtruderManager(QObject):
|
||||
# list.
|
||||
#
|
||||
# \return A list of extruder stacks.
|
||||
def getUsedExtruderStacks(self):
|
||||
def getUsedExtruderStacks(self) -> List["ContainerStack"]:
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
|
||||
@ -451,17 +456,15 @@ class ExtruderManager(QObject):
|
||||
## Removes the container stack and user profile for the extruders for a specific machine.
|
||||
#
|
||||
# \param machine_id The machine to remove the extruders for.
|
||||
def removeMachineExtruders(self, machine_id):
|
||||
def removeMachineExtruders(self, machine_id: str):
|
||||
for extruder in self.getMachineExtruders(machine_id):
|
||||
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", extruder = extruder.getId())
|
||||
for container in containers:
|
||||
ContainerRegistry.getInstance().removeContainer(container.getId())
|
||||
ContainerRegistry.getInstance().removeContainer(extruder.user.getId())
|
||||
ContainerRegistry.getInstance().removeContainer(extruder.getId())
|
||||
|
||||
## Returns extruders for a specific machine.
|
||||
#
|
||||
# \param machine_id The machine to get the extruders of.
|
||||
def getMachineExtruders(self, machine_id):
|
||||
def getMachineExtruders(self, machine_id: str):
|
||||
if machine_id not in self._extruder_trains:
|
||||
return []
|
||||
return [self._extruder_trains[machine_id][name] for name in self._extruder_trains[machine_id]]
|
||||
@ -470,7 +473,7 @@ class ExtruderManager(QObject):
|
||||
#
|
||||
# The first element is the global container stack, followed by any extruder stacks.
|
||||
# \return \type{List[ContainerStack]}
|
||||
def getActiveGlobalAndExtruderStacks(self):
|
||||
def getActiveGlobalAndExtruderStacks(self) -> Optional[List[Union["ExtruderStack", "GlobalStack"]]]:
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return None
|
||||
@ -482,7 +485,7 @@ class ExtruderManager(QObject):
|
||||
## Returns the list of active extruder stacks.
|
||||
#
|
||||
# \return \type{List[ContainerStack]} a list of
|
||||
def getActiveExtruderStacks(self):
|
||||
def getActiveExtruderStacks(self) -> List["ExtruderStack"]:
|
||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
|
||||
result = []
|
||||
|
@ -59,7 +59,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||
self.addRoleName(self.VariantRole, "variant")
|
||||
|
||||
self._update_extruder_timer = QTimer()
|
||||
self._update_extruder_timer.setInterval(250)
|
||||
self._update_extruder_timer.setInterval(100)
|
||||
self._update_extruder_timer.setSingleShot(True)
|
||||
self._update_extruder_timer.timeout.connect(self.__updateExtruders)
|
||||
|
||||
|
@ -11,14 +11,11 @@ from UM.Application import Application
|
||||
from UM.Preferences import Preferences
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.Decorators import deprecated
|
||||
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.SettingDefinition import SettingDefinition
|
||||
from UM.Settings.SettingFunction import SettingFunction
|
||||
from UM.Settings.Validator import ValidatorState
|
||||
from UM.Signal import postponeSignals
|
||||
import UM.FlameProfiler
|
||||
|
||||
@ -26,7 +23,6 @@ from cura.QualityManager import QualityManager
|
||||
from cura.PrinterOutputDevice import PrinterOutputDevice
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
from .GlobalStack import GlobalStack
|
||||
from .CuraStackBuilder import CuraStackBuilder
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
@ -36,15 +32,18 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
from cura.Settings.CuraContainerStack import CuraContainerStack
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class MachineManager(QObject):
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self._active_container_stack = None # type: ContainerStack
|
||||
self._global_container_stack = None # type: ContainerStack
|
||||
self._active_container_stack = None # type: CuraContainerStack
|
||||
self._global_container_stack = None # type: GlobalStack
|
||||
|
||||
self._error_check_timer = QTimer()
|
||||
self._error_check_timer.setInterval(250)
|
||||
@ -105,8 +104,6 @@ class MachineManager(QObject):
|
||||
self._material_incompatible_message = Message(catalog.i18nc("@info:status",
|
||||
"The selected material is incompatible with the selected machine or configuration."))
|
||||
|
||||
|
||||
|
||||
globalContainerChanged = pyqtSignal() # Emitted whenever the global stack is changed (ie: when changing between printers, changing a global profile, but not when changing a value)
|
||||
activeMaterialChanged = pyqtSignal()
|
||||
activeVariantChanged = pyqtSignal()
|
||||
@ -142,7 +139,7 @@ class MachineManager(QObject):
|
||||
return self._printer_output_devices
|
||||
|
||||
@pyqtProperty(int, constant=True)
|
||||
def totalNumberOfSettings(self):
|
||||
def totalNumberOfSettings(self) -> int:
|
||||
return len(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0].getAllKeys())
|
||||
|
||||
def _onHotendIdChanged(self, index: Union[str, int], hotend_id: str) -> None:
|
||||
@ -166,7 +163,7 @@ class MachineManager(QObject):
|
||||
else:
|
||||
Logger.log("w", "No variant found for printer definition %s with id %s" % (self._global_container_stack.getBottom().getId(), hotend_id))
|
||||
|
||||
def _onMaterialIdChanged(self, index, material_id):
|
||||
def _onMaterialIdChanged(self, index: Union[str, int], material_id: str):
|
||||
if not self._global_container_stack:
|
||||
return
|
||||
|
||||
@ -331,7 +328,7 @@ class MachineManager(QObject):
|
||||
def _onInstanceContainersChanged(self, container):
|
||||
self._instance_container_timer.start()
|
||||
|
||||
def _onPropertyChanged(self, key, property_name):
|
||||
def _onPropertyChanged(self, key: str, property_name: str):
|
||||
if property_name == "value":
|
||||
# Notify UI items, such as the "changed" star in profile pull down menu.
|
||||
self.activeStackValueChanged.emit()
|
||||
@ -415,7 +412,7 @@ class MachineManager(QObject):
|
||||
## Delete a user setting from the global stack and all extruder stacks.
|
||||
# \param key \type{str} the name of the key to delete
|
||||
@pyqtSlot(str)
|
||||
def clearUserSettingAllCurrentStacks(self, key):
|
||||
def clearUserSettingAllCurrentStacks(self, key: str):
|
||||
if not self._global_container_stack:
|
||||
return
|
||||
|
||||
@ -472,7 +469,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty("QObject", notify = globalContainerChanged)
|
||||
def activeMachine(self) -> GlobalStack:
|
||||
def activeMachine(self) -> "GlobalStack":
|
||||
return self._global_container_stack
|
||||
|
||||
@pyqtProperty(str, notify = activeStackChanged)
|
||||
@ -571,7 +568,7 @@ class MachineManager(QObject):
|
||||
# \return The layer height of the currently active quality profile. If
|
||||
# there is no quality profile, this returns 0.
|
||||
@pyqtProperty(float, notify=activeQualityChanged)
|
||||
def activeQualityLayerHeight(self):
|
||||
def activeQualityLayerHeight(self) -> float:
|
||||
if not self._global_container_stack:
|
||||
return 0
|
||||
|
||||
@ -588,7 +585,7 @@ class MachineManager(QObject):
|
||||
value = value(self._global_container_stack)
|
||||
return value
|
||||
|
||||
return 0 #No quality profile.
|
||||
return 0 # No quality profile.
|
||||
|
||||
## Get the Material ID associated with the currently active material
|
||||
# \returns MaterialID (string) if found, empty string otherwise
|
||||
@ -610,7 +607,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify=activeQualityChanged)
|
||||
def activeQualityName(self):
|
||||
def activeQualityName(self) -> str:
|
||||
if self._active_container_stack and self._global_container_stack:
|
||||
quality = self._global_container_stack.qualityChanges
|
||||
if quality and not isinstance(quality, type(self._empty_quality_changes_container)):
|
||||
@ -621,7 +618,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify=activeQualityChanged)
|
||||
def activeQualityId(self):
|
||||
def activeQualityId(self) -> str:
|
||||
if self._active_container_stack:
|
||||
quality = self._active_container_stack.qualityChanges
|
||||
if quality and not isinstance(quality, type(self._empty_quality_changes_container)):
|
||||
@ -632,7 +629,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify=activeQualityChanged)
|
||||
def globalQualityId(self):
|
||||
def globalQualityId(self) -> str:
|
||||
if self._global_container_stack:
|
||||
quality = self._global_container_stack.qualityChanges
|
||||
if quality and not isinstance(quality, type(self._empty_quality_changes_container)):
|
||||
@ -643,7 +640,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify = activeQualityChanged)
|
||||
def activeQualityType(self):
|
||||
def activeQualityType(self) -> str:
|
||||
if self._active_container_stack:
|
||||
quality = self._active_container_stack.quality
|
||||
if quality:
|
||||
@ -651,7 +648,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(bool, notify = activeQualityChanged)
|
||||
def isActiveQualitySupported(self):
|
||||
def isActiveQualitySupported(self) -> bool:
|
||||
if self._active_container_stack:
|
||||
quality = self._active_container_stack.quality
|
||||
if quality:
|
||||
@ -665,7 +662,7 @@ class MachineManager(QObject):
|
||||
# \todo Ideally, this method would be named activeQualityId(), and the other one
|
||||
# would be named something like activeQualityOrQualityChanges() for consistency
|
||||
@pyqtProperty(str, notify = activeQualityChanged)
|
||||
def activeQualityContainerId(self):
|
||||
def activeQualityContainerId(self) -> str:
|
||||
# We're using the active stack instead of the global stack in case the list of qualities differs per extruder
|
||||
if self._global_container_stack:
|
||||
quality = self._active_container_stack.quality
|
||||
@ -674,7 +671,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify = activeQualityChanged)
|
||||
def activeQualityChangesId(self):
|
||||
def activeQualityChangesId(self) -> str:
|
||||
if self._active_container_stack:
|
||||
changes = self._active_container_stack.qualityChanges
|
||||
if changes and changes.getId() != "empty":
|
||||
@ -683,7 +680,7 @@ class MachineManager(QObject):
|
||||
|
||||
## Check if a container is read_only
|
||||
@pyqtSlot(str, result = bool)
|
||||
def isReadOnly(self, container_id) -> bool:
|
||||
def isReadOnly(self, container_id: str) -> bool:
|
||||
containers = ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
|
||||
if not containers or not self._active_container_stack:
|
||||
return True
|
||||
@ -691,7 +688,7 @@ class MachineManager(QObject):
|
||||
|
||||
## Copy the value of the setting of the current extruder to all other extruders as well as the global container.
|
||||
@pyqtSlot(str)
|
||||
def copyValueToExtruders(self, key):
|
||||
def copyValueToExtruders(self, key: str):
|
||||
if not self._active_container_stack or self._global_container_stack.getProperty("machine_extruder_count", "value") <= 1:
|
||||
return
|
||||
|
||||
@ -705,7 +702,7 @@ class MachineManager(QObject):
|
||||
## Set the active material by switching out a container
|
||||
# Depending on from/to material+current variant, a quality profile is chosen and set.
|
||||
@pyqtSlot(str)
|
||||
def setActiveMaterial(self, material_id):
|
||||
def setActiveMaterial(self, material_id: str):
|
||||
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
|
||||
containers = ContainerRegistry.getInstance().findInstanceContainers(id = material_id)
|
||||
if not containers or not self._active_container_stack:
|
||||
@ -721,7 +718,7 @@ class MachineManager(QObject):
|
||||
Logger.log("w", "While trying to set the active material, no material was found to replace it.")
|
||||
return
|
||||
|
||||
if old_quality_changes and old_quality_changes.getId() == "empty_quality_changes":
|
||||
if old_quality_changes and isinstance(old_quality_changes, type(self._empty_quality_changes_container)):
|
||||
old_quality_changes = None
|
||||
|
||||
self.blurSettings.emit()
|
||||
@ -754,7 +751,7 @@ class MachineManager(QObject):
|
||||
candidate_quality = quality_manager.findQualityByQualityType(quality_type,
|
||||
quality_manager.getWholeMachineDefinition(machine_definition),
|
||||
[material_container])
|
||||
if not candidate_quality or candidate_quality.getId() == "empty_quality":
|
||||
if not candidate_quality or isinstance(candidate_quality, type(self._empty_quality_changes_container)):
|
||||
# Fall back to a quality (which must be compatible with all other extruders)
|
||||
new_qualities = quality_manager.findAllUsableQualitiesForMachineAndExtruders(
|
||||
self._global_container_stack, ExtruderManager.getInstance().getExtruderStacks())
|
||||
@ -770,7 +767,7 @@ class MachineManager(QObject):
|
||||
self.setActiveQuality(new_quality_id)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def setActiveVariant(self, variant_id):
|
||||
def setActiveVariant(self, variant_id: str):
|
||||
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
|
||||
containers = ContainerRegistry.getInstance().findInstanceContainers(id = variant_id)
|
||||
if not containers or not self._active_container_stack:
|
||||
@ -793,7 +790,7 @@ class MachineManager(QObject):
|
||||
## set the active quality
|
||||
# \param quality_id The quality_id of either a quality or a quality_changes
|
||||
@pyqtSlot(str)
|
||||
def setActiveQuality(self, quality_id):
|
||||
def setActiveQuality(self, quality_id: str):
|
||||
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
|
||||
self.blurSettings.emit()
|
||||
|
||||
@ -852,7 +849,7 @@ class MachineManager(QObject):
|
||||
# \param quality_name \type{str} the name of the quality.
|
||||
# \return \type{List[Dict]} with keys "stack", "quality" and "quality_changes".
|
||||
@UM.FlameProfiler.profile
|
||||
def determineQualityAndQualityChangesForQualityType(self, quality_type):
|
||||
def determineQualityAndQualityChangesForQualityType(self, quality_type: str):
|
||||
quality_manager = QualityManager.getInstance()
|
||||
result = []
|
||||
empty_quality_changes = self._empty_quality_changes_container
|
||||
@ -889,7 +886,7 @@ class MachineManager(QObject):
|
||||
#
|
||||
# \param quality_changes_name \type{str} the name of the quality changes.
|
||||
# \return \type{List[Dict]} with keys "stack", "quality" and "quality_changes".
|
||||
def _determineQualityAndQualityChangesForQualityChanges(self, quality_changes_name):
|
||||
def _determineQualityAndQualityChangesForQualityChanges(self, quality_changes_name: str):
|
||||
result = []
|
||||
quality_manager = QualityManager.getInstance()
|
||||
|
||||
@ -945,7 +942,7 @@ class MachineManager(QObject):
|
||||
|
||||
return result
|
||||
|
||||
def _replaceQualityOrQualityChangesInStack(self, stack, container, postpone_emit = False):
|
||||
def _replaceQualityOrQualityChangesInStack(self, stack: "CuraContainerStack", container: "InstanceContainer", postpone_emit = False):
|
||||
# Disconnect the signal handling from the old container.
|
||||
container_type = container.getMetaDataEntry("type")
|
||||
if container_type == "quality":
|
||||
@ -964,7 +961,7 @@ class MachineManager(QObject):
|
||||
Application.getInstance().discardOrKeepProfileChanges()
|
||||
|
||||
@pyqtProperty(str, notify = activeVariantChanged)
|
||||
def activeVariantName(self):
|
||||
def activeVariantName(self) -> str:
|
||||
if self._active_container_stack:
|
||||
variant = self._active_container_stack.variant
|
||||
if variant:
|
||||
@ -973,7 +970,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify = activeVariantChanged)
|
||||
def activeVariantId(self):
|
||||
def activeVariantId(self) -> str:
|
||||
if self._active_container_stack:
|
||||
variant = self._active_container_stack.variant
|
||||
if variant:
|
||||
@ -982,7 +979,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify = globalContainerChanged)
|
||||
def activeDefinitionId(self):
|
||||
def activeDefinitionId(self) -> str:
|
||||
if self._global_container_stack:
|
||||
definition = self._global_container_stack.getBottom()
|
||||
if definition:
|
||||
@ -991,7 +988,7 @@ class MachineManager(QObject):
|
||||
return ""
|
||||
|
||||
@pyqtProperty(str, notify=globalContainerChanged)
|
||||
def activeDefinitionName(self):
|
||||
def activeDefinitionName(self) -> str:
|
||||
if self._global_container_stack:
|
||||
definition = self._global_container_stack.getBottom()
|
||||
if definition:
|
||||
@ -1003,7 +1000,7 @@ class MachineManager(QObject):
|
||||
# \returns DefinitionID (string) if found, empty string otherwise
|
||||
# \sa getQualityDefinitionId
|
||||
@pyqtProperty(str, notify = globalContainerChanged)
|
||||
def activeQualityDefinitionId(self):
|
||||
def activeQualityDefinitionId(self) -> str:
|
||||
if self._global_container_stack:
|
||||
return self.getQualityDefinitionId(self._global_container_stack.getBottom())
|
||||
return ""
|
||||
@ -1012,14 +1009,14 @@ class MachineManager(QObject):
|
||||
# This is normally the id of the definition itself, but machines can specify a different definition to inherit qualities from
|
||||
# \param definition (DefinitionContainer) machine definition
|
||||
# \returns DefinitionID (string) if found, empty string otherwise
|
||||
def getQualityDefinitionId(self, definition):
|
||||
def getQualityDefinitionId(self, definition: "DefinitionContainer") -> str:
|
||||
return QualityManager.getInstance().getParentMachineDefinition(definition).getId()
|
||||
|
||||
## Get the Variant ID to use to select quality profiles for the currently active variant
|
||||
# \returns VariantID (string) if found, empty string otherwise
|
||||
# \sa getQualityVariantId
|
||||
@pyqtProperty(str, notify = activeVariantChanged)
|
||||
def activeQualityVariantId(self):
|
||||
def activeQualityVariantId(self) -> str:
|
||||
if self._active_container_stack:
|
||||
variant = self._active_container_stack.variant
|
||||
if variant:
|
||||
@ -1030,9 +1027,9 @@ class MachineManager(QObject):
|
||||
# This is normally the id of the variant itself, but machines can specify a different definition
|
||||
# to inherit qualities from, which has consequences for the variant to use as well
|
||||
# \param definition (DefinitionContainer) machine definition
|
||||
# \param variant (DefinitionContainer) variant definition
|
||||
# \param variant (InstanceContainer) variant definition
|
||||
# \returns VariantID (string) if found, empty string otherwise
|
||||
def getQualityVariantId(self, definition, variant):
|
||||
def getQualityVariantId(self, definition: "DefinitionContainer", variant: "InstanceContainer") -> str:
|
||||
variant_id = variant.getId()
|
||||
definition_id = definition.getId()
|
||||
quality_definition_id = self.getQualityDefinitionId(definition)
|
||||
@ -1044,7 +1041,7 @@ class MachineManager(QObject):
|
||||
## Gets how the active definition calls variants
|
||||
# Caveat: per-definition-variant-title is currently not translated (though the fallback is)
|
||||
@pyqtProperty(str, notify = globalContainerChanged)
|
||||
def activeDefinitionVariantsName(self):
|
||||
def activeDefinitionVariantsName(self) -> str:
|
||||
fallback_title = catalog.i18nc("@label", "Nozzle")
|
||||
if self._global_container_stack:
|
||||
return self._global_container_stack.getBottom().getMetaDataEntry("variants_name", fallback_title)
|
||||
@ -1052,7 +1049,7 @@ class MachineManager(QObject):
|
||||
return fallback_title
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def renameMachine(self, machine_id, new_name):
|
||||
def renameMachine(self, machine_id: str, new_name: str):
|
||||
containers = ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
|
||||
if containers:
|
||||
new_name = self._createUniqueName("machine", containers[0].getName(), new_name, containers[0].getBottom().getName())
|
||||
@ -1060,7 +1057,7 @@ class MachineManager(QObject):
|
||||
self.globalContainerChanged.emit()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def removeMachine(self, machine_id):
|
||||
def removeMachine(self, machine_id: str):
|
||||
# If the machine that is being removed is the currently active machine, set another machine as the active machine.
|
||||
activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
|
||||
|
||||
@ -1078,14 +1075,14 @@ class MachineManager(QObject):
|
||||
|
||||
|
||||
@pyqtProperty(bool, notify = globalContainerChanged)
|
||||
def hasMaterials(self):
|
||||
def hasMaterials(self) -> bool:
|
||||
if self._global_container_stack:
|
||||
return bool(self._global_container_stack.getMetaDataEntry("has_materials", False))
|
||||
|
||||
return False
|
||||
|
||||
@pyqtProperty(bool, notify = globalContainerChanged)
|
||||
def hasVariants(self):
|
||||
def hasVariants(self) -> bool:
|
||||
if self._global_container_stack:
|
||||
return bool(self._global_container_stack.getMetaDataEntry("has_variants", False))
|
||||
|
||||
@ -1094,7 +1091,7 @@ class MachineManager(QObject):
|
||||
## Property to indicate if a machine has "specialized" material profiles.
|
||||
# Some machines have their own material profiles that "override" the default catch all profiles.
|
||||
@pyqtProperty(bool, notify = globalContainerChanged)
|
||||
def filterMaterialsByMachine(self):
|
||||
def filterMaterialsByMachine(self) -> bool:
|
||||
if self._global_container_stack:
|
||||
return bool(self._global_container_stack.getMetaDataEntry("has_machine_materials", False))
|
||||
|
||||
@ -1103,7 +1100,7 @@ class MachineManager(QObject):
|
||||
## Property to indicate if a machine has "specialized" quality profiles.
|
||||
# Some machines have their own quality profiles that "override" the default catch all profiles.
|
||||
@pyqtProperty(bool, notify = globalContainerChanged)
|
||||
def filterQualityByMachine(self):
|
||||
def filterQualityByMachine(self) -> bool:
|
||||
if self._global_container_stack:
|
||||
return bool(self._global_container_stack.getMetaDataEntry("has_machine_quality", False))
|
||||
return False
|
||||
@ -1112,7 +1109,7 @@ class MachineManager(QObject):
|
||||
# \param machine_id string machine id to get the definition ID of
|
||||
# \returns DefinitionID (string) if found, None otherwise
|
||||
@pyqtSlot(str, result = str)
|
||||
def getDefinitionByMachineId(self, machine_id):
|
||||
def getDefinitionByMachineId(self, machine_id: str) -> str:
|
||||
containers = ContainerRegistry.getInstance().findContainerStacks(id=machine_id)
|
||||
if containers:
|
||||
return containers[0].getBottom().getId()
|
||||
@ -1121,22 +1118,6 @@ class MachineManager(QObject):
|
||||
def createMachineManager(engine=None, script_engine=None):
|
||||
return MachineManager()
|
||||
|
||||
def _updateVariantContainer(self, definition: "DefinitionContainer"):
|
||||
if not definition.getMetaDataEntry("has_variants"):
|
||||
return self._empty_variant_container
|
||||
machine_definition_id = Application.getInstance().getMachineManager().getQualityDefinitionId(definition)
|
||||
containers = []
|
||||
preferred_variant = definition.getMetaDataEntry("preferred_variant")
|
||||
if preferred_variant:
|
||||
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = machine_definition_id, id = preferred_variant)
|
||||
if not containers:
|
||||
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = machine_definition_id)
|
||||
|
||||
if containers:
|
||||
return containers[0]
|
||||
|
||||
return self._empty_variant_container
|
||||
|
||||
def _updateMaterialContainer(self, definition: "DefinitionContainer", stack: "ContainerStack", variant_container: Optional["InstanceContainer"] = None, preferred_material_name: Optional[str] = None):
|
||||
if not definition.getMetaDataEntry("has_materials"):
|
||||
return self._empty_material_container
|
||||
@ -1174,110 +1155,6 @@ class MachineManager(QObject):
|
||||
Logger.log("w", "Unable to find a material container with provided criteria, returning an empty one instead.")
|
||||
return self._empty_material_container
|
||||
|
||||
def _updateQualityContainer(self, definition: "DefinitionContainer", variant_container: "ContainerStack", material_container = None, preferred_quality_name: Optional[str] = None):
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
search_criteria = { "type": "quality" }
|
||||
|
||||
if definition.getMetaDataEntry("has_machine_quality"):
|
||||
search_criteria["definition"] = self.getQualityDefinitionId(definition)
|
||||
|
||||
if definition.getMetaDataEntry("has_materials") and material_container:
|
||||
search_criteria["material"] = material_container.id
|
||||
else:
|
||||
search_criteria["definition"] = "fdmprinter"
|
||||
|
||||
if preferred_quality_name and preferred_quality_name != "empty":
|
||||
search_criteria["name"] = preferred_quality_name
|
||||
else:
|
||||
preferred_quality = definition.getMetaDataEntry("preferred_quality")
|
||||
if preferred_quality:
|
||||
search_criteria["id"] = preferred_quality
|
||||
|
||||
containers = container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers:
|
||||
return containers[0]
|
||||
|
||||
if "material" in search_criteria:
|
||||
# First check if we can solve our material not found problem by checking if we can find quality containers
|
||||
# that are assigned to the parents of this material profile.
|
||||
try:
|
||||
inherited_files = material_container.getInheritedFiles()
|
||||
except AttributeError: # Material_container does not support inheritance.
|
||||
inherited_files = []
|
||||
|
||||
if inherited_files:
|
||||
for inherited_file in inherited_files:
|
||||
# Extract the ID from the path we used to load the file.
|
||||
search_criteria["material"] = os.path.basename(inherited_file).split(".")[0]
|
||||
containers = container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers:
|
||||
return containers[0]
|
||||
# We still weren't able to find a quality for this specific material.
|
||||
# Try to find qualities for a generic version of the material.
|
||||
material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"}
|
||||
if definition.getMetaDataEntry("has_machine_quality"):
|
||||
if material_container:
|
||||
material_search_criteria["definition"] = material_container.getDefinition().id
|
||||
|
||||
if definition.getMetaDataEntry("has_variants"):
|
||||
material_search_criteria["variant"] = material_container.getMetaDataEntry("variant")
|
||||
else:
|
||||
material_search_criteria["definition"] = self.getQualityDefinitionId(definition)
|
||||
|
||||
if definition.getMetaDataEntry("has_variants") and variant_container:
|
||||
material_search_criteria["variant"] = self.getQualityVariantId(definition, variant_container)
|
||||
else:
|
||||
material_search_criteria["definition"] = "fdmprinter"
|
||||
material_containers = container_registry.findInstanceContainers(**material_search_criteria)
|
||||
# Try all materials to see if there is a quality profile available.
|
||||
for material_container in material_containers:
|
||||
search_criteria["material"] = material_container.getId()
|
||||
|
||||
containers = container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers:
|
||||
return containers[0]
|
||||
|
||||
if "name" in search_criteria or "id" in search_criteria:
|
||||
# If a quality by this name can not be found, try a wider set of search criteria
|
||||
search_criteria.pop("name", None)
|
||||
search_criteria.pop("id", None)
|
||||
|
||||
containers = container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers:
|
||||
return containers[0]
|
||||
|
||||
# Notify user that we were unable to find a matching quality
|
||||
message = Message(catalog.i18nc("@info:status", "Unable to find a quality profile for this combination. Default settings will be used instead."))
|
||||
message.show()
|
||||
return self._empty_quality_container
|
||||
|
||||
## Finds a quality-changes container to use if any other container
|
||||
# changes.
|
||||
#
|
||||
# \param quality_type The quality type to find a quality-changes for.
|
||||
# \param preferred_quality_changes_name The name of the quality-changes to
|
||||
# pick, if any such quality-changes profile is available.
|
||||
def _updateQualityChangesContainer(self, quality_type, preferred_quality_changes_name = None):
|
||||
container_registry = ContainerRegistry.getInstance() # Cache.
|
||||
search_criteria = { "type": "quality_changes" }
|
||||
|
||||
search_criteria["quality"] = quality_type
|
||||
if preferred_quality_changes_name:
|
||||
search_criteria["name"] = preferred_quality_changes_name
|
||||
|
||||
# Try to search with the name in the criteria first, since we prefer to have the correct name.
|
||||
containers = container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers: # Found one!
|
||||
return containers[0]
|
||||
|
||||
if "name" in search_criteria:
|
||||
del search_criteria["name"] # Not found, then drop the name requirement (if we had one) and search again.
|
||||
containers = container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers:
|
||||
return containers[0]
|
||||
|
||||
return self._empty_quality_changes_container # Didn't find anything with the required quality_type.
|
||||
|
||||
def _onMachineNameChanged(self):
|
||||
self.globalContainerChanged.emit()
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Workspace.WorkspaceReader import WorkspaceReader
|
||||
from UM.Application import Application
|
||||
|
||||
@ -109,7 +112,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
machine_type = ""
|
||||
variant_type_name = i18n_catalog.i18nc("@label", "Nozzle")
|
||||
|
||||
num_extruders = 0
|
||||
# Check if there are any conflicts, so we can ask the user.
|
||||
archive = zipfile.ZipFile(file_name, "r")
|
||||
cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")]
|
||||
@ -121,31 +123,41 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
instance_container_list = []
|
||||
material_container_list = []
|
||||
|
||||
#
|
||||
# Read definition containers
|
||||
#
|
||||
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)]
|
||||
for definition_container_file in definition_container_files:
|
||||
container_id = self._stripFileToId(definition_container_file)
|
||||
for each_definition_container_file in definition_container_files:
|
||||
container_id = self._stripFileToId(each_definition_container_file)
|
||||
definitions = self._container_registry.findDefinitionContainers(id=container_id)
|
||||
|
||||
if not definitions:
|
||||
definition_container = DefinitionContainer(container_id)
|
||||
definition_container.deserialize(archive.open(definition_container_file).read().decode("utf-8"))
|
||||
definition_container.deserialize(archive.open(each_definition_container_file).read().decode("utf-8"))
|
||||
|
||||
else:
|
||||
definition_container = definitions[0]
|
||||
|
||||
definition_container_list.append(definition_container)
|
||||
|
||||
if definition_container.getMetaDataEntry("type") != "extruder":
|
||||
definition_container_type = definition_container.getMetaDataEntry("type")
|
||||
if definition_container_type == "machine":
|
||||
machine_type = definition_container.getName()
|
||||
variant_type_name = definition_container.getMetaDataEntry("variants_name", variant_type_name)
|
||||
|
||||
machine_definition_container_count += 1
|
||||
elif definition_container_type == "extruder":
|
||||
extruder_definition_container_count += 1
|
||||
else:
|
||||
num_extruders += 1
|
||||
Logger.log("w", "Unknown definition container type %s for %s",
|
||||
definition_container_type, each_definition_container_file)
|
||||
Job.yieldThread()
|
||||
|
||||
if num_extruders == 0:
|
||||
num_extruders = 1 # No extruder stacks found, which means there is one extruder
|
||||
|
||||
extruders = num_extruders * [""]
|
||||
# sanity check
|
||||
if machine_definition_container_count != 1:
|
||||
msg = "Expecting one machine definition container but got %s" % machine_definition_container_count
|
||||
Logger.log("e", msg)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
material_labels = []
|
||||
material_conflict = False
|
||||
@ -161,19 +173,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
if materials and not materials[0].isReadOnly(): # Only non readonly materials can be in conflict
|
||||
material_conflict = True
|
||||
Job.yieldThread()
|
||||
|
||||
# Check if any quality_changes instance container is in conflict.
|
||||
instance_container_files = [name for name in cura_file_names if name.endswith(self._instance_container_suffix)]
|
||||
quality_name = ""
|
||||
quality_type = ""
|
||||
num_settings_overriden_by_quality_changes = 0 # How many settings are changed by the quality changes
|
||||
num_settings_overriden_by_definition_changes = 0 # How many settings are changed by the definition changes
|
||||
num_user_settings = 0
|
||||
for instance_container_file in instance_container_files:
|
||||
container_id = self._stripFileToId(instance_container_file)
|
||||
quality_changes_conflict = False
|
||||
definition_changes_conflict = False
|
||||
for each_instance_container_file in instance_container_files:
|
||||
container_id = self._stripFileToId(each_instance_container_file)
|
||||
instance_container = InstanceContainer(container_id)
|
||||
|
||||
# Deserialize InstanceContainer by converting read data from bytes to string
|
||||
instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"))
|
||||
|
||||
instance_container.deserialize(archive.open(each_instance_container_file).read().decode("utf-8"))
|
||||
instance_container_list.append(instance_container)
|
||||
|
||||
container_type = instance_container.getMetaDataEntry("type")
|
||||
@ -186,6 +201,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
# Check if there really is a conflict by comparing the values
|
||||
if quality_changes[0] != instance_container:
|
||||
quality_changes_conflict = True
|
||||
elif container_type == "definition_changes":
|
||||
definition_name = instance_container.getName()
|
||||
num_settings_overriden_by_definition_changes += len(instance_container._instances)
|
||||
definition_changes = self._container_registry.findDefinitionContainers(id = container_id)
|
||||
if definition_changes:
|
||||
if definition_changes[0] != instance_container:
|
||||
definition_changes_conflict = True
|
||||
elif container_type == "quality":
|
||||
# If the quality name is not set (either by quality or changes, set it now)
|
||||
# Quality changes should always override this (as they are "on top")
|
||||
@ -202,7 +224,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
file_name, cura_file_names)
|
||||
self._resolve_strategies = {"machine": None, "quality_changes": None, "material": None}
|
||||
machine_conflict = False
|
||||
quality_changes_conflict = False
|
||||
for container_stack_file in [global_stack_file] + extruder_stack_files:
|
||||
container_id = self._stripFileToId(container_stack_file)
|
||||
serialized = archive.open(container_stack_file).read().decode("utf-8")
|
||||
@ -237,9 +258,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
if not show_dialog:
|
||||
return WorkspaceReader.PreReadResult.accepted
|
||||
|
||||
# prepare data for the dialog
|
||||
num_extruders = extruder_definition_container_count
|
||||
if num_extruders == 0:
|
||||
num_extruders = 1 # No extruder stacks found, which means there is one extruder
|
||||
|
||||
extruders = num_extruders * [""]
|
||||
|
||||
# Show the dialog, informing the user what is about to happen.
|
||||
self._dialog.setMachineConflict(machine_conflict)
|
||||
self._dialog.setQualityChangesConflict(quality_changes_conflict)
|
||||
self._dialog.setDefinitionChangesConflict(definition_changes_conflict)
|
||||
self._dialog.setMaterialConflict(material_conflict)
|
||||
self._dialog.setNumVisibleSettings(num_visible_settings)
|
||||
self._dialog.setQualityName(quality_name)
|
||||
@ -262,6 +291,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
return WorkspaceReader.PreReadResult.cancelled
|
||||
|
||||
self._resolve_strategies = self._dialog.getResult()
|
||||
#
|
||||
# There can be 3 resolve strategies coming from the dialog:
|
||||
# - new: create a new container
|
||||
# - override: override the existing container
|
||||
# - None: There is no conflict, which means containers with the same IDs may or may not be there already.
|
||||
# If they are there, there is no conflict between the them.
|
||||
# In this case, you can either create a new one, or safely override the existing one.
|
||||
#
|
||||
# Default values
|
||||
for k, v in self._resolve_strategies.items():
|
||||
if v is None:
|
||||
@ -316,6 +353,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
extruder_stacks_added = []
|
||||
container_stacks_added = []
|
||||
|
||||
containers_added = []
|
||||
|
||||
global_stack_id_original = self._stripFileToId(global_stack_file)
|
||||
global_stack_id_new = global_stack_id_original
|
||||
global_stack_need_rename = False
|
||||
@ -325,7 +364,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
global_stack_id_new = self.getNewId(global_stack_id_original)
|
||||
global_stack_need_rename = True
|
||||
|
||||
|
||||
# TODO: For the moment we use pretty naive existence checking. If the ID is the same, we assume in quite a few
|
||||
# TODO: cases that the container loaded is the same (most notable in materials & definitions).
|
||||
# TODO: It might be possible that we need to add smarter checking in the future.
|
||||
@ -352,21 +390,24 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
for material_container_file in material_container_files:
|
||||
container_id = self._stripFileToId(material_container_file)
|
||||
materials = self._container_registry.findInstanceContainers(id = container_id)
|
||||
|
||||
if not materials:
|
||||
material_container = xml_material_profile(container_id)
|
||||
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"))
|
||||
containers_to_add.append(material_container)
|
||||
else:
|
||||
if not materials[0].isReadOnly(): # Only create new materials if they are not read only.
|
||||
material_container = materials[0]
|
||||
if not material_container.isReadOnly(): # Only create new materials if they are not read only.
|
||||
if self._resolve_strategies["material"] == "override":
|
||||
materials[0].deserialize(archive.open(material_container_file).read().decode("utf-8"))
|
||||
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"))
|
||||
elif self._resolve_strategies["material"] == "new":
|
||||
# Note that we *must* deserialize it with a new ID, as multiple containers will be
|
||||
# auto created & added.
|
||||
material_container = xml_material_profile(self.getNewId(container_id))
|
||||
material_container.deserialize(archive.open(material_container_file).read().decode("utf-8"))
|
||||
containers_to_add.append(material_container)
|
||||
material_containers.append(material_container)
|
||||
|
||||
material_containers.append(material_container)
|
||||
Job.yieldThread()
|
||||
|
||||
Logger.log("d", "Workspace loading is checking instance containers...")
|
||||
@ -389,23 +430,27 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
containers_to_add.append(instance_container)
|
||||
else:
|
||||
if self._resolve_strategies["machine"] == "override" or self._resolve_strategies["machine"] is None:
|
||||
user_containers[0].deserialize(archive.open(instance_container_file).read().decode("utf-8"))
|
||||
instance_container = user_containers[0]
|
||||
instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"))
|
||||
instance_container.setDirty(True)
|
||||
elif self._resolve_strategies["machine"] == "new":
|
||||
# The machine is going to get a spiffy new name, so ensure that the id's of user settings match.
|
||||
extruder_id = instance_container.getMetaDataEntry("extruder", None)
|
||||
if extruder_id:
|
||||
new_id = self.getNewId(extruder_id) + "_current_settings"
|
||||
new_extruder_id = self.getNewId(extruder_id)
|
||||
new_id = new_extruder_id + "_current_settings"
|
||||
instance_container._id = new_id
|
||||
instance_container.setName(new_id)
|
||||
instance_container.setMetaDataEntry("extruder", self.getNewId(extruder_id))
|
||||
instance_container.setMetaDataEntry("extruder", new_extruder_id)
|
||||
containers_to_add.append(instance_container)
|
||||
|
||||
machine_id = instance_container.getMetaDataEntry("machine", None)
|
||||
if machine_id:
|
||||
new_id = self.getNewId(machine_id) + "_current_settings"
|
||||
new_machine_id = self.getNewId(machine_id)
|
||||
new_id = new_machine_id + "_current_settings"
|
||||
instance_container._id = new_id
|
||||
instance_container.setName(new_id)
|
||||
instance_container.setMetaDataEntry("machine", self.getNewId(machine_id))
|
||||
instance_container.setMetaDataEntry("machine", new_machine_id)
|
||||
containers_to_add.append(instance_container)
|
||||
user_instance_containers.append(instance_container)
|
||||
elif container_type in ("quality_changes", "definition_changes"):
|
||||
@ -415,7 +460,32 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
containers_to_add.append(instance_container)
|
||||
else:
|
||||
if self._resolve_strategies[container_type] == "override":
|
||||
changes_containers[0].deserialize(archive.open(instance_container_file).read().decode("utf-8"))
|
||||
instance_container = changes_containers[0]
|
||||
instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"))
|
||||
instance_container.setDirty(True)
|
||||
elif self._resolve_strategies[container_type] == "new":
|
||||
# TODO: how should we handle the case "new" for quality_changes and definition_changes?
|
||||
|
||||
new_changes_container_id = self.getNewId(instance_container.getId())
|
||||
instance_container._id = new_changes_container_id
|
||||
instance_container.setName(new_changes_container_id)
|
||||
|
||||
# TODO: we don't know the following is correct or not, need to verify
|
||||
# AND REFACTOR!!!
|
||||
if self._resolve_strategies["machine"] == "new":
|
||||
# The machine is going to get a spiffy new name, so ensure that the id's of user settings match.
|
||||
extruder_id = instance_container.getMetaDataEntry("extruder", None)
|
||||
if extruder_id:
|
||||
new_extruder_id = self.getNewId(extruder_id)
|
||||
instance_container.setMetaDataEntry("extruder", new_extruder_id)
|
||||
|
||||
machine_id = instance_container.getMetaDataEntry("machine", None)
|
||||
if machine_id:
|
||||
new_machine_id = self.getNewId(machine_id)
|
||||
instance_container.setMetaDataEntry("machine", new_machine_id)
|
||||
|
||||
containers_to_add.append(instance_container)
|
||||
|
||||
elif self._resolve_strategies[container_type] is None:
|
||||
# The ID already exists, but nothing in the values changed, so do nothing.
|
||||
pass
|
||||
@ -432,73 +502,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
for container in containers_to_add:
|
||||
self._container_registry.addContainer(container)
|
||||
container.setDirty(True)
|
||||
containers_added.append(container)
|
||||
|
||||
# Get the stack(s) saved in the workspace.
|
||||
Logger.log("d", "Workspace loading is checking stacks containers...")
|
||||
|
||||
# load extruder stack files
|
||||
try:
|
||||
for index, extruder_stack_file in enumerate(extruder_stack_files):
|
||||
container_id = self._stripFileToId(extruder_stack_file)
|
||||
|
||||
container_stacks = self._container_registry.findContainerStacks(id = container_id)
|
||||
if container_stacks:
|
||||
# this container stack already exists, try to resolve
|
||||
stack = container_stacks[0]
|
||||
if self._resolve_strategies["machine"] == "override":
|
||||
pass # do nothing
|
||||
elif self._resolve_strategies["machine"] == "new":
|
||||
# create a new extruder stack from this one
|
||||
new_id = self.getNewId(container_id)
|
||||
stack = ExtruderStack(new_id)
|
||||
stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
|
||||
|
||||
# Ensure a unique ID and name
|
||||
stack._id = new_id
|
||||
|
||||
self._container_registry.addContainer(stack)
|
||||
extruder_stacks_added.append(stack)
|
||||
else:
|
||||
if self._resolve_strategies["machine"] == "override":
|
||||
global_stacks = self._container_registry.findContainerStacks(id = global_stack_id_original)
|
||||
# deserialize new extruder stack over the current ones
|
||||
if global_stacks:
|
||||
old_extruder_stack_id = global_stacks[0].extruders[index].getId()
|
||||
# HACK delete file
|
||||
self._container_registry._deleteFiles(global_stacks[0].extruders[index])
|
||||
global_stacks[0].extruders[index].deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
|
||||
# HACK
|
||||
global_stacks[0]._extruders = global_stacks[0]._extruders[:2]
|
||||
# HACK update cache
|
||||
del self._container_registry._id_container_cache[old_extruder_stack_id]
|
||||
new_extruder_stack_id = global_stacks[0].extruders[index].getId()
|
||||
self._container_registry._id_container_cache[new_extruder_stack_id] = global_stacks[0].extruders[index]
|
||||
|
||||
stack = global_stacks[0].extruders[index]
|
||||
else:
|
||||
Logger.log("w", "Could not find global stack, while I expected it: %s" % global_stack_id_original)
|
||||
elif self._resolve_strategies["machine"] == "new":
|
||||
# container not found, create a new one
|
||||
stack = ExtruderStack(container_id)
|
||||
stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
|
||||
self._container_registry.addContainer(stack)
|
||||
extruder_stacks_added.append(stack)
|
||||
else:
|
||||
Logger.log("w", "Unknown resolve strategy: %s" % str(self._resolve_strategies["machine"]))
|
||||
|
||||
if global_stack_need_rename:
|
||||
if stack.getMetaDataEntry("machine"):
|
||||
stack.setMetaDataEntry("machine", global_stack_id_new)
|
||||
extruder_stacks.append(stack)
|
||||
|
||||
except:
|
||||
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
|
||||
# Something went really wrong. Try to remove any data that we added.
|
||||
for container in extruder_stacks:
|
||||
self._container_registry.removeContainer(container.getId())
|
||||
|
||||
return None
|
||||
|
||||
# --
|
||||
# load global stack file
|
||||
try:
|
||||
# Check if a stack by this ID already exists;
|
||||
@ -541,82 +550,185 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
stack.deserialize(archive.open(global_stack_file).read().decode("utf-8"))
|
||||
container_stacks_added.append(stack)
|
||||
self._container_registry.addContainer(stack)
|
||||
containers_added.append(stack)
|
||||
|
||||
global_stack = stack
|
||||
Job.yieldThread()
|
||||
except:
|
||||
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
|
||||
# Something went really wrong. Try to remove any data that we added.
|
||||
for container in containers_added:
|
||||
self._container_registry.removeContainer(container.getId())
|
||||
return
|
||||
|
||||
# --
|
||||
# load extruder stack files
|
||||
try:
|
||||
for index, extruder_stack_file in enumerate(extruder_stack_files):
|
||||
container_id = self._stripFileToId(extruder_stack_file)
|
||||
|
||||
container_stacks = self._container_registry.findContainerStacks(id = container_id)
|
||||
if container_stacks:
|
||||
# this container stack already exists, try to resolve
|
||||
stack = container_stacks[0]
|
||||
if self._resolve_strategies["machine"] == "override":
|
||||
pass # do nothing
|
||||
elif self._resolve_strategies["machine"] == "new":
|
||||
# create a new extruder stack from this one
|
||||
new_id = self.getNewId(container_id)
|
||||
stack = ExtruderStack(new_id)
|
||||
stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
|
||||
|
||||
# Ensure a unique ID and name
|
||||
stack._id = new_id
|
||||
|
||||
self._container_registry.addContainer(stack)
|
||||
extruder_stacks_added.append(stack)
|
||||
containers_added.append(stack)
|
||||
else:
|
||||
if self._resolve_strategies["machine"] == "override":
|
||||
global_stacks = self._container_registry.findContainerStacks(id = global_stack_id_original)
|
||||
# deserialize new extruder stack over the current ones
|
||||
if global_stacks:
|
||||
old_extruder_stack_id = global_stacks[0].extruders[index].getId()
|
||||
# HACK delete file
|
||||
self._container_registry._deleteFiles(global_stacks[0].extruders[index])
|
||||
global_stacks[0].extruders[index].deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
|
||||
# HACK
|
||||
global_stacks[0]._extruders = global_stacks[0]._extruders[:2]
|
||||
# HACK update cache
|
||||
del self._container_registry._id_container_cache[old_extruder_stack_id]
|
||||
new_extruder_stack_id = global_stacks[0].extruders[index].getId()
|
||||
self._container_registry._id_container_cache[new_extruder_stack_id] = global_stacks[0].extruders[index]
|
||||
|
||||
stack = global_stacks[0].extruders[index]
|
||||
else:
|
||||
Logger.log("w", "Could not find global stack, while I expected it: %s" % global_stack_id_original)
|
||||
elif self._resolve_strategies["machine"] == "new":
|
||||
# container not found, create a new one
|
||||
stack = ExtruderStack(container_id)
|
||||
stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
|
||||
self._container_registry.addContainer(stack)
|
||||
extruder_stacks_added.append(stack)
|
||||
containers_added.append(stack)
|
||||
else:
|
||||
Logger.log("w", "Unknown resolve strategy: %s" % str(self._resolve_strategies["machine"]))
|
||||
|
||||
if global_stack_need_rename:
|
||||
if stack.getMetaDataEntry("machine"):
|
||||
stack.setMetaDataEntry("machine", global_stack_id_new)
|
||||
extruder_stacks.append(stack)
|
||||
except:
|
||||
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
|
||||
# Something went really wrong. Try to remove any data that we added.
|
||||
for container in containers_to_add:
|
||||
for container in containers_added:
|
||||
self._container_registry.removeContainer(container.getId())
|
||||
return
|
||||
|
||||
for container in container_stacks_added:
|
||||
self._container_registry.removeContainer(container.getId())
|
||||
|
||||
for container in extruder_stacks_added:
|
||||
self._container_registry.removeContainer(container.getId())
|
||||
|
||||
return None
|
||||
|
||||
#
|
||||
# Replacing the old containers if resolve is "new".
|
||||
# When resolve is "new", some containers will get renamed, so all the other containers that reference to those
|
||||
# MUST get updated too.
|
||||
#
|
||||
if self._resolve_strategies["machine"] == "new":
|
||||
# A new machine was made, but it was serialized with the wrong user container. Fix that now.
|
||||
for container in user_instance_containers:
|
||||
# replacing the container ID for user instance containers for the extruders
|
||||
extruder_id = container.getMetaDataEntry("extruder", None)
|
||||
if extruder_id:
|
||||
for extruder in extruder_stacks:
|
||||
if extruder.getId() == extruder_id:
|
||||
extruder.replaceContainer(0, container)
|
||||
extruder.userChanges = container
|
||||
continue
|
||||
|
||||
# replacing the container ID for user instance containers for the machine
|
||||
machine_id = container.getMetaDataEntry("machine", None)
|
||||
if machine_id:
|
||||
if global_stack.getId() == machine_id:
|
||||
global_stack.replaceContainer(0, container)
|
||||
global_stack.userChanges = container
|
||||
continue
|
||||
|
||||
for container_type in ("quality_changes", "definition_changes"):
|
||||
if self._resolve_strategies[container_type] == "new":
|
||||
for changes_container_type in ("quality_changes", "definition_changes"):
|
||||
if self._resolve_strategies[changes_container_type] == "new":
|
||||
# Quality changes needs to get a new ID, added to registry and to the right stacks
|
||||
for container in quality_and_definition_changes_instance_containers:
|
||||
old_id = container.getId()
|
||||
container.setName(self._container_registry.uniqueName(container.getName()))
|
||||
for each_changes_container in quality_and_definition_changes_instance_containers:
|
||||
old_id = each_changes_container.getId()
|
||||
each_changes_container.setName(self._container_registry.uniqueName(each_changes_container.getName()))
|
||||
# We're not really supposed to change the ID in normal cases, but this is an exception.
|
||||
container._id = self.getNewId(container.getId())
|
||||
each_changes_container._id = self.getNewId(each_changes_container.getId())
|
||||
|
||||
# The container was not added yet, as it didn't have an unique ID. It does now, so add it.
|
||||
self._container_registry.addContainer(container)
|
||||
self._container_registry.addContainer(each_changes_container)
|
||||
|
||||
# Replace the quality/definition changes container
|
||||
if container_type == "quality_changes":
|
||||
# Find the old (current) changes container in the global stack
|
||||
if changes_container_type == "quality_changes":
|
||||
old_container = global_stack.qualityChanges
|
||||
elif container_type == "definition_changes":
|
||||
elif changes_container_type == "definition_changes":
|
||||
old_container = global_stack.definitionChanges
|
||||
# old_container = global_stack.findContainer({"type": container_type})
|
||||
|
||||
# sanity checks
|
||||
# NOTE: The following cases SHOULD NOT happen!!!!
|
||||
if not old_container:
|
||||
Logger.log("e", "We try to get [%s] from the global stack [%s] but we got None instead!",
|
||||
changes_container_type, global_stack.getId())
|
||||
|
||||
# Replace the quality/definition changes container if it's in the GlobalStack
|
||||
# NOTE: we can get an empty container here, but the IDs will not match,
|
||||
# so this comparison is fine.
|
||||
if old_container.getId() == old_id:
|
||||
changes_index = global_stack.getContainerIndex(old_container)
|
||||
global_stack.replaceContainer(changes_index, container)
|
||||
if changes_container_type == "quality_changes":
|
||||
global_stack.qualityChanges = each_changes_container
|
||||
elif changes_container_type == "definition_changes":
|
||||
global_stack.definitionChanges = each_changes_container
|
||||
continue
|
||||
|
||||
for stack in extruder_stacks:
|
||||
old_container = stack.findContainer({"type": container_type})
|
||||
if old_container.getId() == old_id:
|
||||
changes_index = stack.getContainerIndex(old_container)
|
||||
stack.replaceContainer(changes_index, container)
|
||||
# Replace the quality/definition changes container if it's in one of the ExtruderStacks
|
||||
for each_extruder_stack in extruder_stacks:
|
||||
changes_container = None
|
||||
if changes_container_type == "quality_changes":
|
||||
changes_container = each_extruder_stack.qualityChanges
|
||||
elif changes_container_type == "definition_changes":
|
||||
changes_container = each_extruder_stack.definitionChanges
|
||||
|
||||
# sanity checks
|
||||
# NOTE: The following cases SHOULD NOT happen!!!!
|
||||
if not changes_container:
|
||||
Logger.log("e", "We try to get [%s] from the extruder stack [%s] but we got None instead!",
|
||||
changes_container_type, each_extruder_stack.getId())
|
||||
|
||||
# NOTE: we can get an empty container here, but the IDs will not match,
|
||||
# so this comparison is fine.
|
||||
if changes_container.getId() == old_id:
|
||||
if changes_container_type == "quality_changes":
|
||||
each_extruder_stack.qualityChanges = each_changes_container
|
||||
elif changes_container_type == "definition_changes":
|
||||
each_extruder_stack.definitionChanges = each_changes_container
|
||||
|
||||
if self._resolve_strategies["material"] == "new":
|
||||
for material in material_containers:
|
||||
old_material = global_stack.findContainer({"type": "material"})
|
||||
if old_material.getId() in self._id_mapping:
|
||||
material_index = global_stack.getContainerIndex(old_material)
|
||||
global_stack.replaceContainer(material_index, material)
|
||||
for each_material in material_containers:
|
||||
old_material = global_stack.material
|
||||
|
||||
# check if the old material container has been renamed to this material container ID
|
||||
# if the container hasn't been renamed, we do nothing.
|
||||
new_id = self._id_mapping.get(old_material.getId())
|
||||
if new_id is None or new_id != each_material.getId():
|
||||
continue
|
||||
|
||||
for stack in extruder_stacks:
|
||||
old_material = stack.findContainer({"type": "material"})
|
||||
if old_material.getId() in self._id_mapping:
|
||||
material_index = stack.getContainerIndex(old_material)
|
||||
stack.replaceContainer(material_index, material)
|
||||
if old_material.getId() in self._id_mapping:
|
||||
global_stack.material = each_material
|
||||
|
||||
for each_extruder_stack in extruder_stacks:
|
||||
old_material = each_extruder_stack.material
|
||||
|
||||
# check if the old material container has been renamed to this material container ID
|
||||
# if the container hasn't been renamed, we do nothing.
|
||||
new_id = self._id_mapping.get(old_material.getId())
|
||||
if new_id is None or new_id != each_material.getId():
|
||||
continue
|
||||
|
||||
if old_material.getId() in self._id_mapping:
|
||||
each_extruder_stack.material = each_material
|
||||
|
||||
if extruder_stacks:
|
||||
for stack in extruder_stacks:
|
||||
ExtruderManager.getInstance().registerExtruder(stack, global_stack.getId())
|
||||
|
@ -79,7 +79,7 @@ The initial and final printing temperatures reduce the amount of oozing during P
|
||||
Initial and final printing temperature settings have been tuned for higher quality results. For all materials the initial print temperature is 5 degrees above the default value.
|
||||
|
||||
*Printing temperature of the materials
|
||||
The printing temperature of the materials in the material profiles is now the same as the printing temperature for the Normal Quality profile.
|
||||
The printing temperature of the materials in the material profiles is now the same as the printing temperature for the Fine profile.
|
||||
|
||||
*Improved PLA-PVA layer adhesion
|
||||
The PVA jerk and acceleration have been optimized to improve the layer adhesion between PVA and PLA.
|
||||
|
@ -99,6 +99,7 @@ class MachineSettingsAction(MachineAction):
|
||||
definition = container_stack.getBottom()
|
||||
definition_changes_container.setDefinition(definition)
|
||||
definition_changes_container.addMetaDataEntry("type", "definition_changes")
|
||||
definition_changes_container.addMetaDataEntry("setting_version", definition.getMetaDataEntry("setting_version", default = 0))
|
||||
|
||||
self._container_registry.addContainer(definition_changes_container)
|
||||
container_stack.definitionChanges = definition_changes_container
|
||||
|
@ -63,17 +63,20 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand
|
||||
stack_nr = -1
|
||||
stack = None
|
||||
# Check from what stack we should copy the raw property of the setting from.
|
||||
if definition.limit_to_extruder != "-1" and self._stack.getProperty("machine_extruder_count", "value") > 1:
|
||||
# A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use.
|
||||
stack_nr = str(int(round(float(self._stack.getProperty(item, "limit_to_extruder")))))
|
||||
if self._stack.getProperty("machine_extruder_count", "value") > 1:
|
||||
if definition.limit_to_extruder != "-1":
|
||||
# A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use.
|
||||
stack_nr = str(int(round(float(self._stack.getProperty(item, "limit_to_extruder")))))
|
||||
|
||||
# Check if the found stack_number is in the extruder list of extruders.
|
||||
if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value") is not None:
|
||||
stack_nr = -1
|
||||
# Check if the found stack_number is in the extruder list of extruders.
|
||||
if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value") is not None:
|
||||
stack_nr = -1
|
||||
|
||||
# Use the found stack number to get the right stack to copy the value from.
|
||||
if stack_nr in ExtruderManager.getInstance().extruderIds:
|
||||
stack = ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0]
|
||||
# Use the found stack number to get the right stack to copy the value from.
|
||||
if stack_nr in ExtruderManager.getInstance().extruderIds:
|
||||
stack = ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0]
|
||||
else:
|
||||
stack = self._stack
|
||||
|
||||
# Use the raw property to set the value (so the inheritance doesn't break)
|
||||
if stack is not None:
|
||||
|
@ -49,6 +49,7 @@ class UMOUpgradeSelection(MachineAction):
|
||||
definition = global_container_stack.getBottom()
|
||||
definition_changes_container.setDefinition(definition)
|
||||
definition_changes_container.addMetaDataEntry("type", "definition_changes")
|
||||
definition_changes_container.addMetaDataEntry("setting_version", definition.getMetaDataEntry("setting_version", default = 0))
|
||||
|
||||
UM.Settings.ContainerRegistry.ContainerRegistry.getInstance().addContainer(definition_changes_container)
|
||||
# Insert definition_changes between the definition and the variant
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import configparser #To get version numbers from config files.
|
||||
@ -70,8 +70,8 @@ _printer_translations_profiles = {
|
||||
# as a set for which profiles were built-in.
|
||||
_profile_translations = {
|
||||
"Low Quality": "low",
|
||||
"Normal Quality": "normal",
|
||||
"High Quality": "high",
|
||||
"Fine": "normal",
|
||||
"Extra Fine": "high",
|
||||
"Ulti Quality": "high", #This one doesn't have an equivalent. Map it to high.
|
||||
"abs_0.25_normal": "um2p_abs_0.25_normal",
|
||||
"abs_0.4_fast": "um2p_abs_0.4_fast",
|
||||
@ -249,7 +249,9 @@ class VersionUpgrade21to22(VersionUpgrade):
|
||||
def getCfgVersion(self, serialised):
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialised)
|
||||
return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||
return format_version * 1000000 + setting_version
|
||||
|
||||
## Gets the fallback quality to use for a specific machine-variant-material
|
||||
# combination.
|
||||
|
@ -18,10 +18,10 @@ def getMetaData():
|
||||
"api": 3
|
||||
},
|
||||
"version_upgrade": {
|
||||
# From To Upgrade function
|
||||
("profile", 1): ("quality", 2, upgrade.upgradeProfile),
|
||||
("machine_instance", 1): ("machine_stack", 2, upgrade.upgradeMachineInstance),
|
||||
("preferences", 2): ("preferences", 3, upgrade.upgradePreferences)
|
||||
# From To Upgrade function
|
||||
("profile", 1000000): ("quality", 2000000, upgrade.upgradeProfile),
|
||||
("machine_instance", 1000000): ("machine_stack", 2000000, upgrade.upgradeMachineInstance),
|
||||
("preferences", 2000000): ("preferences", 3000000, upgrade.upgradePreferences)
|
||||
},
|
||||
"sources": {
|
||||
"profile": {
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016 Ultimaker B.V.
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import configparser #To get version numbers from config files.
|
||||
@ -77,6 +77,7 @@ class VersionUpgrade22to24(VersionUpgrade):
|
||||
with open(variant_path, "r") as fhandle:
|
||||
variant_config.read_file(fhandle)
|
||||
|
||||
config_name = "Unknown Variant"
|
||||
if variant_config.has_section("general") and variant_config.has_option("general", "name"):
|
||||
config_name = variant_config.get("general", "name")
|
||||
if config_name.endswith("_variant"):
|
||||
@ -144,4 +145,6 @@ class VersionUpgrade22to24(VersionUpgrade):
|
||||
def getCfgVersion(self, serialised):
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialised)
|
||||
return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||
return format_version * 1000000 + setting_version
|
||||
|
@ -18,10 +18,10 @@ def getMetaData():
|
||||
"api": 3
|
||||
},
|
||||
"version_upgrade": {
|
||||
# From To Upgrade function
|
||||
("machine_instance", 2): ("machine_stack", 3, upgrade.upgradeMachineInstance),
|
||||
("extruder_train", 2): ("extruder_train", 3, upgrade.upgradeExtruderTrain),
|
||||
("preferences", 3): ("preferences", 4, upgrade.upgradePreferences)
|
||||
# From To Upgrade function
|
||||
("machine_instance", 2000000): ("machine_stack", 3000000, upgrade.upgradeMachineInstance),
|
||||
("extruder_train", 2000000): ("extruder_train", 3000000, upgrade.upgradeExtruderTrain),
|
||||
("preferences", 3000000): ("preferences", 4000000, upgrade.upgradePreferences)
|
||||
|
||||
},
|
||||
"sources": {
|
||||
|
@ -7,7 +7,8 @@ import io #To serialise configparser output to a string.
|
||||
from UM.VersionUpgrade import VersionUpgrade
|
||||
|
||||
_removed_settings = { #Settings that were removed in 2.5.
|
||||
"start_layers_at_same_position"
|
||||
"start_layers_at_same_position",
|
||||
"sub_div_rad_mult"
|
||||
}
|
||||
|
||||
_split_settings = { #These settings should be copied to all settings it was split into.
|
||||
@ -15,13 +16,13 @@ _split_settings = { #These settings should be copied to all settings it was spli
|
||||
}
|
||||
|
||||
## A collection of functions that convert the configuration of the user in Cura
|
||||
# 2.4 to a configuration for Cura 2.5.
|
||||
# 2.5 to a configuration for Cura 2.6.
|
||||
#
|
||||
# All of these methods are essentially stateless.
|
||||
class VersionUpgrade24to25(VersionUpgrade):
|
||||
## Gets the version number from a CFG file in Uranium's 2.4 format.
|
||||
class VersionUpgrade25to26(VersionUpgrade):
|
||||
## Gets the version number from a CFG file in Uranium's 2.5 format.
|
||||
#
|
||||
# Since the format may change, this is implemented for the 2.4 format only
|
||||
# Since the format may change, this is implemented for the 2.5 format only
|
||||
# and needs to be included in the version upgrade system rather than
|
||||
# globally in Uranium.
|
||||
#
|
||||
@ -33,9 +34,11 @@ class VersionUpgrade24to25(VersionUpgrade):
|
||||
def getCfgVersion(self, serialised):
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialised)
|
||||
return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||
return format_version * 1000000 + setting_version
|
||||
|
||||
## Upgrades the preferences file from version 2.4 to 2.5.
|
||||
## Upgrades the preferences file from version 2.5 to 2.6.
|
||||
#
|
||||
# \param serialised The serialised form of a preferences file.
|
||||
# \param filename The name of the file to upgrade.
|
||||
@ -66,7 +69,7 @@ class VersionUpgrade24to25(VersionUpgrade):
|
||||
parser.write(output)
|
||||
return [filename], [output.getvalue()]
|
||||
|
||||
## Upgrades an instance container from version 2.4 to 2.5.
|
||||
## Upgrades an instance container from version 2.5 to 2.6.
|
||||
#
|
||||
# \param serialised The serialised form of a quality profile.
|
||||
# \param filename The name of the file to upgrade.
|
||||
@ -85,7 +88,7 @@ class VersionUpgrade24to25(VersionUpgrade):
|
||||
|
||||
#Change the version number in the file.
|
||||
if parser.has_section("general"):
|
||||
parser["general"]["version"] = "3"
|
||||
parser["general"]["setting_version"] = "1"
|
||||
|
||||
#Re-serialise the file.
|
||||
output = io.StringIO()
|
@ -1,28 +1,28 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from . import VersionUpgrade24to25
|
||||
from . import VersionUpgrade25to26
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
upgrade = VersionUpgrade24to25.VersionUpgrade24to25()
|
||||
upgrade = VersionUpgrade25to26.VersionUpgrade25to26()
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
"plugin": {
|
||||
"name": catalog.i18nc("@label", "Version Upgrade 2.4 to 2.5"),
|
||||
"name": catalog.i18nc("@label", "Version Upgrade 2.5 to 2.6"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Upgrades configurations from Cura 2.4 to Cura 2.5."),
|
||||
"description": catalog.i18nc("@info:whatsthis", "Upgrades configurations from Cura 2.5 to Cura 2.6."),
|
||||
"api": 3
|
||||
},
|
||||
"version_upgrade": {
|
||||
# From To Upgrade function
|
||||
("preferences", 4): ("preferences", 5, upgrade.upgradePreferences),
|
||||
("quality", 2): ("quality", 3, upgrade.upgradeInstanceContainer),
|
||||
("variant", 2): ("variant", 3, upgrade.upgradeInstanceContainer), #We can re-use upgradeContainerStack since there is nothing specific to quality, variant or user profiles being changed.
|
||||
("user", 2): ("user", 3, upgrade.upgradeInstanceContainer)
|
||||
# From To Upgrade function
|
||||
("preferences", 4000000): ("preferences", 4000001, upgrade.upgradePreferences),
|
||||
("quality", 2000000): ("quality", 2000001, upgrade.upgradeInstanceContainer),
|
||||
("variant", 2000000): ("variant", 2000001, upgrade.upgradeInstanceContainer), #We can re-use upgradeContainerStack since there is nothing specific to quality, variant or user profiles being changed.
|
||||
("user", 2000000): ("user", 2000001, upgrade.upgradeInstanceContainer)
|
||||
},
|
||||
"sources": {
|
||||
"quality": {
|
||||
@ -41,5 +41,4 @@ def getMetaData():
|
||||
}
|
||||
|
||||
def register(app):
|
||||
return {}
|
||||
return { "version_upgrade": upgrade }
|
@ -4,12 +4,12 @@
|
||||
import configparser #To check whether the appropriate exceptions are raised.
|
||||
import pytest #To register tests with.
|
||||
|
||||
import VersionUpgrade24to25 #The module we're testing.
|
||||
import VersionUpgrade25to26 #The module we're testing.
|
||||
|
||||
## Creates an instance of the upgrader to test with.
|
||||
@pytest.fixture
|
||||
def upgrader():
|
||||
return VersionUpgrade24to25.VersionUpgrade24to25()
|
||||
return VersionUpgrade25to26.VersionUpgrade25to26()
|
||||
|
||||
test_cfg_version_good_data = [
|
||||
{
|
||||
@ -17,7 +17,7 @@ test_cfg_version_good_data = [
|
||||
"file_data": """[general]
|
||||
version = 1
|
||||
""",
|
||||
"version": 1
|
||||
"version": 1000000
|
||||
},
|
||||
{
|
||||
"test_name": "Other Data Around",
|
||||
@ -31,14 +31,32 @@ version = 3
|
||||
layer_height = 0.12
|
||||
infill_sparse_density = 42
|
||||
""",
|
||||
"version": 3
|
||||
"version": 3000000
|
||||
},
|
||||
{
|
||||
"test_name": "Negative Version", #Why not?
|
||||
"file_data": """[general]
|
||||
version = -20
|
||||
""",
|
||||
"version": -20
|
||||
"version": -20000000
|
||||
},
|
||||
{
|
||||
"test_name": "Setting Version",
|
||||
"file_data": """[general]
|
||||
version = 1
|
||||
[metadata]
|
||||
setting_version = 1
|
||||
""",
|
||||
"version": 1000001
|
||||
},
|
||||
{
|
||||
"test_name": "Negative Setting Version",
|
||||
"file_data": """[general]
|
||||
version = 1
|
||||
[metadata]
|
||||
setting_version = -3
|
||||
""",
|
||||
"version": 999997
|
||||
}
|
||||
]
|
||||
|
||||
@ -77,6 +95,22 @@ true = false
|
||||
"test_name": "Not a Number",
|
||||
"file_data": """[general]
|
||||
version = not-a-text-version-number
|
||||
""",
|
||||
"exception": ValueError
|
||||
},
|
||||
{
|
||||
"test_name": "Setting Value NaN",
|
||||
"file_data": """[general]
|
||||
version = 4
|
||||
[metadata]
|
||||
setting_version = latest_or_something
|
||||
""",
|
||||
"exception": ValueError
|
||||
},
|
||||
{
|
||||
"test_name": "Major-Minor",
|
||||
"file_data": """[general]
|
||||
version = 1.2
|
||||
""",
|
||||
"exception": ValueError
|
||||
}
|
||||
@ -121,7 +155,7 @@ foo = bar
|
||||
}
|
||||
]
|
||||
|
||||
## Tests whether the settings that should be removed are removed for the 2.5
|
||||
## Tests whether the settings that should be removed are removed for the 2.6
|
||||
# version of preferences.
|
||||
@pytest.mark.parametrize("data", test_upgrade_preferences_removed_settings_data)
|
||||
def test_upgradePreferencesRemovedSettings(data, upgrader):
|
||||
@ -137,7 +171,7 @@ def test_upgradePreferencesRemovedSettings(data, upgrader):
|
||||
upgraded_preferences = upgraded_preferences[0]
|
||||
|
||||
#Find whether the removed setting is removed from the file now.
|
||||
settings -= VersionUpgrade24to25._removed_settings
|
||||
settings -= VersionUpgrade25to26._removed_settings
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(upgraded_preferences)
|
||||
assert (parser.has_section("general") and "visible_settings" in parser["general"]) == (len(settings) > 0) #If there are settings, there must also be a preference.
|
||||
@ -166,7 +200,7 @@ type = instance_container
|
||||
}
|
||||
]
|
||||
|
||||
## Tests whether the settings that should be removed are removed for the 2.5
|
||||
## Tests whether the settings that should be removed are removed for the 2.6
|
||||
# version of instance containers.
|
||||
@pytest.mark.parametrize("data", test_upgrade_instance_container_removed_settings_data)
|
||||
def test_upgradeInstanceContainerRemovedSettings(data, upgrader):
|
||||
@ -182,7 +216,7 @@ def test_upgradeInstanceContainerRemovedSettings(data, upgrader):
|
||||
upgraded_container = upgraded_container[0]
|
||||
|
||||
#Find whether the forbidden setting is still in the container.
|
||||
settings -= VersionUpgrade24to25._removed_settings
|
||||
settings -= VersionUpgrade25to26._removed_settings
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(upgraded_container)
|
||||
assert parser.has_section("values") == (len(settings) > 0) #If there are settings, there must also be the values category.
|
@ -21,6 +21,20 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
super().__init__(container_id, *args, **kwargs)
|
||||
self._inherited_files = []
|
||||
|
||||
## Translates the version number in the XML files to the setting_version
|
||||
# metadata entry.
|
||||
#
|
||||
# Since the two may increment independently we need a way to say which
|
||||
# versions of the XML specification are compatible with our setting data
|
||||
# version numbers.
|
||||
#
|
||||
# \param xml_version: The version number found in an XML file.
|
||||
# \return The corresponding setting_version.
|
||||
def xmlVersionToSettingVersion(self, xml_version: str) -> int:
|
||||
if xml_version == "1.3":
|
||||
return 1
|
||||
return 0 #Older than 1.3.
|
||||
|
||||
def getInheritedFiles(self):
|
||||
return self._inherited_files
|
||||
|
||||
@ -145,10 +159,10 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
|
||||
for key, value in metadata.items():
|
||||
builder.start(key)
|
||||
# Normally value is a string.
|
||||
# Nones get handled well.
|
||||
if isinstance(value, bool):
|
||||
value = str(value) # parseBool in deserialize expects 'True'.
|
||||
if value is not None: #Nones get handled well by the builder.
|
||||
#Otherwise the builder always expects a string.
|
||||
#Deserialize expects the stringified version.
|
||||
value = str(value)
|
||||
builder.data(value)
|
||||
builder.end(key)
|
||||
|
||||
@ -409,6 +423,10 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
inherited = self._resolveInheritance(inherits.text)
|
||||
data = self._mergeXML(inherited, data)
|
||||
|
||||
if "version" in data.attrib:
|
||||
meta_data["setting_version"] = self.xmlVersionToSettingVersion(data.attrib["version"])
|
||||
else:
|
||||
meta_data["setting_version"] = self.xmlVersionToSettingVersion("1.2") #1.2 and lower didn't have that version number there yet.
|
||||
metadata = data.iterfind("./um:metadata/*", self.__namespaces)
|
||||
for entry in metadata:
|
||||
tag_name = _tag_without_namespace(entry)
|
||||
@ -441,8 +459,7 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
tag_name = _tag_without_namespace(entry)
|
||||
property_values[tag_name] = entry.text
|
||||
|
||||
diameter = float(property_values.get("diameter", 2.85)) # In mm
|
||||
density = float(property_values.get("density", 1.3)) # In g/cm3
|
||||
meta_data["approximate_diameter"] = round(float(property_values.get("diameter", 2.85))) # In mm
|
||||
meta_data["properties"] = property_values
|
||||
|
||||
self.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0])
|
||||
@ -461,7 +478,6 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
Logger.log("d", "Unsupported material setting %s", key)
|
||||
self._cached_values = global_setting_values
|
||||
|
||||
meta_data["approximate_diameter"] = round(diameter)
|
||||
meta_data["compatible"] = global_compatibility
|
||||
self.setMetaData(meta_data)
|
||||
self._dirty = False
|
||||
|
@ -7,6 +7,7 @@
|
||||
"type": "extruder",
|
||||
"author": "Ultimaker B.V.",
|
||||
"manufacturer": "Ultimaker",
|
||||
"setting_version": 1,
|
||||
"visible": false
|
||||
},
|
||||
"settings":
|
||||
|
@ -8,6 +8,7 @@
|
||||
"author": "Ultimaker B.V.",
|
||||
"category": "Ultimaker",
|
||||
"manufacturer": "Ultimaker",
|
||||
"setting_version": 1,
|
||||
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g",
|
||||
"visible": false,
|
||||
"has_materials": true,
|
||||
@ -1217,19 +1218,6 @@
|
||||
"enabled": "infill_sparse_density > 0 and spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"sub_div_rad_mult":
|
||||
{
|
||||
"label": "Cubic Subdivision Radius",
|
||||
"description": "A multiplier on the radius from the center of each cube to check for the boundary of the model, as to decide whether this cube should be subdivided. Larger values lead to more subdivisions, i.e. more small cubes.",
|
||||
"unit": "%",
|
||||
"type": "float",
|
||||
"default_value": 100,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "100",
|
||||
"maximum_value_warning": "200",
|
||||
"enabled": "infill_sparse_density > 0 and infill_pattern == 'cubicsubdiv'",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"sub_div_rad_add":
|
||||
{
|
||||
"label": "Cubic Subdivision Shell",
|
||||
@ -1335,7 +1323,7 @@
|
||||
"default_value": 0,
|
||||
"type": "int",
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "4",
|
||||
"maximum_value_warning": "5",
|
||||
"maximum_value": "0 if spaghetti_infill_enabled else (999999 if infill_line_distance == 0 else (20 - math.log(infill_line_distance) / math.log(2)))",
|
||||
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv' and not spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
@ -3636,7 +3624,7 @@
|
||||
"none": "None"
|
||||
},
|
||||
"default_value": "brim",
|
||||
"resolve": "'raft' if 'raft' in extruderValues('adhesion_type') else ('brim' if 'brim' in extruderValues('adhesion_type') else 'skirt')",
|
||||
"limit_to_extruder": "adhesion_extruder_nr",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false
|
||||
},
|
||||
@ -4583,7 +4571,7 @@
|
||||
"magic_spiralize":
|
||||
{
|
||||
"label": "Spiralize Outer Contour",
|
||||
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid model into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
|
||||
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid model into a single walled print with a solid bottom. This feature should only be enabled when each layer only contains a single part.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"settable_per_mesh": false,
|
||||
@ -4595,7 +4583,9 @@
|
||||
"description": "Smooth the spiralized contours to reduce the visibility of the Z seam (the Z-seam should be barely visible on the print but will still be visible in the layer view). Note that smoothing will tend to blur fine surface details.",
|
||||
"type": "bool",
|
||||
"default_value": true,
|
||||
"enabled": "magic_spiralize"
|
||||
"enabled": "magic_spiralize",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -11,8 +11,7 @@
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2.png",
|
||||
"platform": "ultimaker2_platform.obj",
|
||||
"platform_texture": "Ultimaker2Extendedbackplate.png",
|
||||
"supported_actions": ["UpgradeFirmware"]
|
||||
"platform_texture": "Ultimaker2Extendedbackplate.png"
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
|
4009
resources/i18n/jp/fdmprinter.def.json.po
Normal file
4009
resources/i18n/jp/fdmprinter.def.json.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -56,7 +56,6 @@ UM.Dialog
|
||||
{
|
||||
text: catalog.i18nc("@text:window", "You have customized some profile settings.\nWould you like to keep or discard those settings?")
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
font: UM.Theme.getFont("default")
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2015 Ultimaker B.V.
|
||||
// Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
import UM 1.1 as UM
|
||||
|
||||
UM.Dialog
|
||||
{
|
||||
id: base
|
||||
|
||||
//: Dialog title
|
||||
title: catalog.i18nc("@title:window", "Multiply Model")
|
||||
|
||||
minimumWidth: 400 * Screen.devicePixelRatio
|
||||
minimumHeight: 80 * Screen.devicePixelRatio
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
|
||||
property var objectId: 0;
|
||||
onAccepted: CuraApplication.multiplyObject(base.objectId, parseInt(copiesField.text))
|
||||
|
||||
property variant catalog: UM.I18nCatalog { name: "cura" }
|
||||
|
||||
signal reset()
|
||||
onReset: {
|
||||
copiesField.text = "1";
|
||||
copiesField.selectAll();
|
||||
copiesField.focus = true;
|
||||
}
|
||||
|
||||
Row
|
||||
{
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
|
||||
Label {
|
||||
text: "Number of copies:"
|
||||
anchors.verticalCenter: copiesField.verticalCenter
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: copiesField
|
||||
validator: RegExpValidator { regExp: /^\d{0,2}/ }
|
||||
maximumLength: 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rightButtons:
|
||||
[
|
||||
Button
|
||||
{
|
||||
text: catalog.i18nc("@action:button","OK")
|
||||
onClicked: base.accept()
|
||||
enabled: base.objectId != 0 && parseInt(copiesField.text) > 0
|
||||
},
|
||||
Button
|
||||
{
|
||||
text: catalog.i18nc("@action:button","Cancel")
|
||||
onClicked: base.reject()
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ UM.PreferencesPage
|
||||
append({ text: "Suomi", code: "fi" })
|
||||
append({ text: "Français", code: "fr" })
|
||||
append({ text: "Italiano", code: "it" })
|
||||
append({ text: "日本語", code: "jp" })
|
||||
append({ text: "Nederlands", code: "nl" })
|
||||
append({ text: "Português do Brasil", code: "ptbr" })
|
||||
append({ text: "Русский", code: "ru" })
|
||||
|
@ -24,66 +24,89 @@ TabView
|
||||
property double spoolLength: calculateSpoolLength()
|
||||
property real costPerMeter: calculateCostPerMeter()
|
||||
|
||||
property bool reevaluateLinkedMaterials: false
|
||||
property string linkedMaterialNames:
|
||||
{
|
||||
if (reevaluateLinkedMaterials)
|
||||
{
|
||||
reevaluateLinkedMaterials = false;
|
||||
}
|
||||
if(!base.containerId || !base.editingEnabled)
|
||||
{
|
||||
return ""
|
||||
}
|
||||
var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.containerId);
|
||||
return linkedMaterials.join(", ");
|
||||
}
|
||||
|
||||
Tab
|
||||
{
|
||||
title: catalog.i18nc("@title","Information")
|
||||
|
||||
anchors
|
||||
{
|
||||
leftMargin: UM.Theme.getSize("default_margin").width
|
||||
topMargin: UM.Theme.getSize("default_margin").height
|
||||
bottomMargin: UM.Theme.getSize("default_margin").height
|
||||
rightMargin: 0
|
||||
}
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
|
||||
ScrollView
|
||||
{
|
||||
id: scrollView
|
||||
anchors.fill: parent
|
||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
flickableItem.flickableDirection: Flickable.VerticalFlick
|
||||
frameVisible: true
|
||||
|
||||
property real columnWidth: Math.floor(viewport.width * 0.5) - UM.Theme.getSize("default_margin").width
|
||||
|
||||
Flow
|
||||
{
|
||||
id: containerGrid
|
||||
|
||||
width: base.width;
|
||||
x: UM.Theme.getSize("default_margin").width
|
||||
y: UM.Theme.getSize("default_lining").height
|
||||
|
||||
property real rowHeight: textField.height;
|
||||
width: base.width
|
||||
property real rowHeight: textField.height + UM.Theme.getSize("default_lining").height
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Display Name") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Display Name") }
|
||||
ReadOnlyTextField
|
||||
{
|
||||
id: displayNameTextField;
|
||||
width: base.secondColumnWidth;
|
||||
width: scrollView.columnWidth;
|
||||
text: properties.name;
|
||||
readOnly: !base.editingEnabled;
|
||||
onEditingFinished: base.setName(properties.name, text)
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Brand") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Brand") }
|
||||
ReadOnlyTextField
|
||||
{
|
||||
id: textField;
|
||||
width: base.secondColumnWidth;
|
||||
width: scrollView.columnWidth;
|
||||
text: properties.supplier;
|
||||
readOnly: !base.editingEnabled;
|
||||
onEditingFinished: base.setMetaDataEntry("brand", properties.supplier, text)
|
||||
onEditingFinished:
|
||||
{
|
||||
base.setMetaDataEntry("brand", properties.supplier, text);
|
||||
pane.objectList.currentIndex = pane.getIndexById(base.containerId);
|
||||
}
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Material Type") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Material Type") }
|
||||
ReadOnlyTextField
|
||||
{
|
||||
width: base.secondColumnWidth;
|
||||
width: scrollView.columnWidth;
|
||||
text: properties.material_type;
|
||||
readOnly: !base.editingEnabled;
|
||||
onEditingFinished: base.setMetaDataEntry("material", properties.material_type, text)
|
||||
onEditingFinished:
|
||||
{
|
||||
base.setMetaDataEntry("material", properties.material_type, text);
|
||||
pane.objectList.currentIndex = pane.getIndexById(base.containerId)
|
||||
}
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") }
|
||||
|
||||
Row
|
||||
{
|
||||
width: base.secondColumnWidth;
|
||||
width: scrollView.columnWidth;
|
||||
height: parent.rowHeight;
|
||||
spacing: UM.Theme.getSize("default_margin").width/2
|
||||
|
||||
@ -115,11 +138,11 @@ TabView
|
||||
|
||||
Label { width: parent.width; height: parent.rowHeight; font.bold: true; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Properties") }
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Density") }
|
||||
ReadOnlySpinBox
|
||||
{
|
||||
id: densitySpinBox
|
||||
width: base.secondColumnWidth
|
||||
width: scrollView.columnWidth
|
||||
value: properties.density
|
||||
decimals: 2
|
||||
suffix: " g/cm³"
|
||||
@ -130,11 +153,11 @@ TabView
|
||||
onValueChanged: updateCostPerMeter()
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Diameter") }
|
||||
ReadOnlySpinBox
|
||||
{
|
||||
id: diameterSpinBox
|
||||
width: base.secondColumnWidth
|
||||
width: scrollView.columnWidth
|
||||
value: properties.diameter
|
||||
decimals: 2
|
||||
suffix: " mm"
|
||||
@ -145,11 +168,11 @@ TabView
|
||||
onValueChanged: updateCostPerMeter()
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament Cost") }
|
||||
SpinBox
|
||||
{
|
||||
id: spoolCostSpinBox
|
||||
width: base.secondColumnWidth
|
||||
width: scrollView.columnWidth
|
||||
value: base.getMaterialPreferenceValue(properties.guid, "spool_cost")
|
||||
prefix: base.currency + " "
|
||||
decimals: 2
|
||||
@ -161,11 +184,11 @@ TabView
|
||||
}
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") }
|
||||
SpinBox
|
||||
{
|
||||
id: spoolWeightSpinBox
|
||||
width: base.secondColumnWidth
|
||||
width: scrollView.columnWidth
|
||||
value: base.getMaterialPreferenceValue(properties.guid, "spool_weight")
|
||||
suffix: " g"
|
||||
stepSize: 100
|
||||
@ -178,24 +201,45 @@ TabView
|
||||
}
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") }
|
||||
Label
|
||||
{
|
||||
width: base.secondColumnWidth
|
||||
width: scrollView.columnWidth
|
||||
text: "~ %1 m".arg(Math.round(base.spoolLength))
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
height: parent.rowHeight
|
||||
}
|
||||
|
||||
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter") }
|
||||
Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Cost per Meter") }
|
||||
Label
|
||||
{
|
||||
width: base.secondColumnWidth
|
||||
width: scrollView.columnWidth
|
||||
text: "~ %1 %2/m".arg(base.costPerMeter.toFixed(2)).arg(base.currency)
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
height: parent.rowHeight
|
||||
}
|
||||
|
||||
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height; visible: unlinkMaterialButton.visible }
|
||||
Label
|
||||
{
|
||||
width: 2 * scrollView.columnWidth
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
text: catalog.i18nc("@label", "This material is linked to %1 and shares some of its properties.").arg(base.linkedMaterialNames)
|
||||
wrapMode: Text.WordWrap
|
||||
visible: unlinkMaterialButton.visible
|
||||
}
|
||||
Button
|
||||
{
|
||||
id: unlinkMaterialButton
|
||||
text: catalog.i18nc("@label", "Unlink Material")
|
||||
visible: base.linkedMaterialNames != ""
|
||||
onClicked:
|
||||
{
|
||||
Cura.ContainerManager.unlinkMaterial(base.containerId)
|
||||
base.reevaluateLinkedMaterials = true
|
||||
}
|
||||
}
|
||||
|
||||
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
|
||||
|
||||
Label { width: parent.width; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Description") }
|
||||
@ -203,7 +247,7 @@ TabView
|
||||
ReadOnlyTextArea
|
||||
{
|
||||
text: properties.description;
|
||||
width: base.firstColumnWidth + base.secondColumnWidth
|
||||
width: 2 * scrollView.columnWidth
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
readOnly: !base.editingEnabled;
|
||||
@ -216,13 +260,15 @@ TabView
|
||||
ReadOnlyTextArea
|
||||
{
|
||||
text: properties.adhesion_info;
|
||||
width: base.firstColumnWidth + base.secondColumnWidth
|
||||
width: 2 * scrollView.columnWidth
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
readOnly: !base.editingEnabled;
|
||||
|
||||
onEditingFinished: base.setMetaDataEntry("adhesion_info", properties.adhesion_info, text)
|
||||
}
|
||||
|
||||
Item { width: parent.width; height: UM.Theme.getSize("default_margin").height }
|
||||
}
|
||||
|
||||
function updateCostPerMeter()
|
||||
@ -266,8 +312,10 @@ TabView
|
||||
{
|
||||
id: label
|
||||
width: base.firstColumnWidth;
|
||||
height: spinBox.height
|
||||
height: spinBox.height + UM.Theme.getSize("default_lining").height
|
||||
text: model.label
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
ReadOnlySpinBox
|
||||
{
|
||||
@ -380,6 +428,7 @@ TabView
|
||||
Cura.ContainerManager.setContainerName(base.containerId, new_value);
|
||||
// update material name label. not so pretty, but it works
|
||||
materialProperties.name = new_value;
|
||||
pane.objectList.currentIndex = pane.getIndexById(base.containerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,12 @@ UM.ManagementPage
|
||||
|
||||
title: catalog.i18nc("@title:tab", "Materials");
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
// Workaround to make sure all of the items are visible
|
||||
objectList.positionViewAtBeginning();
|
||||
}
|
||||
|
||||
model: UM.InstanceContainersModel
|
||||
{
|
||||
filter:
|
||||
@ -81,6 +87,7 @@ UM.ManagementPage
|
||||
anchors.fill: parent;
|
||||
onClicked:
|
||||
{
|
||||
forceActiveFocus();
|
||||
if(!parent.ListView.isCurrentItem)
|
||||
{
|
||||
parent.ListView.view.currentIndex = index;
|
||||
@ -91,9 +98,11 @@ UM.ManagementPage
|
||||
}
|
||||
|
||||
activeId: Cura.MachineManager.activeMaterialId
|
||||
activeIndex: {
|
||||
activeIndex: getIndexById(activeId)
|
||||
function getIndexById(material_id)
|
||||
{
|
||||
for(var i = 0; i < model.rowCount(); i++) {
|
||||
if (model.getItem(i).id == Cura.MachineManager.activeMaterialId) {
|
||||
if (model.getItem(i).id == material_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -135,6 +144,24 @@ UM.ManagementPage
|
||||
}
|
||||
},
|
||||
Button
|
||||
{
|
||||
text: catalog.i18nc("@action:button", "Create")
|
||||
iconName: "list-add"
|
||||
onClicked:
|
||||
{
|
||||
var material_id = Cura.ContainerManager.createMaterial()
|
||||
if(material_id == "")
|
||||
{
|
||||
return
|
||||
}
|
||||
if(Cura.MachineManager.hasMaterials)
|
||||
{
|
||||
Cura.MachineManager.setActiveMaterial(material_id)
|
||||
}
|
||||
base.objectList.currentIndex = base.getIndexById(material_id);
|
||||
}
|
||||
},
|
||||
Button
|
||||
{
|
||||
text: catalog.i18nc("@action:button", "Duplicate");
|
||||
iconName: "list-add";
|
||||
@ -152,6 +179,7 @@ UM.ManagementPage
|
||||
{
|
||||
Cura.MachineManager.setActiveMaterial(material_id)
|
||||
}
|
||||
base.objectList.currentIndex = base.getIndexById(material_id);
|
||||
}
|
||||
},
|
||||
Button
|
||||
@ -206,6 +234,8 @@ UM.ManagementPage
|
||||
|
||||
properties: materialProperties
|
||||
containerId: base.currentItem != null ? base.currentItem.id : ""
|
||||
|
||||
property alias pane: base
|
||||
}
|
||||
|
||||
QtObject
|
||||
@ -251,6 +281,10 @@ UM.ManagementPage
|
||||
{
|
||||
Cura.ContainerManager.removeContainer(containers[i])
|
||||
}
|
||||
if(base.objectList.currentIndex > 0)
|
||||
{
|
||||
base.objectList.currentIndex--;
|
||||
}
|
||||
currentItem = base.model.getItem(base.objectList.currentIndex) // Refresh the current item.
|
||||
}
|
||||
}
|
||||
|
@ -45,17 +45,4 @@ Item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label
|
||||
{
|
||||
visible: base.readOnly
|
||||
text: textArea.text
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: textArea.__style ? textArea.__style.textMargin : 4
|
||||
|
||||
color: palette.buttonText
|
||||
}
|
||||
|
||||
SystemPalette { id: palette }
|
||||
}
|
||||
|
@ -53,7 +53,8 @@ Item
|
||||
id: infillCellRight
|
||||
|
||||
height: childrenRect.height;
|
||||
width: base.width * .55
|
||||
width: base.width * .5
|
||||
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
|
||||
anchors.left: infillCellLeft.right
|
||||
@ -124,7 +125,7 @@ Item
|
||||
{
|
||||
id: infillIcon
|
||||
anchors.fill: parent;
|
||||
anchors.margins: UM.Theme.getSize("infill_button_margin").width
|
||||
anchors.margins: 2
|
||||
|
||||
sourceSize.width: width
|
||||
sourceSize.height: width
|
||||
@ -184,47 +185,47 @@ Item
|
||||
Component.onCompleted:
|
||||
{
|
||||
infillModel.append({
|
||||
name: catalog.i18nc("@label", "Empty"),
|
||||
name: catalog.i18nc("@label", "0%"),
|
||||
percentage: 0,
|
||||
steps: 0,
|
||||
percentageMin: -1,
|
||||
percentageMax: 0,
|
||||
stepsMin: -1,
|
||||
stepsMax: 0,
|
||||
text: catalog.i18nc("@label", "Empty infill will leave your model hollow with low strength"),
|
||||
text: catalog.i18nc("@label", "Empty infill will leave your model hollow with low strength."),
|
||||
icon: "hollow"
|
||||
})
|
||||
infillModel.append({
|
||||
name: catalog.i18nc("@label", "Light"),
|
||||
name: catalog.i18nc("@label", "20%"),
|
||||
percentage: 20,
|
||||
steps: 0,
|
||||
percentageMin: 0,
|
||||
percentageMax: 30,
|
||||
stepsMin: -1,
|
||||
stepsMax: 0,
|
||||
text: catalog.i18nc("@label", "Light (20%) infill will give your model an average strength"),
|
||||
text: catalog.i18nc("@label", "Light (20%) infill will give your model an average strength."),
|
||||
icon: "sparse"
|
||||
})
|
||||
infillModel.append({
|
||||
name: catalog.i18nc("@label", "Dense"),
|
||||
name: catalog.i18nc("@label", "50%"),
|
||||
percentage: 50,
|
||||
steps: 0,
|
||||
percentageMin: 30,
|
||||
percentageMax: 70,
|
||||
stepsMin: -1,
|
||||
stepsMax: 0,
|
||||
text: catalog.i18nc("@label", "Dense (50%) infill will give your model an above average strength"),
|
||||
text: catalog.i18nc("@label", "Dense (50%) infill will give your model an above average strength."),
|
||||
icon: "dense"
|
||||
})
|
||||
infillModel.append({
|
||||
name: catalog.i18nc("@label", "Solid"),
|
||||
name: catalog.i18nc("@label", "100%"),
|
||||
percentage: 100,
|
||||
steps: 0,
|
||||
percentageMin: 70,
|
||||
percentageMax: 9999999999,
|
||||
stepsMin: -1,
|
||||
stepsMax: 0,
|
||||
text: catalog.i18nc("@label", "Solid (100%) infill will make your model completely solid"),
|
||||
text: catalog.i18nc("@label", "Solid (100%) infill will make your model completely solid."),
|
||||
icon: "solid"
|
||||
})
|
||||
infillModel.append({
|
||||
@ -236,7 +237,7 @@ Item
|
||||
stepsMin: 0,
|
||||
stepsMax: 9999999999,
|
||||
infill_layer_height: 1.5,
|
||||
text: catalog.i18nc("@label", "This will gradually increase the amount of infill towards the top"),
|
||||
text: catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top."),
|
||||
icon: "gradual"
|
||||
})
|
||||
}
|
||||
|
@ -13,13 +13,10 @@ UM.Dialog
|
||||
{
|
||||
title: catalog.i18nc("@title:window", "Save Project")
|
||||
|
||||
width: 550 * Screen.devicePixelRatio
|
||||
minimumWidth: 550 * Screen.devicePixelRatio
|
||||
width: 500
|
||||
height: 400
|
||||
|
||||
height: 350 * Screen.devicePixelRatio
|
||||
minimumHeight: 350 * Screen.devicePixelRatio
|
||||
|
||||
property int spacerHeight: 10 * Screen.devicePixelRatio
|
||||
property int spacerHeight: 10
|
||||
|
||||
property bool dontShowAgain: true
|
||||
|
||||
@ -42,7 +39,6 @@ UM.Dialog
|
||||
Item
|
||||
{
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20 * Screen.devicePixelRatio
|
||||
|
||||
UM.SettingDefinitionsModel
|
||||
{
|
||||
@ -232,42 +228,43 @@ UM.Dialog
|
||||
height: spacerHeight
|
||||
width: height
|
||||
}
|
||||
|
||||
CheckBox
|
||||
{
|
||||
id: dontShowAgainCheckbox
|
||||
text: catalog.i18nc("@action:label", "Don't show project summary on save again")
|
||||
checked: dontShowAgain
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CheckBox
|
||||
{
|
||||
id: dontShowAgainCheckbox
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
|
||||
text: catalog.i18nc("@action:label", "Don't show project summary on save again")
|
||||
checked: dontShowAgain
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: cancel_button
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: ok_button.left
|
||||
anchors.rightMargin: 2
|
||||
|
||||
text: catalog.i18nc("@action:button","Cancel");
|
||||
enabled: true
|
||||
onClicked: close()
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: ok_button
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
text: catalog.i18nc("@action:button","Save");
|
||||
enabled: true
|
||||
onClicked: {
|
||||
close()
|
||||
yes()
|
||||
}
|
||||
anchors.bottomMargin: - 0.5 * height
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
id: cancel_button
|
||||
text: catalog.i18nc("@action:button","Cancel");
|
||||
enabled: true
|
||||
onClicked: close()
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: ok_button.left
|
||||
anchors.bottomMargin: - 0.5 * height
|
||||
anchors.rightMargin:2
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = abax_pri3
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = abax_pri3
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 1
|
||||
quality_type = high
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.1
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = abax_pri3
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = abax_pri5
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = abax_pri5
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 1
|
||||
quality_type = high
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.1
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = abax_pri5
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = abax_titan
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = abax_titan
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_pla
|
||||
weight = 1
|
||||
quality_type = high
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.1
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = abax_titan
|
||||
|
||||
[metadata]
|
||||
@ -9,6 +8,7 @@ type = quality
|
||||
material = generic_pla
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_abs_175_cartesio_0.25_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_abs_175_cartesio_0.25_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_abs_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_abs_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
material = generic_abs_175_cartesio_0.8_mm
|
||||
weight = 3
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
material = generic_abs_175_cartesio_0.8_mm
|
||||
weight = 4
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_abs_175_cartesio_0.8_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_abs_175_cartesio_0.8_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = dsm_arnitel2045_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = dsm_arnitel2045_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
global_quality = True
|
||||
weight = 0
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.4
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
global_quality = True
|
||||
weight = 0
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.6
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
global_quality = True
|
||||
weight = 0
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.1
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
global_quality = True
|
||||
weight = 0
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
layer_height = 0.2
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_hips_175_cartesio_0.25_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_hips_175_cartesio_0.25_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_hips_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_hips_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
material = generic_hips_175_cartesio_0.8_mm
|
||||
weight = 3
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
material = generic_hips_175_cartesio_0.8_mm
|
||||
weight = 4
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_hips_175_cartesio_0.8_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_hips_175_cartesio_0.8_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_nylon_175_cartesio_0.25_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_nylon_175_cartesio_0.25_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_nylon_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_nylon_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
material = generic_nylon_175_cartesio_0.8_mm
|
||||
weight = 3
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
material = generic_nylon_175_cartesio_0.8_mm
|
||||
weight = 4
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_nylon_175_cartesio_0.8_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_nylon_175_cartesio_0.8_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_pc_175_cartesio_0.25_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_pc_175_cartesio_0.25_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_pc_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_pc_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
material = generic_pc_175_cartesio_0.8_mm
|
||||
weight = 3
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
material = generic_pc_175_cartesio_0.8_mm
|
||||
weight = 4
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_pc_175_cartesio_0.8_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_pc_175_cartesio_0.8_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_petg_175_cartesio_0.25_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_petg_175_cartesio_0.25_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_petg_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_petg_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
material = generic_petg_175_cartesio_0.8_mm
|
||||
weight = 3
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
material = generic_petg_175_cartesio_0.8_mm
|
||||
weight = 4
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_petg_175_cartesio_0.8_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_petg_175_cartesio_0.8_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_pla_175_cartesio_0.25_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_pla_175_cartesio_0.25_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.3
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_pla_175_cartesio_0.4_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_pla_175_cartesio_0.4_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.5
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = coarse
|
||||
material = generic_pla_175_cartesio_0.8_mm
|
||||
weight = 3
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = extra coarse
|
||||
material = generic_pla_175_cartesio_0.8_mm
|
||||
weight = 4
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = High Quality
|
||||
name = Extra Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = high
|
||||
material = generic_pla_175_cartesio_0.8_mm
|
||||
weight = 1
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
@ -1,6 +1,6 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Normal Quality
|
||||
name = Fine
|
||||
definition = cartesio
|
||||
|
||||
[metadata]
|
||||
@ -8,6 +8,7 @@ type = quality
|
||||
quality_type = normal
|
||||
material = generic_pla_175_cartesio_0.8_mm
|
||||
weight = 2
|
||||
setting_version = 1
|
||||
|
||||
[values]
|
||||
infill_line_width = 0.9
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user