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

ExtruderStack.py « Settings « cura - github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e93193818c6b77625460446d96728d0ede6de2a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.

from typing import Any, Dict, TYPE_CHECKING, Optional

from PyQt6.QtCore import pyqtProperty, pyqtSignal

from UM.Decorators import override
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
from UM.Util import parseBool

import cura.CuraApplication

from . import Exceptions
from .CuraContainerStack import CuraContainerStack, _ContainerIndexes
from .ExtruderManager import ExtruderManager

if TYPE_CHECKING:
    from cura.Settings.GlobalStack import GlobalStack


class ExtruderStack(CuraContainerStack):
    """Represents an Extruder and its related containers."""

    def __init__(self, container_id: str) -> None:
        super().__init__(container_id)

        self.setMetaDataEntry("type", "extruder_train") # For backward compatibility

        self.propertiesChanged.connect(self._onPropertiesChanged)

        self.setDirty(False)

    enabledChanged = pyqtSignal()

    @override(ContainerStack)
    def setNextStack(self, stack: CuraContainerStack, connect_signals: bool = True) -> None:
        """Overridden from ContainerStack

        This will set the next stack and ensure that we register this stack as an extruder.
        """

        super().setNextStack(stack)
        stack.addExtruder(self)
        self.setMetaDataEntry("machine", stack.id)

    @override(ContainerStack)
    def getNextStack(self) -> Optional["GlobalStack"]:
        return super().getNextStack()

    @pyqtProperty(int, constant = True)
    def position(self) -> int:
        return int(self.getMetaDataEntry("position"))

    def setEnabled(self, enabled: bool) -> None:
        if self.getMetaDataEntry("enabled", True) == enabled: # No change.
            return # Don't emit a signal then.
        self.setMetaDataEntry("enabled", str(enabled))
        self.enabledChanged.emit()

    @pyqtProperty(bool, notify = enabledChanged)
    def isEnabled(self) -> bool:
        return parseBool(self.getMetaDataEntry("enabled", "True"))

    @classmethod
    def getLoadingPriority(cls) -> int:
        return 3

    compatibleMaterialDiameterChanged = pyqtSignal()

    def getCompatibleMaterialDiameter(self) -> float:
        """Return the filament diameter that the machine requires.

        If the machine has no requirement for the diameter, -1 is returned.
        :return: The filament diameter for the printer
        """

        context = PropertyEvaluationContext(self)
        context.context["evaluate_from_container_index"] = _ContainerIndexes.Variant

        return float(self.getProperty("material_diameter", "value", context = context))

    def setCompatibleMaterialDiameter(self, value: float) -> None:
        old_approximate_diameter = self.getApproximateMaterialDiameter()
        if self.getCompatibleMaterialDiameter() != value:
            self.definitionChanges.setProperty("material_diameter", "value", value)
            self.compatibleMaterialDiameterChanged.emit()

            # Emit approximate diameter changed signal if needed
            if old_approximate_diameter != self.getApproximateMaterialDiameter():
                self.approximateMaterialDiameterChanged.emit()

    compatibleMaterialDiameter = pyqtProperty(float, fset = setCompatibleMaterialDiameter,
                                              fget = getCompatibleMaterialDiameter,
                                              notify = compatibleMaterialDiameterChanged)

    approximateMaterialDiameterChanged = pyqtSignal()

    def getApproximateMaterialDiameter(self) -> float:
        """Return the approximate filament diameter that the machine requires.

        The approximate material diameter is the material diameter rounded to
        the nearest millimetre.

        If the machine has no requirement for the diameter, -1 is returned.

        :return: The approximate filament diameter for the printer
        """

        return round(self.getCompatibleMaterialDiameter())

    approximateMaterialDiameter = pyqtProperty(float, fget = getApproximateMaterialDiameter,
                                               notify = approximateMaterialDiameterChanged)

    @override(ContainerStack)
    def getProperty(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> Any:
        """Overridden from ContainerStack

        It will perform a few extra checks when trying to get properties.

        The two extra checks it currently does is to ensure a next stack is set and to bypass
        the extruder when the property is not settable per extruder.

        :throws Exceptions.NoGlobalStackError Raised when trying to get a property from an extruder without
        having a next stack set.
        """

        if not self._next_stack:
            raise Exceptions.NoGlobalStackError("Extruder {id} is missing the next stack!".format(id = self.id))

        if context:
            context.pushContainer(self)

        if not super().getProperty(key, "settable_per_extruder", context):
            result = self.getNextStack().getProperty(key, property_name, context)
            if context:
                context.popContainer()
            return result

        limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
        if limit_to_extruder is not None:
            if limit_to_extruder == -1:
                limit_to_extruder = int(cura.CuraApplication.CuraApplication.getInstance().getMachineManager().defaultExtruderPosition)
            limit_to_extruder = str(limit_to_extruder)

        if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder):
            try:
                result = self.getNextStack().extruderList[int(limit_to_extruder)].getProperty(key, property_name, context)
                if result is not None:
                    if context:
                        context.popContainer()
                    return result
            except IndexError:
                pass

        result = super().getProperty(key, property_name, context)
        if context:
            context.popContainer()
        return result

    @override(CuraContainerStack)
    def _getMachineDefinition(self) -> ContainerInterface:
        if not self.getNextStack():
            raise Exceptions.NoGlobalStackError("Extruder {id} is missing the next stack!".format(id = self.id))

        return self.getNextStack()._getMachineDefinition()

    @override(CuraContainerStack)
    def deserialize(self, contents: str, file_name: Optional[str] = None) -> None:
        super().deserialize(contents, file_name)
        if "enabled" not in self.getMetaData():
            self.setMetaDataEntry("enabled", "True")

    def _onPropertiesChanged(self, key: str, properties: Dict[str, Any]) -> None:
        # When there is a setting that is not settable per extruder that depends on a value from a setting that is,
        # we do not always get properly informed that we should re-evaluate the setting. So make sure to indicate
        # something changed for those settings.
        if not self.getNextStack():
            return #There are no global settings to depend on.
        definitions = self.getNextStack().definition.findDefinitions(key = key)
        if definitions:
            has_global_dependencies = False
            for relation in definitions[0].relations:
                if not getattr(relation.target, "settable_per_extruder", True):
                    has_global_dependencies = True
                    break

            if has_global_dependencies:
                self.getNextStack().propertiesChanged.emit(key, properties)


extruder_stack_mime = MimeType(
    name = "application/x-cura-extruderstack",
    comment = "Cura Extruder Stack",
    suffixes = ["extruder.cfg"]
)

MimeTypeDatabase.addMimeType(extruder_stack_mime)
ContainerRegistry.addContainerTypeByName(ExtruderStack, "extruder_stack", extruder_stack_mime.name)