Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/cura
diff options
context:
space:
mode:
authorj.delarago <joeydelarago@gmail.com>2022-06-14 12:41:38 +0300
committerj.delarago <joeydelarago@gmail.com>2022-06-14 12:41:38 +0300
commita87695cd8dfb5c257ed63ffd05a972846bcb77ec (patch)
treeca418c069db6f044df4fc308e52134a61fe1a27a /cura
parent6f88adab8e031176b27f90ed50abe374112afeef (diff)
Added new intent selection buttons and resolution drop down to replace the matrix.
We are now selecting intents first and then quality, however the container hierarchy quality -> intents. This is the reason for the new functions inside machine manager. CURA-8849
Diffstat (limited to 'cura')
-rwxr-xr-xcura/CuraApplication.py4
-rw-r--r--cura/Machines/Models/ActiveIntentQualitiesModel.py121
-rw-r--r--cura/Machines/Models/IntentSelectionModel.py129
-rwxr-xr-xcura/Settings/MachineManager.py28
4 files changed, 282 insertions, 0 deletions
diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py
index 3a3ac17cdf..e1805584b0 100755
--- a/cura/CuraApplication.py
+++ b/cura/CuraApplication.py
@@ -115,6 +115,8 @@ from . import CuraActions
from . import PlatformPhysics
from . import PrintJobPreviewImageProvider
from .AutoSave import AutoSave
+from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
+from .Machines.Models.IntentSelectionModel import IntentSelectionModel
from .SingleInstance import SingleInstance
if TYPE_CHECKING:
@@ -1192,6 +1194,8 @@ class CuraApplication(QtApplication):
qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel")
qmlRegisterType(IntentModel, "Cura", 1, 6, "IntentModel")
qmlRegisterType(IntentCategoryModel, "Cura", 1, 6, "IntentCategoryModel")
+ qmlRegisterType(IntentSelectionModel, "Cura", 1, 7, "IntentSelectionModel")
+ qmlRegisterType(ActiveIntentQualitiesModel, "Cura", 1, 7, "ActiveIntentQualitiesModel")
self.processEvents()
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
diff --git a/cura/Machines/Models/ActiveIntentQualitiesModel.py b/cura/Machines/Models/ActiveIntentQualitiesModel.py
new file mode 100644
index 0000000000..67b9cec9a4
--- /dev/null
+++ b/cura/Machines/Models/ActiveIntentQualitiesModel.py
@@ -0,0 +1,121 @@
+# Copyright (c) 2022 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+from typing import Optional, Set, Dict, List, Any
+
+from PyQt6.QtCore import Qt, QObject, QTimer
+
+import cura.CuraApplication
+from UM.Logger import Logger
+from UM.Qt.ListModel import ListModel
+from cura.Machines.ContainerTree import ContainerTree
+from cura.Machines.Models.MachineModelUtils import fetchLayerHeight
+from cura.Machines.MaterialNode import MaterialNode
+from cura.Machines.QualityGroup import QualityGroup
+from cura.Settings.IntentManager import IntentManager
+
+
+class ActiveIntentQualitiesModel(ListModel):
+ NameRole = Qt.ItemDataRole.UserRole + 1
+ DisplayTextRole = Qt.ItemDataRole.UserRole + 2
+ QualityTypeRole = Qt.ItemDataRole.UserRole + 3
+ LayerHeightRole = Qt.ItemDataRole.UserRole + 4
+ IntentCategeoryRole = Qt.ItemDataRole.UserRole + 5
+
+ def __init__(self, parent: Optional[QObject] = None) -> None:
+ super().__init__(parent)
+
+ self.addRoleName(self.NameRole, "name")
+ self.addRoleName(self.QualityTypeRole, "quality_type")
+ self.addRoleName(self.LayerHeightRole, "layer_height")
+ self.addRoleName(self.DisplayTextRole, "display_text")
+ self.addRoleName(self.IntentCategeoryRole, "intent_category")
+
+ self._intent_category = ""
+
+ IntentManager.intentCategoryChangedSignal.connect(self._update)
+
+ self._update_timer = QTimer()
+ self._update_timer.setInterval(100)
+ self._update_timer.setSingleShot(True)
+ self._update_timer.timeout.connect(self._update)
+
+ self._update()
+
+ def _updateDelayed(self):
+ self._update_timer.start()
+
+ def _onChanged(self, container):
+ if container.getMetaDataEntry("type") == "intent":
+ self._updateDelayed()
+
+ def _update(self):
+ active_extruder_stack = cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeStack
+ if active_extruder_stack:
+ self._intent_category = active_extruder_stack.intent.getMetaDataEntry("intent_category", "")
+
+ new_items = [] # type: List[Dict[str, Any]]
+ global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
+ if not global_stack:
+ self.setItems(new_items)
+ return
+ quality_groups = ContainerTree.getInstance().getCurrentQualityGroups()
+
+ material_nodes = self._getActiveMaterials()
+
+ added_quality_type_set = set() # type: Set[str]
+ for material_node in material_nodes:
+ intents = self._getIntentsForMaterial(material_node, quality_groups)
+ for intent in intents:
+ if intent["quality_type"] not in added_quality_type_set:
+ new_items.append(intent)
+ added_quality_type_set.add(intent["quality_type"])
+
+ new_items = sorted(new_items, key=lambda x: x["layer_height"])
+ self.setItems(new_items)
+
+ def _getActiveMaterials(self) -> Set["MaterialNode"]:
+ """Get the active materials for all extruders. No duplicates will be returned"""
+
+ global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
+ if global_stack is None:
+ return set()
+
+ container_tree = ContainerTree.getInstance()
+ machine_node = container_tree.machines[global_stack.definition.getId()]
+ nodes = set() # type: Set[MaterialNode]
+
+ for extruder in global_stack.extruderList:
+ active_variant_name = extruder.variant.getMetaDataEntry("name")
+ if active_variant_name not in machine_node.variants:
+ Logger.log("w", "Could not find the variant %s", active_variant_name)
+ continue
+ active_variant_node = machine_node.variants[active_variant_name]
+ active_material_node = active_variant_node.materials.get(extruder.material.getMetaDataEntry("base_file"))
+ if active_material_node is None:
+ Logger.log("w", "Could not find the material %s", extruder.material.getMetaDataEntry("base_file"))
+ continue
+ nodes.add(active_material_node)
+
+ return nodes
+
+ def _getIntentsForMaterial(self, active_material_node: "MaterialNode", quality_groups: Dict[str, "QualityGroup"]) -> List[Dict[str, Any]]:
+ extruder_intents = [] # type: List[Dict[str, Any]]
+
+ 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).
+ continue
+ quality_group = quality_groups[quality_node.quality_type]
+ layer_height = fetchLayerHeight(quality_group)
+
+ for intent_id, intent_node in quality_node.intents.items():
+ if intent_node.intent_category != self._intent_category:
+ continue
+ extruder_intents.append({"name": quality_group.name,
+ "display_text": f"{quality_group.name} - {layer_height}mm",
+ "quality_type": quality_group.quality_type,
+ "layer_height": layer_height,
+ "intent_category": self._intent_category
+ })
+ return extruder_intents
+
+
diff --git a/cura/Machines/Models/IntentSelectionModel.py b/cura/Machines/Models/IntentSelectionModel.py
new file mode 100644
index 0000000000..c8c9b9974d
--- /dev/null
+++ b/cura/Machines/Models/IntentSelectionModel.py
@@ -0,0 +1,129 @@
+# Copyright (c) 2022 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+
+import collections
+from typing import OrderedDict
+
+from PyQt6.QtCore import Qt, QTimer
+
+import cura
+from UM import i18nCatalog
+from UM.Logger import Logger
+from UM.Qt.ListModel import ListModel
+from UM.Settings.ContainerRegistry import ContainerRegistry
+from UM.Settings.Interfaces import ContainerInterface
+from cura.Settings.IntentManager import IntentManager
+
+catalog = i18nCatalog("cura")
+
+
+class IntentSelectionModel(ListModel):
+
+ NameRole = Qt.ItemDataRole.UserRole + 1
+ IntentCategoryRole = Qt.ItemDataRole.UserRole + 2
+ WeightRole = Qt.ItemDataRole.UserRole + 3
+ DescriptionRole = Qt.ItemDataRole.UserRole + 4
+ IconRole = Qt.ItemDataRole.UserRole + 5
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.addRoleName(self.NameRole, "name")
+ self.addRoleName(self.IntentCategoryRole, "intent_category")
+ self.addRoleName(self.WeightRole, "weight")
+ self.addRoleName(self.DescriptionRole, "description")
+ self.addRoleName(self.IconRole, "icon")
+
+ application = cura.CuraApplication.CuraApplication.getInstance()
+
+ ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChange)
+ ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChange)
+ machine_manager = cura.CuraApplication.CuraApplication.getInstance().getMachineManager()
+ machine_manager.activeMaterialChanged.connect(self._update)
+ machine_manager.activeVariantChanged.connect(self._update)
+ machine_manager.extruderChanged.connect(self._update)
+
+ extruder_manager = application.getExtruderManager()
+ extruder_manager.extrudersChanged.connect(self._update)
+
+ self._update_timer = QTimer() # type: QTimer
+ self._update_timer.setInterval(100)
+ self._update_timer.setSingleShot(True)
+ self._update_timer.timeout.connect(self._update)
+
+ self._onChange()
+
+ @staticmethod
+ def _getDefaultProfileInformation() -> OrderedDict[str, dict]:
+ """ Default information user-visible string. Ordered by weight. """
+ default_profile_information = collections.OrderedDict()
+ default_profile_information["default"] = {
+ "name": catalog.i18nc("@label", "Default"),
+ "icon": "GearCheck"
+ }
+ default_profile_information["visual"] = {
+ "name": catalog.i18nc("@label", "Visual"),
+ "description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality."),
+ "icon" : "Visual"
+ }
+ default_profile_information["engineering"] = {
+ "name": catalog.i18nc("@label", "Engineering"),
+ "description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances."),
+ "icon": "Nut"
+ }
+ default_profile_information["quick"] = {
+ "name": catalog.i18nc("@label", "Draft"),
+ "description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction."),
+ "icon": "SpeedOMeter"
+ }
+ return default_profile_information
+
+ def _onContainerChange(self, container: ContainerInterface) -> None:
+ """Updates the list of intents if an intent profile was added or removed."""
+
+ if container.getMetaDataEntry("type") == "intent":
+ self._update()
+
+ def _onChange(self) -> None:
+ self._update_timer.start()
+
+ def _update(self):
+ Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))
+
+ global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
+ if global_stack is None:
+ self.setItems([])
+ Logger.log("d", "No active GlobalStack, set quality profile model as empty.")
+ return
+
+ # Check for material compatibility
+ if not cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeMaterialsCompatible():
+ Logger.log("d", "No active material compatibility, set quality profile model as empty.")
+ self.setItems([])
+ return
+
+ default_profile_info = self._getDefaultProfileInformation()
+
+ available_categories = IntentManager.getInstance().currentAvailableIntentCategories()
+ result = []
+ for i, category in enumerate(available_categories):
+ profile_info = default_profile_info.get(category, {})
+
+ try:
+ weight = list(default_profile_info.keys()).index(category)
+ except ValueError:
+ weight = len(available_categories) + i
+
+ result.append({
+ "name": profile_info.get("name", category.title()),
+ "description": profile_info.get("description", None),
+ "icon" : profile_info.get("icon", ""),
+ "intent_category": category,
+ "weight": weight,
+ })
+
+ result.sort(key=lambda k: k["weight"])
+
+ self.setItems(result)
+
+
diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py
index 9b98179bff..64d34d6c3e 100755
--- a/cura/Settings/MachineManager.py
+++ b/cura/Settings/MachineManager.py
@@ -1778,3 +1778,31 @@ class MachineManager(QObject):
abbr_machine += stripped_word
return abbr_machine
+
+ @pyqtSlot(str, str, result = bool)
+ def intentCategoryHasQuality(self, intent_category: str, quality_type: str) -> bool:
+ """ Checks if there are any quality groups for active extruders that have an intent category """
+ quality_groups = ContainerTree.getInstance().getCurrentQualityGroups()
+
+ if quality_type in quality_groups:
+ quality_group = quality_groups[quality_type]
+ for node in quality_group.nodes_for_extruders.values():
+ if any(intent.intent_category == intent_category for intent in node.intents.values()):
+ return True
+
+ return False
+
+ @pyqtSlot(str, result = str)
+ def getDefaultQualityTypeForIntent(self, intent_category) -> str:
+ """ If there is an intent category for the default machine quality return it, otherwise return the first quality for this intent category """
+ machine = ContainerTree.getInstance().machines.get(self._global_container_stack.definition.getId())
+
+ if self.intentCategoryHasQuality(intent_category, machine.preferred_quality_type):
+ return machine.preferred_quality_type
+
+ for quality_type, quality_group in ContainerTree.getInstance().getCurrentQualityGroups().items():
+ for node in quality_group.nodes_for_extruders.values():
+ if any(intent.intent_category == intent_category for intent in node.intents.values()):
+ return quality_type
+
+ return ""