mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-11 18:49:01 +08:00
Merge remote-tracking branch 'origin/feature_intent_container_tree' into feature_intent_upgrade
This commit is contained in:
commit
823f7e5921
@ -131,8 +131,8 @@ class MaterialManager(QObject):
|
||||
|
||||
# Fetch the available materials (ContainerNode) for the current active machine and extruder setup.
|
||||
materials = self.getAvailableMaterials(machine.definition.getId(), nozzle_name)
|
||||
compatible_material_diameter = str(round(extruder_stack.getCompatibleMaterialDiameter()))
|
||||
result = {key: material for key, material in materials.items() if material.container and material.container.getMetaDataEntry("approximate_diameter") == compatible_material_diameter}
|
||||
compatible_material_diameter = extruder_stack.getApproximateMaterialDiameter()
|
||||
result = {key: material for key, material in materials.items() if material.container and float(material.container.getMetaDataEntry("approximate_diameter")) == compatible_material_diameter}
|
||||
return result
|
||||
|
||||
#
|
||||
@ -171,9 +171,11 @@ class MaterialManager(QObject):
|
||||
def getMaterialNodeByType(self, global_stack: "GlobalStack", position: str, nozzle_name: str,
|
||||
buildplate_name: Optional[str], material_guid: str) -> Optional["MaterialNode"]:
|
||||
machine_definition = global_stack.definition
|
||||
variant_name = global_stack.extruders[position].variant.getName()
|
||||
extruder = global_stack.extruderList[int(position)]
|
||||
variant_name = extruder.variant.getName()
|
||||
approximate_diameter = extruder.getApproximateMaterialDiameter()
|
||||
|
||||
return self.getMaterialNode(machine_definition.getId(), variant_name, buildplate_name, 3, material_guid)
|
||||
return self.getMaterialNode(machine_definition.getId(), variant_name, buildplate_name, approximate_diameter, material_guid)
|
||||
|
||||
# There are 2 ways to get fallback materials;
|
||||
# - A fallback by type (@sa getFallbackMaterialIdByMaterialType), which adds the generic version of this material
|
||||
@ -266,128 +268,59 @@ class MaterialManager(QObject):
|
||||
return False
|
||||
return True
|
||||
|
||||
## Change the user-visible name of a material.
|
||||
# \param material_node The ContainerTree node of the material to rename.
|
||||
# \param name The new name for the material.
|
||||
@pyqtSlot("QVariant", str)
|
||||
def setMaterialName(self, material_node: "MaterialNode", name: str) -> None:
|
||||
if material_node.container is None:
|
||||
return
|
||||
root_material_id = material_node.container.getMetaDataEntry("base_file")
|
||||
if root_material_id is None:
|
||||
return
|
||||
if CuraContainerRegistry.getInstance().isReadOnly(root_material_id):
|
||||
Logger.log("w", "Cannot set name of read-only container %s.", root_material_id)
|
||||
return
|
||||
containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = root_material_id)
|
||||
containers[0].setName(name)
|
||||
return cura.CuraApplication.CuraApplication.getMaterialManagementModel().setMaterialName(material_node, name)
|
||||
|
||||
## Deletes a material from Cura.
|
||||
#
|
||||
# This function does not do any safety checking any more. Please call this
|
||||
# function only if:
|
||||
# - The material is not read-only.
|
||||
# - The material is not used in any stacks.
|
||||
# If the material was not lazy-loaded yet, this will fully load the
|
||||
# container. When removing this material node, all other materials with
|
||||
# the same base fill will also be removed.
|
||||
# \param material_node The material to remove.
|
||||
@pyqtSlot("QVariant")
|
||||
def removeMaterial(self, material_node: "MaterialNode") -> None:
|
||||
if material_node.container is None:
|
||||
return
|
||||
root_material_id = material_node.container.getMetaDataEntry("base_file")
|
||||
if root_material_id is not None:
|
||||
self.removeMaterialByRootId(root_material_id)
|
||||
return cura.CuraApplication.CuraApplication.getMaterialManagementModel().setMaterialName(material_node)
|
||||
|
||||
def duplicateMaterialByRootId(self, root_material_id: str, new_base_id: Optional[str] = None,
|
||||
new_metadata: Optional[Dict[str, Any]] = None) -> Optional[str]:
|
||||
container_registry = CuraContainerRegistry.getInstance()
|
||||
results = container_registry.findContainers(id=root_material_id)
|
||||
|
||||
if not results:
|
||||
Logger.log("i", "Unable to duplicate the material with id %s, because it doesn't exist.", root_material_id)
|
||||
return None
|
||||
|
||||
base_container = results[0]
|
||||
|
||||
# Ensure all settings are saved.
|
||||
cura.CuraApplication.CuraApplication.getInstance().saveSettings()
|
||||
|
||||
# Create a new ID & container to hold the data.
|
||||
new_containers = []
|
||||
if new_base_id is None:
|
||||
new_base_id = container_registry.uniqueName(base_container.getId())
|
||||
new_base_container = copy.deepcopy(base_container)
|
||||
new_base_container.getMetaData()["id"] = new_base_id
|
||||
new_base_container.getMetaData()["base_file"] = new_base_id
|
||||
if new_metadata is not None:
|
||||
for key, value in new_metadata.items():
|
||||
new_base_container.getMetaData()[key] = value
|
||||
new_containers.append(new_base_container)
|
||||
|
||||
# Clone all of them.
|
||||
for container_to_copy in container_registry.findContainers(base_file=root_material_id):
|
||||
if container_to_copy.getId() == root_material_id:
|
||||
continue # We already have that one, skip it
|
||||
new_id = new_base_id
|
||||
if container_to_copy.getMetaDataEntry("definition") != "fdmprinter":
|
||||
new_id += "_" + container_to_copy.getMetaDataEntry("definition")
|
||||
if container_to_copy.getMetaDataEntry("variant_name"):
|
||||
nozzle_name = container_to_copy.getMetaDataEntry("variant_name")
|
||||
new_id += "_" + nozzle_name.replace(" ", "_")
|
||||
|
||||
new_container = copy.deepcopy(container_to_copy)
|
||||
new_container.getMetaData()["id"] = new_id
|
||||
new_container.getMetaData()["base_file"] = new_base_id
|
||||
if new_metadata is not None:
|
||||
for key, value in new_metadata.items():
|
||||
new_container.getMetaData()[key] = value
|
||||
new_containers.append(new_container)
|
||||
|
||||
for container_to_add in new_containers:
|
||||
container_to_add.setDirty(True)
|
||||
container_registry.addContainer(container_to_add)
|
||||
|
||||
# if the duplicated material was favorite then the new material should also be added to favorite.
|
||||
if root_material_id in self.getFavorites():
|
||||
cura.CuraApplication.CuraApplication.getInstance().getMaterialManagementModel().addFavorite(new_base_id)
|
||||
|
||||
return new_base_id
|
||||
|
||||
#
|
||||
# Creates a duplicate of a material, which has the same GUID and base_file metadata.
|
||||
# Returns the root material ID of the duplicated material if successful.
|
||||
#
|
||||
@pyqtSlot("QVariant", result = str)
|
||||
def duplicateMaterial(self, material_node: MaterialNode, new_base_id: Optional[str] = None,
|
||||
new_metadata: Optional[Dict[str, Any]] = None) -> str:
|
||||
if material_node.container is None:
|
||||
Logger.log("e", "Material node {0} doesn't have container.".format(material_node.container_id))
|
||||
def duplicateMaterialByRootId(self, root_material_id: str, new_base_id: Optional[str] = None, new_metadata: Optional[Dict[str, Any]] = None) -> Optional[str]:
|
||||
result = cura.CuraApplication.CuraApplication.getInstance().getMaterialManagementModel().duplicateMaterialByBaseFile(root_material_id, new_base_id, new_metadata)
|
||||
if result is None:
|
||||
return "ERROR"
|
||||
root_material_id = cast(str, material_node.container.getMetaDataEntry("base_file", ""))
|
||||
new_material_id = self.duplicateMaterialByRootId(root_material_id, new_base_id, new_metadata)
|
||||
return new_material_id if new_material_id is not None else "ERROR"
|
||||
return result
|
||||
|
||||
# Create a new material by cloning Generic PLA for the current material diameter and generate a new GUID.
|
||||
# Returns the ID of the newly created material.
|
||||
## Creates a duplicate of a material with the same GUID and base_file
|
||||
# metadata.
|
||||
# \param material_node The node representing the material to duplicate.
|
||||
# \param new_base_id A new material ID for the base material. The IDs of
|
||||
# the submaterials will be based off this one. If not provided, a material
|
||||
# ID will be generated automatically.
|
||||
# \param new_metadata Metadata for the new material. If not provided, this
|
||||
# will be duplicated from the original material.
|
||||
# \return The root material ID of the duplicate material.
|
||||
@pyqtSlot("QVariant", result = str)
|
||||
def duplicateMaterial(self, material_node: MaterialNode, new_base_id: Optional[str] = None, new_metadata: Optional[Dict[str, Any]] = None) -> str:
|
||||
result = cura.CuraApplication.CuraApplication.getInstance().getMaterialManagementModel().duplicateMaterial(material_node, new_base_id, new_metadata)
|
||||
if result is None:
|
||||
return "ERROR"
|
||||
return result
|
||||
|
||||
## Create a new material by cloning the preferred material for the current
|
||||
# material diameter and generate a new GUID.
|
||||
#
|
||||
# The material type is explicitly left to be the one from the preferred
|
||||
# material, since this allows the user to still have SOME profiles to work
|
||||
# with.
|
||||
# \return The ID of the newly created material.
|
||||
@pyqtSlot(result = str)
|
||||
def createMaterial(self) -> str:
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
# Ensure all settings are saved.
|
||||
application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
application.saveSettings()
|
||||
|
||||
machine_manager = application.getMachineManager()
|
||||
extruder_stack = machine_manager.activeStack
|
||||
|
||||
global_stack = application.getGlobalContainerStack()
|
||||
if global_stack is None:
|
||||
Logger.log("e", "Global stack not present!")
|
||||
return "ERROR"
|
||||
machine_definition = global_stack.definition
|
||||
root_material_id = machine_definition.getMetaDataEntry("preferred_material", default = "generic_pla")
|
||||
|
||||
approximate_diameter = str(extruder_stack.approximateMaterialDiameter)
|
||||
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
|
||||
|
||||
# Create a new ID & container to hold the data.
|
||||
new_id = CuraContainerRegistry.getInstance().uniqueName("custom_material")
|
||||
new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
|
||||
"brand": catalog.i18nc("@label", "Custom"),
|
||||
"GUID": str(uuid.uuid4()),
|
||||
}
|
||||
|
||||
self.duplicateMaterialByRootId(root_material_id, new_base_id = new_id, new_metadata = new_metadata)
|
||||
return new_id
|
||||
return cura.CuraApplication.CuraApplication.getMaterialManagementModel().createMaterial()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def addFavorite(self, root_material_id: str) -> None:
|
||||
|
@ -127,8 +127,8 @@ class BaseMaterialsModel(ListModel):
|
||||
return
|
||||
nozzle_name = extruder_stack.variant.getName()
|
||||
materials = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants[nozzle_name].materials
|
||||
compatible_material_diameter = str(round(extruder_stack.getCompatibleMaterialDiameter()))
|
||||
self._available_materials = {key: material for key, material in materials.items() if material.container.getMetaDataEntry("approximate_diameter") == compatible_material_diameter}
|
||||
approximate_material_diameter = extruder_stack.getApproximateMaterialDiameter()
|
||||
self._available_materials = {key: material for key, material in materials.items() if float(material.container.getMetaDataEntry("approximate_diameter")) == approximate_material_diameter}
|
||||
|
||||
## This method is used by all material models in the beginning of the
|
||||
# _update() method in order to prevent errors. It's the same in all models
|
||||
|
@ -10,7 +10,7 @@ from cura.Settings.IntentManager import IntentManager
|
||||
from UM.Qt.ListModel import ListModel
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry #To update the list if anything changes.
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal
|
||||
|
||||
import cura.CuraApplication
|
||||
if TYPE_CHECKING:
|
||||
from UM.Settings.ContainerRegistry import ContainerInterface
|
||||
|
||||
@ -48,7 +48,7 @@ class IntentCategoryModel(ListModel):
|
||||
|
||||
ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChange)
|
||||
ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChange)
|
||||
IntentManager.getInstance().configurationChanged.connect(self.update)
|
||||
cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeStackChanged.connect(self.update)
|
||||
|
||||
self.update()
|
||||
|
||||
|
@ -66,12 +66,26 @@ class IntentModel(ListModel):
|
||||
|
||||
container_tree = ContainerTree.getInstance()
|
||||
machine_node = container_tree.machines[global_stack.definition.getId()]
|
||||
active_extruder = ExtruderManager.getInstance().getActiveExtruderStack()
|
||||
|
||||
# We can't just look at the active extruder, since it is possible for only one extruder to have an intent
|
||||
# and the other extruders have no intent (eg, default). It is not possible for one extruder to have intent A and
|
||||
# the other to have B.
|
||||
# So we will use the first extruder that we find that has an intent that is not default as the "active" extruder
|
||||
|
||||
active_extruder = None
|
||||
for extruder in global_stack.extruderList:
|
||||
if extruder.intent.getMetaDataEntry("intent_category", "default") == "default":
|
||||
if active_extruder is None:
|
||||
active_extruder = extruder # If there is no extruder found and the intent is default, use that.
|
||||
else: # We found an intent, use that extruder as "active"
|
||||
active_extruder = extruder
|
||||
|
||||
if not active_extruder:
|
||||
return
|
||||
active_variant_name = active_extruder.variant.getMetaDataEntry("name")
|
||||
active_variant_node = machine_node.variants[active_variant_name]
|
||||
active_material_node = active_variant_node.materials[active_extruder.material.getMetaDataEntry("base_file")]
|
||||
|
||||
layer_heights_added = []
|
||||
for quality_id, quality_node in active_material_node.qualities.items():
|
||||
if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively).
|
||||
|
@ -73,20 +73,19 @@ class MaterialManagementModel(QObject):
|
||||
|
||||
## Creates a duplicate of a material with the same GUID and base_file
|
||||
# metadata.
|
||||
# \param material_node The node representing the material to duplicate.
|
||||
# \param base_file: The base file of the material to duplicate.
|
||||
# \param new_base_id A new material ID for the base material. The IDs of
|
||||
# the submaterials will be based off this one. If not provided, a material
|
||||
# ID will be generated automatically.
|
||||
# \param new_metadata Metadata for the new material. If not provided, this
|
||||
# will be duplicated from the original material.
|
||||
# \return The root material ID of the duplicate material.
|
||||
@pyqtSlot("QVariant", result = str)
|
||||
def duplicateMaterial(self, material_node: "MaterialNode", new_base_id: Optional[str] = None, new_metadata: Dict[str, Any] = None) -> Optional[str]:
|
||||
def duplicateMaterialByBaseFile(self, base_file: str, new_base_id: Optional[str] = None, new_metadata: Dict[str, Any] = None) -> Optional[str]:
|
||||
container_registry = CuraContainerRegistry.getInstance()
|
||||
|
||||
root_materials = container_registry.findContainers(id = material_node.base_file)
|
||||
root_materials = container_registry.findContainers(id = base_file)
|
||||
if not root_materials:
|
||||
Logger.log("i", "Unable to duplicate the root material with ID {root_id}, because it doesn't exist.".format(root_id = material_node.base_file))
|
||||
Logger.log("i", "Unable to duplicate the root material with ID {root_id}, because it doesn't exist.".format(root_id = base_file))
|
||||
return None
|
||||
root_material = root_materials[0]
|
||||
|
||||
@ -105,8 +104,8 @@ class MaterialManagementModel(QObject):
|
||||
new_containers = [new_root_material]
|
||||
|
||||
# Clone all submaterials.
|
||||
for container_to_copy in container_registry.findInstanceContainers(base_file = material_node.base_file):
|
||||
if container_to_copy.getId() == material_node.base_file:
|
||||
for container_to_copy in container_registry.findInstanceContainers(base_file = base_file):
|
||||
if container_to_copy.getId() == base_file:
|
||||
continue # We already have that one. Skip it.
|
||||
new_id = new_base_id
|
||||
definition = container_to_copy.getMetaDataEntry("definition")
|
||||
@ -129,12 +128,25 @@ class MaterialManagementModel(QObject):
|
||||
|
||||
# If the duplicated material was favorite then the new material should also be added to the favorites.
|
||||
favorites_set = set(application.getPreferences().getValue("cura/favorite_materials").split(";"))
|
||||
if material_node.base_file in favorites_set:
|
||||
if base_file in favorites_set:
|
||||
favorites_set.add(new_base_id)
|
||||
application.getPreferences().setValue("cura/favorite_materials", ";".join(favorites_set))
|
||||
|
||||
return new_base_id
|
||||
|
||||
## Creates a duplicate of a material with the same GUID and base_file
|
||||
# metadata.
|
||||
# \param material_node The node representing the material to duplicate.
|
||||
# \param new_base_id A new material ID for the base material. The IDs of
|
||||
# the submaterials will be based off this one. If not provided, a material
|
||||
# ID will be generated automatically.
|
||||
# \param new_metadata Metadata for the new material. If not provided, this
|
||||
# will be duplicated from the original material.
|
||||
# \return The root material ID of the duplicate material.
|
||||
@pyqtSlot("QVariant", result = str)
|
||||
def duplicateMaterial(self, material_node: "MaterialNode", new_base_id: Optional[str] = None, new_metadata: Dict[str, Any] = None) -> Optional[str]:
|
||||
return self.duplicateMaterialByBaseFile(material_node.base_file, new_base_id, new_metadata)
|
||||
|
||||
## Create a new material by cloning the preferred material for the current
|
||||
# material diameter and generate a new GUID.
|
||||
#
|
||||
|
@ -78,9 +78,7 @@ class QualityProfilesDropDownMenuModel(ListModel):
|
||||
quality_group_dict = ContainerTree.getInstance().getCurrentQualityGroups()
|
||||
|
||||
item_list = []
|
||||
for key in quality_group_dict:
|
||||
quality_group = quality_group_dict[key]
|
||||
|
||||
for quality_group in quality_group_dict.values():
|
||||
layer_height = self._fetchLayerHeight(quality_group)
|
||||
|
||||
item = {"name": quality_group.name,
|
||||
|
@ -5,7 +5,6 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
|
||||
|
||||
from UM.Logger import Logger
|
||||
from UM.Util import parseBool
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Decorators import deprecated
|
||||
|
@ -4,6 +4,7 @@
|
||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple, TYPE_CHECKING
|
||||
import cura.CuraApplication
|
||||
from UM.Logger import Logger
|
||||
from cura.Machines.ContainerTree import ContainerTree
|
||||
from cura.Settings.cura_empty_instance_containers import empty_intent_container
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
@ -11,20 +12,12 @@ from UM.Settings.InstanceContainer import InstanceContainer
|
||||
if TYPE_CHECKING:
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
|
||||
|
||||
## Front-end for querying which intents are available for a certain
|
||||
# configuration.
|
||||
#
|
||||
# CURRENTLY THIS CLASS CONTAINS ONLY SOME PSEUDOCODE OF WHAT WE ARE SUPPOSED
|
||||
# TO IMPLEMENT.
|
||||
class IntentManager(QObject):
|
||||
__instance = None
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeStackChanged.connect(self.configurationChanged)
|
||||
self.configurationChanged.connect(self.selectDefaultIntent)
|
||||
pass
|
||||
|
||||
## This class is a singleton.
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
@ -32,7 +25,6 @@ class IntentManager(QObject):
|
||||
cls.__instance = IntentManager()
|
||||
return cls.__instance
|
||||
|
||||
configurationChanged = pyqtSignal() #Triggered when something changed in the rest of the stack.
|
||||
intentCategoryChanged = pyqtSignal() #Triggered when we switch categories.
|
||||
|
||||
## Gets the metadata dictionaries of all intent profiles for a given
|
||||
@ -40,12 +32,16 @@ class IntentManager(QObject):
|
||||
#
|
||||
# \param definition_id ID of the printer.
|
||||
# \param nozzle_name Name of the nozzle.
|
||||
# \param material_id ID of the material.
|
||||
# \param material_base_file The base_file of the material.
|
||||
# \return A list of metadata dictionaries matching the search criteria, or
|
||||
# an empty list if nothing was found.
|
||||
def intentMetadatas(self, definition_id: str, nozzle_name: str, material_id: str) -> List[Dict[str, Any]]:
|
||||
registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry()
|
||||
return registry.findContainersMetadata(type = "intent", definition = definition_id, variant = nozzle_name, material = material_id)
|
||||
def intentMetadatas(self, definition_id: str, nozzle_name: str, material_base_file: str) -> List[Dict[str, Any]]:
|
||||
material_node = ContainerTree.getInstance().machines[definition_id].variants[nozzle_name].materials[material_base_file]
|
||||
intent_metadatas = []
|
||||
for quality_node in material_node.qualities.values():
|
||||
for intent_node in quality_node.intents.values():
|
||||
intent_metadatas.append(intent_node.getMetadata())
|
||||
return intent_metadatas
|
||||
|
||||
## Collects and returns all intent categories available for the given
|
||||
# parameters. Note that the 'default' category is always available.
|
||||
@ -77,7 +73,6 @@ class IntentManager(QObject):
|
||||
# even though there should always be defaults. The problem then is what to do with the quality_types.
|
||||
# Currently _also_ inconsistent with 'currentAvailableIntentCategories', which _does_ return default.
|
||||
quality_groups = ContainerTree.getInstance().getCurrentQualityGroups()
|
||||
# TODO: These quality nodes in that tree already contain the intent nodes. We can optimise this.
|
||||
available_quality_types = {quality_group.quality_type for quality_group in quality_groups.values() if quality_group.node_for_global is not None}
|
||||
|
||||
final_intent_ids = set() # type: Set[str]
|
||||
@ -131,6 +126,7 @@ class IntentManager(QObject):
|
||||
## Apply intent on the stacks.
|
||||
@pyqtSlot(str, str)
|
||||
def selectIntent(self, intent_category: str, quality_type: str) -> None:
|
||||
Logger.log("i", "Attempting to set intent_category to [%s] and quality type to [%s]", intent_category, quality_type)
|
||||
old_intent_category = self.currentIntentCategory
|
||||
application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
global_stack = application.getGlobalContainerStack()
|
||||
@ -147,13 +143,4 @@ class IntentManager(QObject):
|
||||
extruder_stack.intent = self.getDefaultIntent()
|
||||
application.getMachineManager().setQualityGroupByQualityType(quality_type)
|
||||
if old_intent_category != intent_category:
|
||||
self.intentCategoryChanged.emit()
|
||||
|
||||
## Selects the default intents on every extruder.
|
||||
def selectDefaultIntent(self) -> None:
|
||||
application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
global_stack = application.getGlobalContainerStack()
|
||||
if global_stack is None:
|
||||
return
|
||||
for extruder_stack in global_stack.extruderList:
|
||||
extruder_stack.intent = self.getDefaultIntent()
|
||||
self.intentCategoryChanged.emit()
|
@ -26,7 +26,6 @@ import cura.CuraApplication # Imported like this to prevent circular references
|
||||
|
||||
from cura.Machines.ContainerNode import ContainerNode
|
||||
from cura.Machines.ContainerTree import ContainerTree
|
||||
from cura.Machines.MaterialManager import MaterialManager
|
||||
|
||||
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice, ConnectionType
|
||||
from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel
|
||||
@ -616,10 +615,15 @@ class MachineManager(QObject):
|
||||
|
||||
@pyqtProperty(str, notify=activeIntentChanged)
|
||||
def activeIntentCategory(self):
|
||||
global_container_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
|
||||
if not self._active_container_stack:
|
||||
if not global_container_stack:
|
||||
return ""
|
||||
intent_category = self._active_container_stack.intent.getMetaDataEntry("intent_category")
|
||||
intent_category = "default"
|
||||
for extruder in global_container_stack.extruderList:
|
||||
category = extruder.intent.getMetaDataEntry("intent_category", "default")
|
||||
if category != "default" and category != intent_category:
|
||||
intent_category = category
|
||||
return intent_category
|
||||
|
||||
## Returns whether there is anything unsupported in the current set-up.
|
||||
@ -1301,8 +1305,7 @@ class MachineManager(QObject):
|
||||
self._setMaterial(position_item, new_material)
|
||||
else:
|
||||
# The current material is not available, find the preferred one.
|
||||
material_diameter = self._global_container_stack.extruders[position].getCompatibleMaterialDiameter()
|
||||
approximate_material_diameter = round(material_diameter)
|
||||
approximate_material_diameter = int(self._global_container_stack.extruderList[int(position)].getApproximateMaterialDiameter())
|
||||
material_node = nozzle_node.preferredMaterial(approximate_material_diameter)
|
||||
self._setMaterial(position_item, material_node)
|
||||
|
||||
@ -1343,6 +1346,7 @@ class MachineManager(QObject):
|
||||
if self._global_container_stack is None:
|
||||
return
|
||||
self.blurSettings.emit()
|
||||
container_registry = CuraContainerRegistry.getInstance()
|
||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||
self.switchPrinterType(configuration.printerType)
|
||||
|
||||
@ -1379,20 +1383,18 @@ class MachineManager(QObject):
|
||||
else:
|
||||
machine_node = ContainerTree.getInstance().machines.get(self._global_container_stack.definition.getId())
|
||||
variant_node = machine_node.variants.get(extruder_configuration.hotendID)
|
||||
if variant_node:
|
||||
self._setVariantNode(position, variant_node)
|
||||
else:
|
||||
self._global_container_stack.extruders[position].variant = empty_variant_container
|
||||
self._setVariantNode(position, variant_node)
|
||||
|
||||
material_container_node = MaterialManager.getInstance().getMaterialNodeByType(self._global_container_stack,
|
||||
position,
|
||||
extruder_configuration.hotendID,
|
||||
configuration.buildplateConfiguration,
|
||||
extruder_configuration.material.guid)
|
||||
if material_container_node:
|
||||
self._setMaterial(position, material_container_node)
|
||||
else:
|
||||
self._global_container_stack.extruders[position].material = empty_material_container
|
||||
# Find the material profile that the printer has stored.
|
||||
# This might find one of the duplicates if the user duplicated the material to sync with. But that's okay; both have this GUID so both are correct.
|
||||
approximate_diameter = int(self._global_container_stack.extruderList[int(position)].getApproximateMaterialDiameter())
|
||||
materials_with_guid = container_registry.findInstanceContainersMetadata(guid = extruder_configuration.material.guid, approximate_diameter = approximate_diameter)
|
||||
material_container_node = variant_node.preferredMaterial(approximate_diameter)
|
||||
if materials_with_guid: # We also have the material profile that the printer wants to share.
|
||||
base_file = materials_with_guid[0]["base_file"]
|
||||
material_container_node = variant_node.materials.get(base_file, default = material_container_node) # If Cura thinks that the selected material is not available for this printer, revert to the preferred material.
|
||||
|
||||
self._setMaterial(position, material_container_node)
|
||||
self._global_container_stack.extruders[position].setEnabled(True)
|
||||
self.updateMaterialWithVariant(position)
|
||||
|
||||
@ -1431,17 +1433,12 @@ class MachineManager(QObject):
|
||||
def setMaterialById(self, position: str, root_material_id: str) -> None:
|
||||
if self._global_container_stack is None:
|
||||
return
|
||||
buildplate_name = None
|
||||
if self._global_container_stack.variant.getId() != "empty_variant":
|
||||
buildplate_name = self._global_container_stack.variant.getName()
|
||||
|
||||
machine_definition_id = self._global_container_stack.definition.id
|
||||
position = str(position)
|
||||
extruder_stack = self._global_container_stack.extruders[position]
|
||||
nozzle_name = extruder_stack.variant.getName()
|
||||
material_diameter = extruder_stack.getApproximateMaterialDiameter()
|
||||
material_node = MaterialManager.getInstance().getMaterialNode(machine_definition_id, nozzle_name, buildplate_name,
|
||||
material_diameter, root_material_id)
|
||||
material_node = ContainerTree.getInstance().machines[machine_definition_id].variants[nozzle_name].materials[root_material_id]
|
||||
self.setMaterial(position, material_node)
|
||||
|
||||
## Global_stack: if you want to provide your own global_stack instead of the current active one
|
||||
@ -1624,7 +1621,3 @@ class MachineManager(QObject):
|
||||
abbr_machine += stripped_word
|
||||
|
||||
return abbr_machine
|
||||
|
||||
# Gets all machines that belong to the given group_id.
|
||||
def getMachinesInGroup(self, group_id: str) -> List["GlobalStack"]:
|
||||
return self._container_registry.findContainerStacks(type = "machine", group_id = group_id)
|
||||
|
@ -11,7 +11,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
from UM.Util import parseBool
|
||||
|
||||
import cura.CuraApplication # Imported like this to prevent circular dependencies.
|
||||
from cura.MachineAction import MachineAction
|
||||
from cura.Machines.ContainerTree import ContainerTree # To re-build the machine node when hasMaterials changes.
|
||||
from cura.Settings.CuraStackBuilder import CuraStackBuilder
|
||||
from cura.Settings.cura_empty_instance_containers import isEmptyContainer
|
||||
|
||||
@ -41,6 +43,9 @@ class MachineSettingsAction(MachineAction):
|
||||
self._backend = self._application.getBackend()
|
||||
self.onFinished.connect(self._onFinished)
|
||||
|
||||
# If the g-code flavour changes between UltiGCode and another flavour, we need to update the container tree.
|
||||
self._application.globalContainerStackChanged.connect(self._updateHasMaterialsInContainerTree)
|
||||
|
||||
# Which container index in a stack to store machine setting changes.
|
||||
@pyqtProperty(int, constant = True)
|
||||
def storeContainerIndex(self) -> int:
|
||||
@ -51,6 +56,16 @@ class MachineSettingsAction(MachineAction):
|
||||
if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
|
||||
self._application.getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
|
||||
|
||||
## Triggered when the global container stack changes or when the g-code
|
||||
# flavour setting is changed.
|
||||
def _updateHasMaterialsInContainerTree(self) -> None:
|
||||
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
||||
machine_node = ContainerTree.getInstance().machines[global_stack.definition.getId()]
|
||||
|
||||
if machine_node.has_materials != parseBool(global_stack.getMetaDataEntry("has_materials")): # May have changed due to the g-code flavour.
|
||||
machine_node.has_materials = parseBool(global_stack.getMetaDataEntry("has_materials"))
|
||||
machine_node._loadAll()
|
||||
|
||||
def _reset(self):
|
||||
global_stack = self._application.getMachineManager().activeMachine
|
||||
if not global_stack:
|
||||
@ -98,11 +113,8 @@ class MachineSettingsAction(MachineAction):
|
||||
return
|
||||
|
||||
machine_manager = self._application.getMachineManager()
|
||||
material_manager = self._application.getMaterialManager()
|
||||
extruder_positions = list(global_stack.extruders.keys())
|
||||
has_materials = global_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
|
||||
|
||||
material_node = None
|
||||
if has_materials:
|
||||
global_stack.setMetaDataEntry("has_materials", True)
|
||||
else:
|
||||
@ -111,11 +123,15 @@ class MachineSettingsAction(MachineAction):
|
||||
if "has_materials" in global_stack.getMetaData():
|
||||
global_stack.removeMetaDataEntry("has_materials")
|
||||
|
||||
self._updateHasMaterialsInContainerTree()
|
||||
|
||||
# set materials
|
||||
for position in extruder_positions:
|
||||
if has_materials:
|
||||
material_node = material_manager.getDefaultMaterial(global_stack, position, None)
|
||||
machine_manager.setMaterial(position, material_node)
|
||||
machine_node = ContainerTree.getInstance().machines[global_stack.definition.getId()]
|
||||
for position, extruder in enumerate(global_stack.extruderList):
|
||||
#Find out what material we need to default to.
|
||||
approximate_diameter = round(extruder.getProperty("material_diameter", "value"))
|
||||
material_node = machine_node.variants[extruder.variant.getName()].preferredMaterial(approximate_diameter)
|
||||
machine_manager.setMaterial(str(position), material_node)
|
||||
|
||||
self._application.globalContainerStackChanged.emit()
|
||||
|
||||
|
@ -69,9 +69,9 @@ class SendMaterialJob(Job):
|
||||
def _sendMaterials(self, materials_to_send: Set[str]) -> None:
|
||||
container_registry = CuraApplication.getInstance().getContainerRegistry()
|
||||
all_materials = container_registry.findInstanceContainersMetadata(type = "material")
|
||||
all_root_materials = {material["base_file"] for material in all_materials if "base_file" in material} # Filters out uniques by making it a set. Don't include files without base file (i.e. empty material).
|
||||
all_base_files = {material["base_file"] for material in all_materials if "base_file" in material} # Filters out uniques by making it a set. Don't include files without base file (i.e. empty material).
|
||||
|
||||
for root_material_id in all_root_materials:
|
||||
for root_material_id in all_base_files:
|
||||
if root_material_id not in materials_to_send:
|
||||
# If the material does not have to be sent we skip it.
|
||||
continue
|
||||
@ -129,10 +129,10 @@ class SendMaterialJob(Job):
|
||||
def _getLocalMaterials() -> Dict[str, LocalMaterial]:
|
||||
result = {} # type: Dict[str, LocalMaterial]
|
||||
all_materials = CuraApplication.getInstance().getContainerRegistry().findInstanceContainersMetadata(type = "material")
|
||||
all_root_materials = [material for material in all_materials if material["id"] == material.get("base_file")] # Don't send materials without base_file: The empty material doesn't need to be sent.
|
||||
all_base_files = [material for material in all_materials if material["id"] == material.get("base_file")] # Don't send materials without base_file: The empty material doesn't need to be sent.
|
||||
|
||||
# Find the latest version of all material containers in the registry.
|
||||
for material_metadata in all_root_materials:
|
||||
for material_metadata in all_base_files:
|
||||
try:
|
||||
# material version must be an int
|
||||
material_metadata["version"] = int(material_metadata["version"])
|
||||
|
@ -22,7 +22,7 @@ Button
|
||||
background: Rectangle
|
||||
{
|
||||
id: backgroundRectangle
|
||||
border.width: 1
|
||||
border.width: UM.Theme.getSize("default_lining").width
|
||||
border.color: button.checked ? UM.Theme.getColor("setting_control_border_highlight") : "transparent"
|
||||
color: button.hovered ? UM.Theme.getColor("action_button_hovered") : "transparent"
|
||||
radius: UM.Theme.getSize("action_button_radius").width
|
||||
|
@ -182,11 +182,12 @@ Popup
|
||||
|
||||
Rectangle
|
||||
{
|
||||
height: 1
|
||||
height: UM.Theme.getSize("default_lining").height
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: borderColor
|
||||
}
|
||||
|
||||
MenuButton
|
||||
{
|
||||
labelText: Cura.Actions.addProfile.text
|
||||
|
@ -14,7 +14,7 @@ Item
|
||||
property color activeColor: UM.Theme.getColor("primary")
|
||||
property color inactiveColor: UM.Theme.getColor("slider_groove")
|
||||
property color defaultItemColor: UM.Theme.getColor("small_button_active")
|
||||
property int checkboxSize: UM.Theme.getSize("radio_button").height * 0.75
|
||||
property int checkboxSize: Math.round(UM.Theme.getSize("radio_button").height * 0.75)
|
||||
property int inactiveMarkerSize: 2 * barSize
|
||||
property int barSize: UM.Theme.getSize("slider_groove_radius").height
|
||||
property var isCheckedFunction // Function that accepts the modelItem and returns if the item should be active.
|
||||
@ -36,8 +36,8 @@ Item
|
||||
{
|
||||
left: buttonBar.left
|
||||
right: buttonBar.right
|
||||
leftMargin: (checkboxSize - inactiveMarkerSize) / 2
|
||||
rightMargin: (checkboxSize - inactiveMarkerSize) / 2
|
||||
leftMargin: Math.round((checkboxSize - inactiveMarkerSize) / 2)
|
||||
rightMargin: Math.round((checkboxSize - inactiveMarkerSize) / 2)
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ Item
|
||||
property Item previousItem: repeater.itemAt(index - 1)
|
||||
|
||||
height: barSize
|
||||
width: buttonBar.width / (repeater.count - 1) - activeComponent.width - 2
|
||||
width: Math.round(buttonBar.width / (repeater.count - 1) - activeComponent.width - 2)
|
||||
color: defaultItemColor
|
||||
|
||||
anchors
|
||||
@ -110,7 +110,7 @@ Item
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: inactiveMarkerSize
|
||||
width: inactiveMarkerSize
|
||||
radius: width / 2
|
||||
radius: Math.round(width / 2)
|
||||
color: inactiveColor
|
||||
}
|
||||
}
|
||||
@ -132,7 +132,7 @@ Item
|
||||
{
|
||||
height: checkboxSize
|
||||
width: checkboxSize
|
||||
radius: width / 2
|
||||
radius: Math.round(width / 2)
|
||||
|
||||
border.color: defaultItemColor
|
||||
|
||||
@ -143,7 +143,7 @@ Item
|
||||
margins: 3
|
||||
fill: parent
|
||||
}
|
||||
radius: width / 2
|
||||
radius: Math.round(width / 2)
|
||||
color: activeColor
|
||||
visible: checkbox.checked
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user