Allow for custom descriptions/icons in packaged intents

CURA-9709
This commit is contained in:
c.lamboo 2023-05-31 12:54:56 +02:00
parent af12166595
commit 27cc89ff89
6 changed files with 72 additions and 54 deletions

View file

@ -1,4 +1,4 @@
# Copyright (c) 2022 Ultimaker B.V.
# Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import enum
import os
@ -147,6 +147,7 @@ class CuraApplication(QtApplication):
DefinitionChangesContainer = Resources.UserType + 10
SettingVisibilityPreset = Resources.UserType + 11
IntentInstanceContainer = Resources.UserType + 12
ImageFiles = Resources.UserType + 13
pyqtEnum(ResourceTypes)
@ -425,6 +426,7 @@ class CuraApplication(QtApplication):
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility")
Resources.addStorageType(self.ResourceTypes.IntentInstanceContainer, "intent")
Resources.addStorageType(self.ResourceTypes.ImageFiles, "images")
self._container_registry.addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes")
@ -435,6 +437,7 @@ class CuraApplication(QtApplication):
self._container_registry.addResourceType(self.ResourceTypes.MachineStack, "machine")
self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
self._container_registry.addResourceType(self.ResourceTypes.IntentInstanceContainer, "intent")
self._container_registry.addResourceType(self.ResourceTypes.ImageFiles, "images")
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
Resources.addType(self.ResourceTypes.Firmware, "firmware")

View file

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import glob
import os
@ -55,7 +55,9 @@ class CuraPackageManager(PackageManager):
def initialize(self) -> None:
self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer)
self._installation_dirs_dict["variants"] = Resources.getStoragePath(CuraApplication.ResourceTypes.VariantInstanceContainer)
self._installation_dirs_dict["variants"] = Resources.getStoragePath(
CuraApplication.ResourceTypes.VariantInstanceContainer)
self._installation_dirs_dict["images"] = Resources.getStoragePath(CuraApplication.ResourceTypes.ImageFiles)
# Due to a bug in Cura 5.1.0 we needed to change the directory structure of the curapackage on the server side (See SD-3871).
# Although the material intent profiles will be installed in the `intent` folder, the curapackage from the server side will

View file

@ -1,29 +1,32 @@
# Copyright (c) 2022 Ultimaker B.V.
# Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import collections
from typing import OrderedDict, Optional
from typing import Optional
from PyQt6.QtCore import Qt, QTimer, QObject
from PyQt6.QtCore import Qt, QTimer, QObject, QUrl
import cura
from UM import i18nCatalog
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel
from UM.Resources import Resources
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import ContainerInterface
from cura.Machines.Models.IntentCategoryModel import IntentCategoryModel
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
CustomIconRole = Qt.ItemDataRole.UserRole + 6
def __init__(self, parent: Optional[QObject] = None) -> None:
super().__init__(parent)
@ -33,6 +36,7 @@ class IntentSelectionModel(ListModel):
self.addRoleName(self.WeightRole, "weight")
self.addRoleName(self.DescriptionRole, "description")
self.addRoleName(self.IconRole, "icon")
self.addRoleName(self.CustomIconRole, "custom_icon")
application = cura.CuraApplication.CuraApplication.getInstance()
@ -53,30 +57,8 @@ class IntentSelectionModel(ListModel):
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
_default_intent_categories = ["default", "visual", "engineering", "quick"]
_icons = {"default": "GearCheck", "visual": "Visual", "engineering": "Nut", "quick": "SpeedOMeter"}
def _onContainerChange(self, container: ContainerInterface) -> None:
"""Updates the list of intents if an intent profile was added or removed."""
@ -102,25 +84,42 @@ class IntentSelectionModel(ListModel):
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, {})
for category in available_categories:
try:
weight = list(default_profile_info.keys()).index(category)
except ValueError:
weight = len(available_categories) + i
if category in self._default_intent_categories:
result.append({
"name": IntentCategoryModel.translation(category, "name", category.title()),
"description": IntentCategoryModel.translation(category, "description", None),
"icon": self._icons[category],
"custom_icon": None,
"intent_category": category,
"weight": self._default_intent_categories.index(category),
})
else:
# There can be multiple intents with the same category, use one of these
# intent-metadata's for the icon/description defintions for the intent
intent_metadata = cura.CuraApplication.CuraApplication \
.getInstance() \
.getContainerRegistry() \
.findContainersMetadata(type="intent", definition=global_stack.definition.getId(),
intent_category=category)[0]
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,
})
icon = intent_metadata.get("icon", None)
if icon is not None:
icon = QUrl.fromLocalFile(
Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.ImageFiles, icon))
result.append({
"name": intent_metadata.get("name", category.title()),
"description": intent_metadata.get("description", None),
"custom_icon": icon,
"icon": None,
"intent_category": category,
"weight": 5,
})
result.sort(key=lambda k: k["weight"])

View file

@ -1,4 +1,4 @@
# Copyright (c) 2021 Ultimaker B.V.
# Copyright (c) 2023 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Settings.SQLQueryFactory import SQLQueryFactory
@ -10,8 +10,8 @@ class IntentDatabaseHandler(DatabaseMetadataContainerController):
"""The Database handler for Intent containers"""
def __init__(self) -> None:
super().__init__(SQLQueryFactory(table = "intent",
fields = {
super().__init__(SQLQueryFactory(table="intent",
fields={
"id": "text",
"name": "text",
"quality_type": "text",
@ -20,6 +20,8 @@ class IntentDatabaseHandler(DatabaseMetadataContainerController):
"definition": "text",
"material": "text",
"version": "text",
"setting_version": "text"
"setting_version": "text",
"icon": "text",
"description": "text",
}))
self._container_type = InstanceContainer

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Ultimaker B.V.
// Copyright (c) 2023 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
@ -32,6 +32,7 @@ Item
{
profileName: model.name
icon: model.icon
custom_icon: model.custom_icon
tooltipText: model.description ? model.description : ""
selected: Cura.MachineManager.activeIntentCategory == model.intent_category

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Ultimaker B.V.
// Copyright (c) 2023 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
@ -19,6 +19,7 @@ Rectangle
property bool selected: false
property string profileName: ""
property string icon: ""
property string custom_icon: ""
property alias tooltipText: tooltip.text
signal clicked()
@ -55,22 +56,32 @@ Rectangle
id: intentIcon
width: UM.Theme.getSize("recommended_button_icon").width
height: UM.Theme.getSize("recommended_button_icon").height
UM.ColorImage
{
anchors.fill: parent
anchors.centerIn: parent
visible: icon != ""
visible: icon !== ""
source: UM.Theme.getIcon(icon)
color: UM.Theme.getColor("icon")
}
UM.ColorImage
{
anchors.fill: parent
anchors.centerIn: parent
visible: custom_icon !== ""
source: custom_icon
color: UM.Theme.getColor("icon")
}
Rectangle
{
id: circle
anchors.fill: parent
radius: width
anchors.verticalCenter: parent.verticalCenter
visible: icon == ""
visible: icon === "" && custom_icon === ""
border.width: UM.Theme.getSize("thick_lining").width
border.color: UM.Theme.getColor("text")