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. # Cura is released under the terms of the LGPLv3 or higher.
import enum import enum
import os import os
@ -147,6 +147,7 @@ class CuraApplication(QtApplication):
DefinitionChangesContainer = Resources.UserType + 10 DefinitionChangesContainer = Resources.UserType + 10
SettingVisibilityPreset = Resources.UserType + 11 SettingVisibilityPreset = Resources.UserType + 11
IntentInstanceContainer = Resources.UserType + 12 IntentInstanceContainer = Resources.UserType + 12
ImageFiles = Resources.UserType + 13
pyqtEnum(ResourceTypes) pyqtEnum(ResourceTypes)
@ -425,6 +426,7 @@ class CuraApplication(QtApplication):
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility") Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility")
Resources.addStorageType(self.ResourceTypes.IntentInstanceContainer, "intent") 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.QualityInstanceContainer, "quality")
self._container_registry.addResourceType(self.ResourceTypes.QualityChangesInstanceContainer, "quality_changes") 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.MachineStack, "machine")
self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes") self._container_registry.addResourceType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
self._container_registry.addResourceType(self.ResourceTypes.IntentInstanceContainer, "intent") 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.QmlFiles, "qml")
Resources.addType(self.ResourceTypes.Firmware, "firmware") 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. # Cura is released under the terms of the LGPLv3 or higher.
import glob import glob
import os import os
@ -55,7 +55,9 @@ class CuraPackageManager(PackageManager):
def initialize(self) -> None: def initialize(self) -> None:
self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer) self._installation_dirs_dict["materials"] = Resources.getStoragePath(CuraApplication.ResourceTypes.MaterialInstanceContainer)
self._installation_dirs_dict["qualities"] = Resources.getStoragePath(CuraApplication.ResourceTypes.QualityInstanceContainer) 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). # 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 # 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. # Cura is released under the terms of the LGPLv3 or higher.
import collections 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 import cura
from UM import i18nCatalog from UM import i18nCatalog
from UM.Logger import Logger from UM.Logger import Logger
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Resources import Resources
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import ContainerInterface from UM.Settings.Interfaces import ContainerInterface
from cura.Machines.Models.IntentCategoryModel import IntentCategoryModel
from cura.Settings.IntentManager import IntentManager from cura.Settings.IntentManager import IntentManager
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
class IntentSelectionModel(ListModel): class IntentSelectionModel(ListModel):
NameRole = Qt.ItemDataRole.UserRole + 1 NameRole = Qt.ItemDataRole.UserRole + 1
IntentCategoryRole = Qt.ItemDataRole.UserRole + 2 IntentCategoryRole = Qt.ItemDataRole.UserRole + 2
WeightRole = Qt.ItemDataRole.UserRole + 3 WeightRole = Qt.ItemDataRole.UserRole + 3
DescriptionRole = Qt.ItemDataRole.UserRole + 4 DescriptionRole = Qt.ItemDataRole.UserRole + 4
IconRole = Qt.ItemDataRole.UserRole + 5 IconRole = Qt.ItemDataRole.UserRole + 5
CustomIconRole = Qt.ItemDataRole.UserRole + 6
def __init__(self, parent: Optional[QObject] = None) -> None: def __init__(self, parent: Optional[QObject] = None) -> None:
super().__init__(parent) super().__init__(parent)
@ -33,6 +36,7 @@ class IntentSelectionModel(ListModel):
self.addRoleName(self.WeightRole, "weight") self.addRoleName(self.WeightRole, "weight")
self.addRoleName(self.DescriptionRole, "description") self.addRoleName(self.DescriptionRole, "description")
self.addRoleName(self.IconRole, "icon") self.addRoleName(self.IconRole, "icon")
self.addRoleName(self.CustomIconRole, "custom_icon")
application = cura.CuraApplication.CuraApplication.getInstance() application = cura.CuraApplication.CuraApplication.getInstance()
@ -53,30 +57,8 @@ class IntentSelectionModel(ListModel):
self._onChange() self._onChange()
@staticmethod _default_intent_categories = ["default", "visual", "engineering", "quick"]
def _getDefaultProfileInformation() -> OrderedDict[str, dict]: _icons = {"default": "GearCheck", "visual": "Visual", "engineering": "Nut", "quick": "SpeedOMeter"}
""" 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: def _onContainerChange(self, container: ContainerInterface) -> None:
"""Updates the list of intents if an intent profile was added or removed.""" """Updates the list of intents if an intent profile was added or removed."""
@ -102,24 +84,41 @@ class IntentSelectionModel(ListModel):
self.setItems([]) self.setItems([])
return return
default_profile_info = self._getDefaultProfileInformation()
available_categories = IntentManager.getInstance().currentAvailableIntentCategories() available_categories = IntentManager.getInstance().currentAvailableIntentCategories()
result = []
for i, category in enumerate(available_categories):
profile_info = default_profile_info.get(category, {})
try: result = []
weight = list(default_profile_info.keys()).index(category) for category in available_categories:
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]
icon = intent_metadata.get("icon", None)
if icon is not None:
icon = QUrl.fromLocalFile(
Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.ImageFiles, icon))
result.append({ result.append({
"name": profile_info.get("name", category.title()), "name": intent_metadata.get("name", category.title()),
"description": profile_info.get("description", None), "description": intent_metadata.get("description", None),
"icon" : profile_info.get("icon", ""), "custom_icon": icon,
"icon": None,
"intent_category": category, "intent_category": category,
"weight": weight, "weight": 5,
}) })
result.sort(key=lambda k: k["weight"]) 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. # Cura is released under the terms of the LGPLv3 or higher.
from UM.Settings.SQLQueryFactory import SQLQueryFactory from UM.Settings.SQLQueryFactory import SQLQueryFactory
@ -20,6 +20,8 @@ class IntentDatabaseHandler(DatabaseMetadataContainerController):
"definition": "text", "definition": "text",
"material": "text", "material": "text",
"version": "text", "version": "text",
"setting_version": "text" "setting_version": "text",
"icon": "text",
"description": "text",
})) }))
self._container_type = InstanceContainer 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. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
@ -32,6 +32,7 @@ Item
{ {
profileName: model.name profileName: model.name
icon: model.icon icon: model.icon
custom_icon: model.custom_icon
tooltipText: model.description ? model.description : "" tooltipText: model.description ? model.description : ""
selected: Cura.MachineManager.activeIntentCategory == model.intent_category 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. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
@ -19,6 +19,7 @@ Rectangle
property bool selected: false property bool selected: false
property string profileName: "" property string profileName: ""
property string icon: "" property string icon: ""
property string custom_icon: ""
property alias tooltipText: tooltip.text property alias tooltipText: tooltip.text
signal clicked() signal clicked()
@ -55,22 +56,32 @@ Rectangle
id: intentIcon id: intentIcon
width: UM.Theme.getSize("recommended_button_icon").width width: UM.Theme.getSize("recommended_button_icon").width
height: UM.Theme.getSize("recommended_button_icon").height height: UM.Theme.getSize("recommended_button_icon").height
UM.ColorImage UM.ColorImage
{ {
anchors.fill: parent anchors.fill: parent
anchors.centerIn: parent anchors.centerIn: parent
visible: icon != "" visible: icon !== ""
source: UM.Theme.getIcon(icon) source: UM.Theme.getIcon(icon)
color: UM.Theme.getColor("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 Rectangle
{ {
id: circle id: circle
anchors.fill: parent anchors.fill: parent
radius: width radius: width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: icon == "" visible: icon === "" && custom_icon === ""
border.width: UM.Theme.getSize("thick_lining").width border.width: UM.Theme.getSize("thick_lining").width
border.color: UM.Theme.getColor("text") border.color: UM.Theme.getColor("text")