mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-09-27 12:13:15 +08:00
Merge branch 'mypy_fixes' of ssh://github.com/Ultimaker/Cura into mypy_fixes
This commit is contained in:
commit
5bf553c63c
@ -1,32 +1,30 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from typing import Tuple, Optional
|
||||||
|
|
||||||
from cura.Backups.BackupsManager import BackupsManager
|
from cura.Backups.BackupsManager import BackupsManager
|
||||||
|
|
||||||
|
|
||||||
|
## The back-ups API provides a version-proof bridge between Cura's
|
||||||
|
# BackupManager and plug-ins that hook into it.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ``from cura.API import CuraAPI
|
||||||
|
# api = CuraAPI()
|
||||||
|
# api.backups.createBackup()
|
||||||
|
# api.backups.restoreBackup(my_zip_file, {"cura_release": "3.1"})``
|
||||||
class Backups:
|
class Backups:
|
||||||
"""
|
|
||||||
The backups API provides a version-proof bridge between Cura's BackupManager and plugins that hook into it.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
from cura.API import CuraAPI
|
|
||||||
api = CuraAPI()
|
|
||||||
api.backups.createBackup()
|
|
||||||
api.backups.restoreBackup(my_zip_file, {"cura_release": "3.1"})
|
|
||||||
"""
|
|
||||||
|
|
||||||
manager = BackupsManager() # Re-used instance of the backups manager.
|
manager = BackupsManager() # Re-used instance of the backups manager.
|
||||||
|
|
||||||
def createBackup(self) -> (bytes, dict):
|
## Create a new back-up using the BackupsManager.
|
||||||
"""
|
# \return Tuple containing a ZIP file with the back-up data and a dict
|
||||||
Create a new backup using the BackupsManager.
|
# with metadata about the back-up.
|
||||||
:return: Tuple containing a ZIP file with the backup data and a dict with meta data about the backup.
|
def createBackup(self) -> Tuple[Optional[bytes], Optional[dict]]:
|
||||||
"""
|
|
||||||
return self.manager.createBackup()
|
return self.manager.createBackup()
|
||||||
|
|
||||||
|
## Restore a back-up using the BackupsManager.
|
||||||
|
# \param zip_file A ZIP file containing the actual back-up data.
|
||||||
|
# \param meta_data Some metadata needed for restoring a back-up, like the
|
||||||
|
# Cura version number.
|
||||||
def restoreBackup(self, zip_file: bytes, meta_data: dict) -> None:
|
def restoreBackup(self, zip_file: bytes, meta_data: dict) -> None:
|
||||||
"""
|
|
||||||
Restore a backup using the BackupManager.
|
|
||||||
:param zip_file: A ZIP file containing the actual backup data.
|
|
||||||
:param meta_data: Some meta data needed for restoring a backup, like the Cura version number.
|
|
||||||
"""
|
|
||||||
return self.manager.restoreBackup(zip_file, meta_data)
|
return self.manager.restoreBackup(zip_file, meta_data)
|
||||||
|
@ -3,14 +3,13 @@
|
|||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from cura.API.Backups import Backups
|
from cura.API.Backups import Backups
|
||||||
|
|
||||||
|
## The official Cura API that plug-ins can use to interact with Cura.
|
||||||
|
#
|
||||||
|
# Python does not technically prevent talking to other classes as well, but
|
||||||
|
# this API provides a version-safe interface with proper deprecation warnings
|
||||||
|
# etc. Usage of any other methods than the ones provided in this API can cause
|
||||||
|
# plug-ins to be unstable.
|
||||||
class CuraAPI:
|
class CuraAPI:
|
||||||
"""
|
|
||||||
The official Cura API that plugins can use to interact with Cura.
|
|
||||||
Python does not technically prevent talking to other classes as well,
|
|
||||||
but this API provides a version-safe interface with proper deprecation warnings etc.
|
|
||||||
Usage of any other methods than the ones provided in this API can cause plugins to be unstable.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# For now we use the same API version to be consistent.
|
# For now we use the same API version to be consistent.
|
||||||
VERSION = PluginRegistry.APIVersion
|
VERSION = PluginRegistry.APIVersion
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Math.Polygon import Polygon
|
from UM.Math.Polygon import Polygon
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from cura.Arranging.ShapeArray import ShapeArray
|
from cura.Arranging.ShapeArray import ShapeArray
|
||||||
from cura.Scene import ZOffsetDecorator
|
from cura.Scene import ZOffsetDecorator
|
||||||
|
|
||||||
@ -85,8 +87,7 @@ class Arrange:
|
|||||||
# \param node
|
# \param node
|
||||||
# \param offset_shape_arr ShapeArray with offset, for placing the shape
|
# \param offset_shape_arr ShapeArray with offset, for placing the shape
|
||||||
# \param hull_shape_arr ShapeArray without offset, used to find location
|
# \param hull_shape_arr ShapeArray without offset, used to find location
|
||||||
def findNodePlacement(self, node, offset_shape_arr, hull_shape_arr, step = 1):
|
def findNodePlacement(self, node: SceneNode, offset_shape_arr: ShapeArray, hull_shape_arr: ShapeArray, step = 1):
|
||||||
new_node = copy.deepcopy(node)
|
|
||||||
best_spot = self.bestSpot(
|
best_spot = self.bestSpot(
|
||||||
hull_shape_arr, start_prio = self._last_priority, step = step)
|
hull_shape_arr, start_prio = self._last_priority, step = step)
|
||||||
x, y = best_spot.x, best_spot.y
|
x, y = best_spot.x, best_spot.y
|
||||||
@ -95,21 +96,21 @@ class Arrange:
|
|||||||
self._last_priority = best_spot.priority
|
self._last_priority = best_spot.priority
|
||||||
|
|
||||||
# Ensure that the object is above the build platform
|
# Ensure that the object is above the build platform
|
||||||
new_node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
|
node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
|
||||||
if new_node.getBoundingBox():
|
if node.getBoundingBox():
|
||||||
center_y = new_node.getWorldPosition().y - new_node.getBoundingBox().bottom
|
center_y = node.getWorldPosition().y - node.getBoundingBox().bottom
|
||||||
else:
|
else:
|
||||||
center_y = 0
|
center_y = 0
|
||||||
|
|
||||||
if x is not None: # We could find a place
|
if x is not None: # We could find a place
|
||||||
new_node.setPosition(Vector(x, center_y, y))
|
node.setPosition(Vector(x, center_y, y))
|
||||||
found_spot = True
|
found_spot = True
|
||||||
self.place(x, y, offset_shape_arr) # place the object in arranger
|
self.place(x, y, offset_shape_arr) # place the object in arranger
|
||||||
else:
|
else:
|
||||||
Logger.log("d", "Could not find spot!"),
|
Logger.log("d", "Could not find spot!"),
|
||||||
found_spot = False
|
found_spot = False
|
||||||
new_node.setPosition(Vector(200, center_y, 100))
|
node.setPosition(Vector(200, center_y, 100))
|
||||||
return new_node, found_spot
|
return found_spot
|
||||||
|
|
||||||
## Fill priority, center is best. Lower value is better
|
## Fill priority, center is best. Lower value is better
|
||||||
# This is a strategy for the arranger.
|
# This is a strategy for the arranger.
|
||||||
|
@ -20,14 +20,14 @@ from typing import List
|
|||||||
|
|
||||||
## Do arrangements on multiple build plates (aka builtiplexer)
|
## Do arrangements on multiple build plates (aka builtiplexer)
|
||||||
class ArrangeArray:
|
class ArrangeArray:
|
||||||
def __init__(self, x: int, y: int, fixed_nodes: List[SceneNode]):
|
def __init__(self, x: int, y: int, fixed_nodes: List[SceneNode]) -> None:
|
||||||
self._x = x
|
self._x = x
|
||||||
self._y = y
|
self._y = y
|
||||||
self._fixed_nodes = fixed_nodes
|
self._fixed_nodes = fixed_nodes
|
||||||
self._count = 0
|
self._count = 0
|
||||||
self._first_empty = None
|
self._first_empty = None
|
||||||
self._has_empty = False
|
self._has_empty = False
|
||||||
self._arrange = []
|
self._arrange = [] # type: List[Arrange]
|
||||||
|
|
||||||
def _update_first_empty(self):
|
def _update_first_empty(self):
|
||||||
for i, a in enumerate(self._arrange):
|
for i, a in enumerate(self._arrange):
|
||||||
@ -48,16 +48,17 @@ class ArrangeArray:
|
|||||||
return self._count
|
return self._count
|
||||||
|
|
||||||
def get(self, index):
|
def get(self, index):
|
||||||
|
print(self._arrange)
|
||||||
return self._arrange[index]
|
return self._arrange[index]
|
||||||
|
|
||||||
def getFirstEmpty(self):
|
def getFirstEmpty(self):
|
||||||
if not self._is_empty:
|
if not self._has_empty:
|
||||||
self.add()
|
self.add()
|
||||||
return self._arrange[self._first_empty]
|
return self._arrange[self._first_empty]
|
||||||
|
|
||||||
|
|
||||||
class ArrangeObjectsAllBuildPlatesJob(Job):
|
class ArrangeObjectsAllBuildPlatesJob(Job):
|
||||||
def __init__(self, nodes: List[SceneNode], min_offset = 8):
|
def __init__(self, nodes: List[SceneNode], min_offset = 8) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._nodes = nodes
|
self._nodes = nodes
|
||||||
self._min_offset = min_offset
|
self._min_offset = min_offset
|
||||||
|
@ -20,7 +20,7 @@ from typing import List
|
|||||||
|
|
||||||
|
|
||||||
class ArrangeObjectsJob(Job):
|
class ArrangeObjectsJob(Job):
|
||||||
def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8):
|
def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._nodes = nodes
|
self._nodes = nodes
|
||||||
self._fixed_nodes = fixed_nodes
|
self._fixed_nodes = fixed_nodes
|
||||||
|
@ -17,26 +17,23 @@ from UM.Resources import Resources
|
|||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
|
||||||
|
## The back-up class holds all data about a back-up.
|
||||||
|
#
|
||||||
|
# It is also responsible for reading and writing the zip file to the user data
|
||||||
|
# folder.
|
||||||
class Backup:
|
class Backup:
|
||||||
"""
|
|
||||||
The backup class holds all data about a backup.
|
|
||||||
It is also responsible for reading and writing the zip file to the user data folder.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# These files should be ignored when making a backup.
|
# These files should be ignored when making a backup.
|
||||||
IGNORED_FILES = [r"cura\.log", r"plugins\.json", r"cache", r"__pycache__", r"\.qmlc", r"\.pyc"]
|
IGNORED_FILES = [r"cura\.log", r"plugins\.json", r"cache", r"__pycache__", r"\.qmlc", r"\.pyc"]
|
||||||
|
|
||||||
# Re-use translation catalog.
|
# Re-use translation catalog.
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
def __init__(self, zip_file: bytes = None, meta_data: dict = None):
|
def __init__(self, zip_file: bytes = None, meta_data: dict = None) -> None:
|
||||||
self.zip_file = zip_file # type: Optional[bytes]
|
self.zip_file = zip_file # type: Optional[bytes]
|
||||||
self.meta_data = meta_data # type: Optional[dict]
|
self.meta_data = meta_data # type: Optional[dict]
|
||||||
|
|
||||||
def makeFromCurrent(self) -> (bool, Optional[str]):
|
## Create a back-up from the current user config folder.
|
||||||
"""
|
def makeFromCurrent(self) -> None:
|
||||||
Create a backup from the current user config folder.
|
|
||||||
"""
|
|
||||||
cura_release = CuraApplication.getInstance().getVersion()
|
cura_release = CuraApplication.getInstance().getVersion()
|
||||||
version_data_dir = Resources.getDataStoragePath()
|
version_data_dir = Resources.getDataStoragePath()
|
||||||
|
|
||||||
@ -57,6 +54,8 @@ class Backup:
|
|||||||
# Create an empty buffer and write the archive to it.
|
# Create an empty buffer and write the archive to it.
|
||||||
buffer = io.BytesIO()
|
buffer = io.BytesIO()
|
||||||
archive = self._makeArchive(buffer, version_data_dir)
|
archive = self._makeArchive(buffer, version_data_dir)
|
||||||
|
if archive is None:
|
||||||
|
return
|
||||||
files = archive.namelist()
|
files = archive.namelist()
|
||||||
|
|
||||||
# Count the metadata items. We do this in a rather naive way at the moment.
|
# Count the metadata items. We do this in a rather naive way at the moment.
|
||||||
@ -75,12 +74,10 @@ class Backup:
|
|||||||
"plugin_count": str(plugin_count)
|
"plugin_count": str(plugin_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Make a full archive from the given root path with the given name.
|
||||||
|
# \param root_path The root directory to archive recursively.
|
||||||
|
# \return The archive as bytes.
|
||||||
def _makeArchive(self, buffer: "io.BytesIO", root_path: str) -> Optional[ZipFile]:
|
def _makeArchive(self, buffer: "io.BytesIO", root_path: str) -> Optional[ZipFile]:
|
||||||
"""
|
|
||||||
Make a full archive from the given root path with the given name.
|
|
||||||
:param root_path: The root directory to archive recursively.
|
|
||||||
:return: The archive as bytes.
|
|
||||||
"""
|
|
||||||
ignore_string = re.compile("|".join(self.IGNORED_FILES))
|
ignore_string = re.compile("|".join(self.IGNORED_FILES))
|
||||||
try:
|
try:
|
||||||
archive = ZipFile(buffer, "w", ZIP_DEFLATED)
|
archive = ZipFile(buffer, "w", ZIP_DEFLATED)
|
||||||
@ -99,15 +96,13 @@ class Backup:
|
|||||||
"Could not create archive from user data directory: {}".format(error)))
|
"Could not create archive from user data directory: {}".format(error)))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
## Show a UI message.
|
||||||
def _showMessage(self, message: str) -> None:
|
def _showMessage(self, message: str) -> None:
|
||||||
"""Show a UI message"""
|
|
||||||
Message(message, title=self.catalog.i18nc("@info:title", "Backup"), lifetime=30).show()
|
Message(message, title=self.catalog.i18nc("@info:title", "Backup"), lifetime=30).show()
|
||||||
|
|
||||||
|
## Restore this back-up.
|
||||||
|
# \return Whether we had success or not.
|
||||||
def restore(self) -> bool:
|
def restore(self) -> bool:
|
||||||
"""
|
|
||||||
Restore this backups
|
|
||||||
:return: A boolean whether we had success or not.
|
|
||||||
"""
|
|
||||||
if not self.zip_file or not self.meta_data or not self.meta_data.get("cura_release", None):
|
if not self.zip_file or not self.meta_data or not self.meta_data.get("cura_release", None):
|
||||||
# We can restore without the minimum required information.
|
# We can restore without the minimum required information.
|
||||||
Logger.log("w", "Tried to restore a Cura backup without having proper data or meta data.")
|
Logger.log("w", "Tried to restore a Cura backup without having proper data or meta data.")
|
||||||
@ -140,14 +135,12 @@ class Backup:
|
|||||||
|
|
||||||
return extracted
|
return extracted
|
||||||
|
|
||||||
|
## Extract the whole archive to the given target path.
|
||||||
|
# \param archive The archive as ZipFile.
|
||||||
|
# \param target_path The target path.
|
||||||
|
# \return Whether we had success or not.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extractArchive(archive: "ZipFile", target_path: str) -> bool:
|
def _extractArchive(archive: "ZipFile", target_path: str) -> bool:
|
||||||
"""
|
|
||||||
Extract the whole archive to the given target path.
|
|
||||||
:param archive: The archive as ZipFile.
|
|
||||||
:param target_path: The target path.
|
|
||||||
:return: A boolean whether we had success or not.
|
|
||||||
"""
|
|
||||||
Logger.log("d", "Removing current data in location: %s", target_path)
|
Logger.log("d", "Removing current data in location: %s", target_path)
|
||||||
Resources.factoryReset()
|
Resources.factoryReset()
|
||||||
Logger.log("d", "Extracting backup to location: %s", target_path)
|
Logger.log("d", "Extracting backup to location: %s", target_path)
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from typing import Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from cura.Backups.Backup import Backup
|
from cura.Backups.Backup import Backup
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
|
||||||
|
## The BackupsManager is responsible for managing the creating and restoring of
|
||||||
|
# back-ups.
|
||||||
|
#
|
||||||
|
# Back-ups themselves are represented in a different class.
|
||||||
class BackupsManager:
|
class BackupsManager:
|
||||||
"""
|
|
||||||
The BackupsManager is responsible for managing the creating and restoring of backups.
|
|
||||||
Backups themselves are represented in a different class.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._application = CuraApplication.getInstance()
|
self._application = CuraApplication.getInstance()
|
||||||
|
|
||||||
def createBackup(self) -> (Optional[bytes], Optional[dict]):
|
## Get a back-up of the current configuration.
|
||||||
"""
|
# \return A tuple containing a ZipFile (the actual back-up) and a dict
|
||||||
Get a backup of the current configuration.
|
# containing some metadata (like version).
|
||||||
:return: A Tuple containing a ZipFile (the actual backup) and a dict containing some meta data (like version).
|
def createBackup(self) -> Tuple[Optional[bytes], Optional[dict]]:
|
||||||
"""
|
|
||||||
self._disableAutoSave()
|
self._disableAutoSave()
|
||||||
backup = Backup()
|
backup = Backup()
|
||||||
backup.makeFromCurrent()
|
backup.makeFromCurrent()
|
||||||
@ -27,12 +26,11 @@ class BackupsManager:
|
|||||||
# We don't return a Backup here because we want plugins only to interact with our API and not full objects.
|
# We don't return a Backup here because we want plugins only to interact with our API and not full objects.
|
||||||
return backup.zip_file, backup.meta_data
|
return backup.zip_file, backup.meta_data
|
||||||
|
|
||||||
|
## Restore a back-up from a given ZipFile.
|
||||||
|
# \param zip_file A bytes object containing the actual back-up.
|
||||||
|
# \param meta_data A dict containing some metadata that is needed to
|
||||||
|
# restore the back-up correctly.
|
||||||
def restoreBackup(self, zip_file: bytes, meta_data: dict) -> None:
|
def restoreBackup(self, zip_file: bytes, meta_data: dict) -> None:
|
||||||
"""
|
|
||||||
Restore a backup from a given ZipFile.
|
|
||||||
:param zip_file: A bytes object containing the actual backup.
|
|
||||||
:param meta_data: A dict containing some meta data that is needed to restore the backup correctly.
|
|
||||||
"""
|
|
||||||
if not meta_data.get("cura_release", None):
|
if not meta_data.get("cura_release", None):
|
||||||
# If there is no "cura_release" specified in the meta data, we don't execute a backup restore.
|
# If there is no "cura_release" specified in the meta data, we don't execute a backup restore.
|
||||||
Logger.log("w", "Tried to restore a backup without specifying a Cura version number.")
|
Logger.log("w", "Tried to restore a backup without specifying a Cura version number.")
|
||||||
@ -47,10 +45,11 @@ class BackupsManager:
|
|||||||
# We don't want to store the data at this point as that would override the just-restored backup.
|
# We don't want to store the data at this point as that would override the just-restored backup.
|
||||||
self._application.windowClosed(save_data=False)
|
self._application.windowClosed(save_data=False)
|
||||||
|
|
||||||
|
## Here we try to disable the auto-save plug-in as it might interfere with
|
||||||
|
# restoring a back-up.
|
||||||
def _disableAutoSave(self):
|
def _disableAutoSave(self):
|
||||||
"""Here we try to disable the auto-save plugin as it might interfere with restoring a backup."""
|
|
||||||
self._application.setSaveDataEnabled(False)
|
self._application.setSaveDataEnabled(False)
|
||||||
|
|
||||||
|
## Re-enable auto-save after we're done.
|
||||||
def _enableAutoSave(self):
|
def _enableAutoSave(self):
|
||||||
"""Re-enable auto-save after we're done."""
|
|
||||||
self._application.setSaveDataEnabled(True)
|
self._application.setSaveDataEnabled(True)
|
||||||
|
@ -225,6 +225,8 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
|
||||||
self._container_registry_class = CuraContainerRegistry
|
self._container_registry_class = CuraContainerRegistry
|
||||||
|
from cura.CuraPackageManager import CuraPackageManager
|
||||||
|
self._package_manager_class = CuraPackageManager
|
||||||
|
|
||||||
# Adds command line options to the command line parser. This should be called after the application is created and
|
# Adds command line options to the command line parser. This should be called after the application is created and
|
||||||
# before the pre-start.
|
# before the pre-start.
|
||||||
@ -511,7 +513,6 @@ class CuraApplication(QtApplication):
|
|||||||
preferences.addPreference("cura/asked_dialog_on_project_save", False)
|
preferences.addPreference("cura/asked_dialog_on_project_save", False)
|
||||||
preferences.addPreference("cura/choice_on_profile_override", "always_ask")
|
preferences.addPreference("cura/choice_on_profile_override", "always_ask")
|
||||||
preferences.addPreference("cura/choice_on_open_project", "always_ask")
|
preferences.addPreference("cura/choice_on_open_project", "always_ask")
|
||||||
preferences.addPreference("cura/not_arrange_objects_on_load", False)
|
|
||||||
preferences.addPreference("cura/use_multi_build_plate", False)
|
preferences.addPreference("cura/use_multi_build_plate", False)
|
||||||
|
|
||||||
preferences.addPreference("cura/currency", "€")
|
preferences.addPreference("cura/currency", "€")
|
||||||
@ -1601,9 +1602,7 @@ class CuraApplication(QtApplication):
|
|||||||
self._currently_loading_files.remove(filename)
|
self._currently_loading_files.remove(filename)
|
||||||
|
|
||||||
self.fileLoaded.emit(filename)
|
self.fileLoaded.emit(filename)
|
||||||
arrange_objects_on_load = (
|
arrange_objects_on_load = not self.getPreferences().getValue("cura/use_multi_build_plate")
|
||||||
not self.getPreferences().getValue("cura/use_multi_build_plate") or
|
|
||||||
not self.getPreferences().getValue("cura/not_arrange_objects_on_load"))
|
|
||||||
target_build_plate = self.getMultiBuildPlateModel().activeBuildPlate if arrange_objects_on_load else -1
|
target_build_plate = self.getMultiBuildPlateModel().activeBuildPlate if arrange_objects_on_load else -1
|
||||||
|
|
||||||
root = self.getController().getScene().getRoot()
|
root = self.getController().getScene().getRoot()
|
||||||
@ -1676,7 +1675,7 @@ class CuraApplication(QtApplication):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher
|
# Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher
|
||||||
node, _ = arranger.findNodePlacement(node, offset_shape_arr, hull_shape_arr, step = 10)
|
arranger.findNodePlacement(node, offset_shape_arr, hull_shape_arr, step = 10)
|
||||||
|
|
||||||
# This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy
|
# This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy
|
||||||
# of BuildPlateDecorator produces one that's associated with build plate -1. So, here we need to check if
|
# of BuildPlateDecorator produces one that's associated with build plate -1. So, here we need to check if
|
||||||
|
@ -7,8 +7,11 @@ from UM.Resources import Resources #To find storage paths for some resource type
|
|||||||
|
|
||||||
|
|
||||||
class CuraPackageManager(PackageManager):
|
class CuraPackageManager(PackageManager):
|
||||||
def __init__(self, parent = None):
|
def __init__(self, application, parent = None):
|
||||||
super().__init__(parent)
|
super().__init__(application, parent)
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
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)
|
||||||
|
|
||||||
|
super().initialize()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional, Any, Dict, Union, TYPE_CHECKING
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
@ -9,6 +9,9 @@ from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
|||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from cura.Machines.QualityGroup import QualityGroup
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# A metadata / container combination. Use getContainer() to get the container corresponding to the metadata.
|
# A metadata / container combination. Use getContainer() to get the container corresponding to the metadata.
|
||||||
@ -23,10 +26,16 @@ from UM.Settings.InstanceContainer import InstanceContainer
|
|||||||
class ContainerNode:
|
class ContainerNode:
|
||||||
__slots__ = ("metadata", "container", "children_map")
|
__slots__ = ("metadata", "container", "children_map")
|
||||||
|
|
||||||
def __init__(self, metadata: Optional[dict] = None):
|
def __init__(self, metadata: Optional[Dict[str, Any]] = None) -> None:
|
||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
self.container = None
|
self.container = None
|
||||||
self.children_map = OrderedDict()
|
self.children_map = OrderedDict() #type: OrderedDict[str, Union[QualityGroup, ContainerNode]]
|
||||||
|
|
||||||
|
## Get an entry value from the metadata
|
||||||
|
def getMetaDataEntry(self, entry: str, default: Any = None) -> Any:
|
||||||
|
if self.metadata is None:
|
||||||
|
return default
|
||||||
|
return self.metadata.get(entry, default)
|
||||||
|
|
||||||
def getChildNode(self, child_key: str) -> Optional["ContainerNode"]:
|
def getChildNode(self, child_key: str) -> Optional["ContainerNode"]:
|
||||||
return self.children_map.get(child_key)
|
return self.children_map.get(child_key)
|
||||||
@ -50,4 +59,4 @@ class ContainerNode:
|
|||||||
return self.container
|
return self.container
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return "%s[%s]" % (self.__class__.__name__, self.metadata.get("id"))
|
return "%s[%s]" % (self.__class__.__name__, self.getMetaDataEntry("id"))
|
||||||
|
@ -18,10 +18,10 @@ from cura.Machines.MaterialNode import MaterialNode #For type checking.
|
|||||||
class MaterialGroup:
|
class MaterialGroup:
|
||||||
__slots__ = ("name", "is_read_only", "root_material_node", "derived_material_node_list")
|
__slots__ = ("name", "is_read_only", "root_material_node", "derived_material_node_list")
|
||||||
|
|
||||||
def __init__(self, name: str, root_material_node: MaterialNode):
|
def __init__(self, name: str, root_material_node: MaterialNode) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.is_read_only = False
|
self.is_read_only = False
|
||||||
self.root_material_node = root_material_node
|
self.root_material_node = root_material_node # type: MaterialNode
|
||||||
self.derived_material_node_list = [] #type: List[MaterialNode]
|
self.derived_material_node_list = [] #type: List[MaterialNode]
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
from collections import defaultdict, OrderedDict
|
from collections import defaultdict, OrderedDict
|
||||||
import copy
|
import copy
|
||||||
import uuid
|
import uuid
|
||||||
|
from typing import Dict
|
||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot
|
from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot
|
||||||
@ -263,7 +264,7 @@ class MaterialManager(QObject):
|
|||||||
# Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup.
|
# Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup.
|
||||||
#
|
#
|
||||||
def getAvailableMaterials(self, machine_definition: "DefinitionContainer", extruder_variant_name: Optional[str],
|
def getAvailableMaterials(self, machine_definition: "DefinitionContainer", extruder_variant_name: Optional[str],
|
||||||
diameter: float) -> dict:
|
diameter: float) -> Dict[str, MaterialNode]:
|
||||||
# round the diameter to get the approximate diameter
|
# round the diameter to get the approximate diameter
|
||||||
rounded_diameter = str(round(diameter))
|
rounded_diameter = str(round(diameter))
|
||||||
if rounded_diameter not in self._diameter_machine_variant_material_map:
|
if rounded_diameter not in self._diameter_machine_variant_material_map:
|
||||||
@ -288,7 +289,7 @@ class MaterialManager(QObject):
|
|||||||
# 3. generic material (for fdmprinter)
|
# 3. generic material (for fdmprinter)
|
||||||
machine_exclude_materials = machine_definition.getMetaDataEntry("exclude_materials", [])
|
machine_exclude_materials = machine_definition.getMetaDataEntry("exclude_materials", [])
|
||||||
|
|
||||||
material_id_metadata_dict = dict()
|
material_id_metadata_dict = dict() # type: Dict[str, MaterialNode]
|
||||||
for node in nodes_to_check:
|
for node in nodes_to_check:
|
||||||
if node is not None:
|
if node is not None:
|
||||||
# Only exclude the materials that are explicitly specified in the "exclude_materials" field.
|
# Only exclude the materials that are explicitly specified in the "exclude_materials" field.
|
||||||
@ -434,7 +435,7 @@ class MaterialManager(QObject):
|
|||||||
|
|
||||||
nodes_to_remove = [material_group.root_material_node] + material_group.derived_material_node_list
|
nodes_to_remove = [material_group.root_material_node] + material_group.derived_material_node_list
|
||||||
for node in nodes_to_remove:
|
for node in nodes_to_remove:
|
||||||
self._container_registry.removeContainer(node.metadata["id"])
|
self._container_registry.removeContainer(node.getMetaDataEntry("id", ""))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Methods for GUI
|
# Methods for GUI
|
||||||
@ -445,22 +446,27 @@ class MaterialManager(QObject):
|
|||||||
#
|
#
|
||||||
@pyqtSlot("QVariant", str)
|
@pyqtSlot("QVariant", str)
|
||||||
def setMaterialName(self, material_node: "MaterialNode", name: str):
|
def setMaterialName(self, material_node: "MaterialNode", name: str):
|
||||||
root_material_id = material_node.metadata["base_file"]
|
root_material_id = material_node.getMetaDataEntry("base_file")
|
||||||
|
if root_material_id is None:
|
||||||
|
return
|
||||||
if self._container_registry.isReadOnly(root_material_id):
|
if self._container_registry.isReadOnly(root_material_id):
|
||||||
Logger.log("w", "Cannot set name of read-only container %s.", root_material_id)
|
Logger.log("w", "Cannot set name of read-only container %s.", root_material_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
material_group = self.getMaterialGroup(root_material_id)
|
material_group = self.getMaterialGroup(root_material_id)
|
||||||
if material_group:
|
if material_group:
|
||||||
material_group.root_material_node.getContainer().setName(name)
|
container = material_group.root_material_node.getContainer()
|
||||||
|
if container:
|
||||||
|
container.setName(name)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Removes the given material.
|
# Removes the given material.
|
||||||
#
|
#
|
||||||
@pyqtSlot("QVariant")
|
@pyqtSlot("QVariant")
|
||||||
def removeMaterial(self, material_node: "MaterialNode"):
|
def removeMaterial(self, material_node: "MaterialNode"):
|
||||||
root_material_id = material_node.metadata["base_file"]
|
root_material_id = material_node.getMetaDataEntry("base_file")
|
||||||
self.removeMaterialByRootId(root_material_id)
|
if root_material_id is not None:
|
||||||
|
self.removeMaterialByRootId(root_material_id)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Creates a duplicate of a material, which has the same GUID and base_file metadata.
|
# Creates a duplicate of a material, which has the same GUID and base_file metadata.
|
||||||
@ -539,6 +545,10 @@ class MaterialManager(QObject):
|
|||||||
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
|
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
|
||||||
material_group = self.getMaterialGroup(root_material_id)
|
material_group = self.getMaterialGroup(root_material_id)
|
||||||
|
|
||||||
|
if not material_group: # This should never happen
|
||||||
|
Logger.log("w", "Cannot get the material group of %s.", root_material_id)
|
||||||
|
return ""
|
||||||
|
|
||||||
# Create a new ID & container to hold the data.
|
# Create a new ID & container to hold the data.
|
||||||
new_id = self._container_registry.uniqueName("custom_material")
|
new_id = self._container_registry.uniqueName("custom_material")
|
||||||
new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
|
new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from typing import Optional, Dict
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from .ContainerNode import ContainerNode
|
from .ContainerNode import ContainerNode
|
||||||
|
|
||||||
@ -15,7 +14,6 @@ from .ContainerNode import ContainerNode
|
|||||||
class MaterialNode(ContainerNode):
|
class MaterialNode(ContainerNode):
|
||||||
__slots__ = ("material_map", "children_map")
|
__slots__ = ("material_map", "children_map")
|
||||||
|
|
||||||
def __init__(self, metadata: Optional[dict] = None):
|
def __init__(self, metadata: Optional[dict] = None) -> None:
|
||||||
super().__init__(metadata = metadata)
|
super().__init__(metadata = metadata)
|
||||||
self.material_map = {} # material_root_id -> material_node
|
self.material_map = {} # type: Dict[str, MaterialNode] # material_root_id -> material_node
|
||||||
self.children_map = {} # mapping for the child nodes
|
|
||||||
|
@ -83,7 +83,7 @@ class QualityProfilesDropDownMenuModel(ListModel):
|
|||||||
|
|
||||||
self.setItems(item_list)
|
self.setItems(item_list)
|
||||||
|
|
||||||
def _fetchLayerHeight(self, quality_group: "QualityGroup"):
|
def _fetchLayerHeight(self, quality_group: "QualityGroup") -> float:
|
||||||
global_stack = self._machine_manager.activeMachine
|
global_stack = self._machine_manager.activeMachine
|
||||||
if not self._layer_height_unit:
|
if not self._layer_height_unit:
|
||||||
unit = global_stack.definition.getProperty("layer_height", "unit")
|
unit = global_stack.definition.getProperty("layer_height", "unit")
|
||||||
@ -94,10 +94,12 @@ class QualityProfilesDropDownMenuModel(ListModel):
|
|||||||
default_layer_height = global_stack.definition.getProperty("layer_height", "value")
|
default_layer_height = global_stack.definition.getProperty("layer_height", "value")
|
||||||
|
|
||||||
# Get layer_height from the quality profile for the GlobalStack
|
# Get layer_height from the quality profile for the GlobalStack
|
||||||
|
if quality_group.node_for_global is None:
|
||||||
|
return float(default_layer_height)
|
||||||
container = quality_group.node_for_global.getContainer()
|
container = quality_group.node_for_global.getContainer()
|
||||||
|
|
||||||
layer_height = default_layer_height
|
layer_height = default_layer_height
|
||||||
if container.hasProperty("layer_height", "value"):
|
if container and container.hasProperty("layer_height", "value"):
|
||||||
layer_height = container.getProperty("layer_height", "value")
|
layer_height = container.getProperty("layer_height", "value")
|
||||||
else:
|
else:
|
||||||
# Look for layer_height in the GlobalStack from material -> definition
|
# Look for layer_height in the GlobalStack from material -> definition
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
||||||
|
|
||||||
from .QualityGroup import QualityGroup
|
from .QualityGroup import QualityGroup
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from cura.Machines.QualityNode import QualityNode
|
||||||
|
|
||||||
|
|
||||||
class QualityChangesGroup(QualityGroup):
|
class QualityChangesGroup(QualityGroup):
|
||||||
def __init__(self, name: str, quality_type: str, parent = None):
|
def __init__(self, name: str, quality_type: str, parent = None) -> None:
|
||||||
super().__init__(name, quality_type, parent)
|
super().__init__(name, quality_type, parent)
|
||||||
self._container_registry = Application.getInstance().getContainerRegistry()
|
self._container_registry = Application.getInstance().getContainerRegistry()
|
||||||
|
|
||||||
def addNode(self, node: "QualityNode"):
|
def addNode(self, node: "QualityNode"):
|
||||||
extruder_position = node.metadata.get("position")
|
extruder_position = node.getMetaDataEntry("position")
|
||||||
|
|
||||||
if extruder_position is None and self.node_for_global is not None or extruder_position in self.nodes_for_extruders: #We would be overwriting another node.
|
if extruder_position is None and self.node_for_global is not None or extruder_position in self.nodes_for_extruders: #We would be overwriting another node.
|
||||||
ConfigurationErrorMessage.getInstance().addFaultyContainers(node.metadata["id"])
|
ConfigurationErrorMessage.getInstance().addFaultyContainers(node.getMetaDataEntry("id"))
|
||||||
return
|
return
|
||||||
|
|
||||||
if extruder_position is None: #Then we're a global quality changes profile.
|
if extruder_position is None: #Then we're a global quality changes profile.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from typing import Dict, Optional, List, Set
|
from typing import Dict, Optional, List, Set
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSlot
|
||||||
|
from cura.Machines.ContainerNode import ContainerNode
|
||||||
|
|
||||||
#
|
#
|
||||||
# A QualityGroup represents a group of containers that must be applied to each ContainerStack when it's used.
|
# A QualityGroup represents a group of containers that must be applied to each ContainerStack when it's used.
|
||||||
@ -24,8 +24,8 @@ class QualityGroup(QObject):
|
|||||||
def __init__(self, name: str, quality_type: str, parent = None) -> None:
|
def __init__(self, name: str, quality_type: str, parent = None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.node_for_global = None # type: Optional["QualityGroup"]
|
self.node_for_global = None # type: Optional[ContainerNode]
|
||||||
self.nodes_for_extruders = {} # type: Dict[int, "QualityGroup"]
|
self.nodes_for_extruders = {} # type: Dict[int, ContainerNode]
|
||||||
self.quality_type = quality_type
|
self.quality_type = quality_type
|
||||||
self.is_available = False
|
self.is_available = False
|
||||||
|
|
||||||
@ -38,10 +38,12 @@ class QualityGroup(QObject):
|
|||||||
for node in [self.node_for_global] + list(self.nodes_for_extruders.values()):
|
for node in [self.node_for_global] + list(self.nodes_for_extruders.values()):
|
||||||
if node is None:
|
if node is None:
|
||||||
continue
|
continue
|
||||||
result.update(node.getContainer().getAllKeys())
|
container = node.getContainer()
|
||||||
|
if container:
|
||||||
|
result.update(container.getAllKeys())
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def getAllNodes(self) -> List["QualityGroup"]:
|
def getAllNodes(self) -> List[ContainerNode]:
|
||||||
result = []
|
result = []
|
||||||
if self.node_for_global is not None:
|
if self.node_for_global is not None:
|
||||||
result.append(self.node_for_global)
|
result.append(self.node_for_global)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional, cast
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ class QualityManager(QObject):
|
|||||||
|
|
||||||
if definition_id not in self._machine_variant_material_quality_type_to_quality_dict:
|
if definition_id not in self._machine_variant_material_quality_type_to_quality_dict:
|
||||||
self._machine_variant_material_quality_type_to_quality_dict[definition_id] = QualityNode()
|
self._machine_variant_material_quality_type_to_quality_dict[definition_id] = QualityNode()
|
||||||
machine_node = self._machine_variant_material_quality_type_to_quality_dict[definition_id]
|
machine_node = cast(QualityNode, self._machine_variant_material_quality_type_to_quality_dict[definition_id])
|
||||||
|
|
||||||
if is_global_quality:
|
if is_global_quality:
|
||||||
# For global qualities, save data in the machine node
|
# For global qualities, save data in the machine node
|
||||||
@ -102,7 +102,7 @@ class QualityManager(QObject):
|
|||||||
# too.
|
# too.
|
||||||
if variant_name not in machine_node.children_map:
|
if variant_name not in machine_node.children_map:
|
||||||
machine_node.children_map[variant_name] = QualityNode()
|
machine_node.children_map[variant_name] = QualityNode()
|
||||||
variant_node = machine_node.children_map[variant_name]
|
variant_node = cast(QualityNode, machine_node.children_map[variant_name])
|
||||||
|
|
||||||
if root_material_id is None:
|
if root_material_id is None:
|
||||||
# If only variant_name is specified but material is not, add the quality/quality_changes metadata
|
# If only variant_name is specified but material is not, add the quality/quality_changes metadata
|
||||||
@ -114,7 +114,7 @@ class QualityManager(QObject):
|
|||||||
# material node.
|
# material node.
|
||||||
if root_material_id not in variant_node.children_map:
|
if root_material_id not in variant_node.children_map:
|
||||||
variant_node.children_map[root_material_id] = QualityNode()
|
variant_node.children_map[root_material_id] = QualityNode()
|
||||||
material_node = variant_node.children_map[root_material_id]
|
material_node = cast(QualityNode, variant_node.children_map[root_material_id])
|
||||||
|
|
||||||
material_node.addQualityMetadata(quality_type, metadata)
|
material_node.addQualityMetadata(quality_type, metadata)
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class QualityManager(QObject):
|
|||||||
if root_material_id is not None:
|
if root_material_id is not None:
|
||||||
if root_material_id not in machine_node.children_map:
|
if root_material_id not in machine_node.children_map:
|
||||||
machine_node.children_map[root_material_id] = QualityNode()
|
machine_node.children_map[root_material_id] = QualityNode()
|
||||||
material_node = machine_node.children_map[root_material_id]
|
material_node = cast(QualityNode, machine_node.children_map[root_material_id])
|
||||||
|
|
||||||
material_node.addQualityMetadata(quality_type, metadata)
|
material_node.addQualityMetadata(quality_type, metadata)
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ class QualityManager(QObject):
|
|||||||
def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"):
|
def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"):
|
||||||
Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name)
|
Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name)
|
||||||
for node in quality_changes_group.getAllNodes():
|
for node in quality_changes_group.getAllNodes():
|
||||||
self._container_registry.removeContainer(node.metadata["id"])
|
self._container_registry.removeContainer(node.getMetaDataEntry("id"))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Rename a set of quality changes containers. Returns the new name.
|
# Rename a set of quality changes containers. Returns the new name.
|
||||||
@ -365,7 +365,9 @@ class QualityManager(QObject):
|
|||||||
|
|
||||||
new_name = self._container_registry.uniqueName(new_name)
|
new_name = self._container_registry.uniqueName(new_name)
|
||||||
for node in quality_changes_group.getAllNodes():
|
for node in quality_changes_group.getAllNodes():
|
||||||
node.getContainer().setName(new_name)
|
container = node.getContainer()
|
||||||
|
if container:
|
||||||
|
container.setName(new_name)
|
||||||
|
|
||||||
quality_changes_group.name = new_name
|
quality_changes_group.name = new_name
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional, Dict, cast
|
||||||
|
|
||||||
from .ContainerNode import ContainerNode
|
from .ContainerNode import ContainerNode
|
||||||
from .QualityChangesGroup import QualityChangesGroup
|
from .QualityChangesGroup import QualityChangesGroup
|
||||||
@ -12,9 +12,9 @@ from .QualityChangesGroup import QualityChangesGroup
|
|||||||
#
|
#
|
||||||
class QualityNode(ContainerNode):
|
class QualityNode(ContainerNode):
|
||||||
|
|
||||||
def __init__(self, metadata: Optional[dict] = None):
|
def __init__(self, metadata: Optional[dict] = None) -> None:
|
||||||
super().__init__(metadata = metadata)
|
super().__init__(metadata = metadata)
|
||||||
self.quality_type_map = {} # quality_type -> QualityNode for InstanceContainer
|
self.quality_type_map = {} # type: Dict[str, QualityNode] # quality_type -> QualityNode for InstanceContainer
|
||||||
|
|
||||||
def addQualityMetadata(self, quality_type: str, metadata: dict):
|
def addQualityMetadata(self, quality_type: str, metadata: dict):
|
||||||
if quality_type not in self.quality_type_map:
|
if quality_type not in self.quality_type_map:
|
||||||
@ -32,4 +32,4 @@ class QualityNode(ContainerNode):
|
|||||||
if name not in quality_type_node.children_map:
|
if name not in quality_type_node.children_map:
|
||||||
quality_type_node.children_map[name] = QualityChangesGroup(name, quality_type)
|
quality_type_node.children_map[name] = QualityChangesGroup(name, quality_type)
|
||||||
quality_changes_group = quality_type_node.children_map[name]
|
quality_changes_group = quality_type_node.children_map[name]
|
||||||
quality_changes_group.addNode(QualityNode(metadata))
|
cast(QualityChangesGroup, quality_changes_group).addNode(QualityNode(metadata))
|
||||||
|
@ -64,10 +64,11 @@ class MultiplyObjectsJob(Job):
|
|||||||
arranger.resetLastPriority()
|
arranger.resetLastPriority()
|
||||||
for i in range(self._count):
|
for i in range(self._count):
|
||||||
# We do place the nodes one by one, as we want to yield in between.
|
# We do place the nodes one by one, as we want to yield in between.
|
||||||
|
new_node = copy.deepcopy(node)
|
||||||
|
solution_found = False
|
||||||
if not node_too_big:
|
if not node_too_big:
|
||||||
new_node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr)
|
solution_found = arranger.findNodePlacement(new_node, offset_shape_arr, hull_shape_arr)
|
||||||
else:
|
|
||||||
new_node = copy.deepcopy(node)
|
|
||||||
if node_too_big or not solution_found:
|
if node_too_big or not solution_found:
|
||||||
found_solution_for_all = False
|
found_solution_for_all = False
|
||||||
new_location = new_node.getPosition()
|
new_location = new_node.getPosition()
|
||||||
|
@ -16,7 +16,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
|||||||
#
|
#
|
||||||
# Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels
|
# Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels
|
||||||
class PickingPass(RenderPass):
|
class PickingPass(RenderPass):
|
||||||
def __init__(self, width: int, height: int):
|
def __init__(self, width: int, height: int) -> None:
|
||||||
super().__init__("picking", width, height)
|
super().__init__("picking", width, height)
|
||||||
|
|
||||||
self._renderer = Application.getInstance().getRenderer()
|
self._renderer = Application.getInstance().getRenderer()
|
||||||
|
@ -8,6 +8,7 @@ from UM.Scene.SceneNode import SceneNode
|
|||||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||||
from UM.Math.Vector import Vector
|
from UM.Math.Vector import Vector
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
|
from UM.Scene.SceneNodeSettings import SceneNodeSettings
|
||||||
|
|
||||||
from cura.Scene.ConvexHullDecorator import ConvexHullDecorator
|
from cura.Scene.ConvexHullDecorator import ConvexHullDecorator
|
||||||
|
|
||||||
@ -80,6 +81,10 @@ class PlatformPhysics:
|
|||||||
|
|
||||||
# only push away objects if this node is a printing mesh
|
# only push away objects if this node is a printing mesh
|
||||||
if not node.callDecoration("isNonPrintingMesh") and Application.getInstance().getPreferences().getValue("physics/automatic_push_free"):
|
if not node.callDecoration("isNonPrintingMesh") and Application.getInstance().getPreferences().getValue("physics/automatic_push_free"):
|
||||||
|
# Do not move locked nodes
|
||||||
|
if node.getSetting(SceneNodeSettings.LockPosition):
|
||||||
|
continue
|
||||||
|
|
||||||
# Check for collisions between convex hulls
|
# Check for collisions between convex hulls
|
||||||
for other_node in BreadthFirstIterator(root):
|
for other_node in BreadthFirstIterator(root):
|
||||||
# Ignore root, ourselves and anything that is not a normal SceneNode.
|
# Ignore root, ourselves and anything that is not a normal SceneNode.
|
||||||
|
@ -33,7 +33,7 @@ def prettier_color(color_list):
|
|||||||
#
|
#
|
||||||
# This is useful to get a preview image of a scene taken from a different location as the active camera.
|
# This is useful to get a preview image of a scene taken from a different location as the active camera.
|
||||||
class PreviewPass(RenderPass):
|
class PreviewPass(RenderPass):
|
||||||
def __init__(self, width: int, height: int):
|
def __init__(self, width: int, height: int) -> None:
|
||||||
super().__init__("preview", width, height, 0)
|
super().__init__("preview", width, height, 0)
|
||||||
|
|
||||||
self._camera = None # type: Optional[Camera]
|
self._camera = None # type: Optional[Camera]
|
||||||
@ -53,20 +53,23 @@ class PreviewPass(RenderPass):
|
|||||||
def render(self) -> None:
|
def render(self) -> None:
|
||||||
if not self._shader:
|
if not self._shader:
|
||||||
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
|
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
|
||||||
self._shader.setUniformValue("u_overhangAngle", 1.0)
|
if self._shader:
|
||||||
self._shader.setUniformValue("u_ambientColor", [0.1, 0.1, 0.1, 1.0])
|
self._shader.setUniformValue("u_overhangAngle", 1.0)
|
||||||
self._shader.setUniformValue("u_specularColor", [0.6, 0.6, 0.6, 1.0])
|
self._shader.setUniformValue("u_ambientColor", [0.1, 0.1, 0.1, 1.0])
|
||||||
self._shader.setUniformValue("u_shininess", 20.0)
|
self._shader.setUniformValue("u_specularColor", [0.6, 0.6, 0.6, 1.0])
|
||||||
|
self._shader.setUniformValue("u_shininess", 20.0)
|
||||||
|
|
||||||
if not self._non_printing_shader:
|
if not self._non_printing_shader:
|
||||||
self._non_printing_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
|
if self._non_printing_shader:
|
||||||
self._non_printing_shader.setUniformValue("u_diffuseColor", [0.5, 0.5, 0.5, 0.5])
|
self._non_printing_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
|
||||||
self._non_printing_shader.setUniformValue("u_opacity", 0.6)
|
self._non_printing_shader.setUniformValue("u_diffuseColor", [0.5, 0.5, 0.5, 0.5])
|
||||||
|
self._non_printing_shader.setUniformValue("u_opacity", 0.6)
|
||||||
|
|
||||||
if not self._support_mesh_shader:
|
if not self._support_mesh_shader:
|
||||||
self._support_mesh_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
|
self._support_mesh_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
|
||||||
self._support_mesh_shader.setUniformValue("u_vertical_stripes", True)
|
if self._support_mesh_shader:
|
||||||
self._support_mesh_shader.setUniformValue("u_width", 5.0)
|
self._support_mesh_shader.setUniformValue("u_vertical_stripes", True)
|
||||||
|
self._support_mesh_shader.setUniformValue("u_width", 5.0)
|
||||||
|
|
||||||
self._gl.glClearColor(0.0, 0.0, 0.0, 0.0)
|
self._gl.glClearColor(0.0, 0.0, 0.0, 0.0)
|
||||||
self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)
|
self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt5.QtCore import QTimer
|
||||||
|
|
||||||
MYPY = False
|
if TYPE_CHECKING:
|
||||||
if MYPY:
|
|
||||||
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
||||||
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
|
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
|
||||||
|
from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel
|
||||||
|
|
||||||
|
|
||||||
class GenericOutputController(PrinterOutputController):
|
class GenericOutputController(PrinterOutputController):
|
||||||
|
@ -32,12 +32,12 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
def __init__(self, device_id, address: str, properties: Dict[bytes, bytes], parent: QObject = None) -> None:
|
def __init__(self, device_id, address: str, properties: Dict[bytes, bytes], parent: QObject = None) -> None:
|
||||||
super().__init__(device_id = device_id, parent = parent)
|
super().__init__(device_id = device_id, parent = parent)
|
||||||
self._manager = None # type: QNetworkAccessManager
|
self._manager = None # type: QNetworkAccessManager
|
||||||
self._last_manager_create_time = None # type: float
|
self._last_manager_create_time = None # type: Optional[float]
|
||||||
self._recreate_network_manager_time = 30
|
self._recreate_network_manager_time = 30
|
||||||
self._timeout_time = 10 # After how many seconds of no response should a timeout occur?
|
self._timeout_time = 10 # After how many seconds of no response should a timeout occur?
|
||||||
|
|
||||||
self._last_response_time = None # type: float
|
self._last_response_time = None # type: Optional[float]
|
||||||
self._last_request_time = None # type: float
|
self._last_request_time = None # type: Optional[float]
|
||||||
|
|
||||||
self._api_prefix = ""
|
self._api_prefix = ""
|
||||||
self._address = address
|
self._address = address
|
||||||
@ -146,12 +146,14 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
if time_since_last_response > self._recreate_network_manager_time:
|
if time_since_last_response > self._recreate_network_manager_time:
|
||||||
if self._last_manager_create_time is None:
|
if self._last_manager_create_time is None:
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
if time() - self._last_manager_create_time > self._recreate_network_manager_time:
|
elif time() - self._last_manager_create_time > self._recreate_network_manager_time:
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
|
assert(self._manager is not None)
|
||||||
elif self._connection_state == ConnectionState.closed:
|
elif self._connection_state == ConnectionState.closed:
|
||||||
# Go out of timeout.
|
# Go out of timeout.
|
||||||
self.setConnectionState(self._connection_state_before_timeout)
|
if self._connection_state_before_timeout is not None: # sanity check, but it should never be None here
|
||||||
self._connection_state_before_timeout = None
|
self.setConnectionState(self._connection_state_before_timeout)
|
||||||
|
self._connection_state_before_timeout = None
|
||||||
|
|
||||||
def _createEmptyRequest(self, target: str, content_type: Optional[str] = "application/json") -> QNetworkRequest:
|
def _createEmptyRequest(self, target: str, content_type: Optional[str] = "application/json") -> QNetworkRequest:
|
||||||
url = QUrl("http://" + self._address + self._api_prefix + target)
|
url = QUrl("http://" + self._address + self._api_prefix + target)
|
||||||
@ -190,6 +192,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
def put(self, target: str, data: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None:
|
def put(self, target: str, data: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None:
|
||||||
if self._manager is None:
|
if self._manager is None:
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
|
assert(self._manager is not None)
|
||||||
request = self._createEmptyRequest(target)
|
request = self._createEmptyRequest(target)
|
||||||
self._last_request_time = time()
|
self._last_request_time = time()
|
||||||
reply = self._manager.put(request, data.encode())
|
reply = self._manager.put(request, data.encode())
|
||||||
@ -198,6 +201,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
def get(self, target: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None:
|
def get(self, target: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None:
|
||||||
if self._manager is None:
|
if self._manager is None:
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
|
assert(self._manager is not None)
|
||||||
request = self._createEmptyRequest(target)
|
request = self._createEmptyRequest(target)
|
||||||
self._last_request_time = time()
|
self._last_request_time = time()
|
||||||
reply = self._manager.get(request)
|
reply = self._manager.get(request)
|
||||||
@ -206,6 +210,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
def post(self, target: str, data: str, onFinished: Optional[Callable[[QNetworkReply], None]], on_progress: Callable = None) -> None:
|
def post(self, target: str, data: str, onFinished: Optional[Callable[[QNetworkReply], None]], on_progress: Callable = None) -> None:
|
||||||
if self._manager is None:
|
if self._manager is None:
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
|
assert(self._manager is not None)
|
||||||
request = self._createEmptyRequest(target)
|
request = self._createEmptyRequest(target)
|
||||||
self._last_request_time = time()
|
self._last_request_time = time()
|
||||||
reply = self._manager.post(request, data)
|
reply = self._manager.post(request, data)
|
||||||
@ -216,6 +221,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
def postFormWithParts(self, target:str, parts: List[QHttpPart], on_finished: Optional[Callable[[QNetworkReply], None]], on_progress: Callable = None) -> None:
|
def postFormWithParts(self, target:str, parts: List[QHttpPart], on_finished: Optional[Callable[[QNetworkReply], None]], on_progress: Callable = None) -> None:
|
||||||
if self._manager is None:
|
if self._manager is None:
|
||||||
self._createNetworkManager()
|
self._createNetworkManager()
|
||||||
|
assert(self._manager is not None)
|
||||||
request = self._createEmptyRequest(target, content_type=None)
|
request = self._createEmptyRequest(target, content_type=None)
|
||||||
multi_post_part = QHttpMultiPart(QHttpMultiPart.FormDataType)
|
multi_post_part = QHttpMultiPart(QHttpMultiPart.FormDataType)
|
||||||
for part in parts:
|
for part in parts:
|
||||||
|
@ -224,5 +224,5 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
|||||||
## Get the name of device firmware
|
## Get the name of device firmware
|
||||||
#
|
#
|
||||||
# This name can be used to define device type
|
# This name can be used to define device type
|
||||||
def getFirmwareName(self) -> str:
|
def getFirmwareName(self) -> Optional[str]:
|
||||||
return self._firmware_name
|
return self._firmware_name
|
@ -16,7 +16,7 @@ from UM.Signal import Signal
|
|||||||
class CuraSceneController(QObject):
|
class CuraSceneController(QObject):
|
||||||
activeBuildPlateChanged = Signal()
|
activeBuildPlateChanged = Signal()
|
||||||
|
|
||||||
def __init__(self, objects_model: ObjectsModel, multi_build_plate_model: MultiBuildPlateModel):
|
def __init__(self, objects_model: ObjectsModel, multi_build_plate_model: MultiBuildPlateModel) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self._objects_model = objects_model
|
self._objects_model = objects_model
|
||||||
|
@ -39,6 +39,9 @@ class CuraSceneNode(SceneNode):
|
|||||||
# TODO The best way to do it is by adding the setActiveExtruder decorator to every node when is loaded
|
# TODO The best way to do it is by adding the setActiveExtruder decorator to every node when is loaded
|
||||||
def getPrintingExtruder(self) -> Optional[ExtruderStack]:
|
def getPrintingExtruder(self) -> Optional[ExtruderStack]:
|
||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
if global_container_stack is None:
|
||||||
|
return None
|
||||||
|
|
||||||
per_mesh_stack = self.callDecoration("getStack")
|
per_mesh_stack = self.callDecoration("getStack")
|
||||||
extruders = list(global_container_stack.extruders.values())
|
extruders = list(global_container_stack.extruders.values())
|
||||||
|
|
||||||
@ -85,10 +88,10 @@ class CuraSceneNode(SceneNode):
|
|||||||
## Return if the provided bbox collides with the bbox of this scene node
|
## Return if the provided bbox collides with the bbox of this scene node
|
||||||
def collidesWithBbox(self, check_bbox: AxisAlignedBox) -> bool:
|
def collidesWithBbox(self, check_bbox: AxisAlignedBox) -> bool:
|
||||||
bbox = self.getBoundingBox()
|
bbox = self.getBoundingBox()
|
||||||
|
if bbox is not None:
|
||||||
# Mark the node as outside the build volume if the bounding box test fails.
|
# Mark the node as outside the build volume if the bounding box test fails.
|
||||||
if check_bbox.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
if check_bbox.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ class ContainerManager(QObject):
|
|||||||
self._container_registry = self._application.getContainerRegistry()
|
self._container_registry = self._application.getContainerRegistry()
|
||||||
self._machine_manager = self._application.getMachineManager()
|
self._machine_manager = self._application.getMachineManager()
|
||||||
self._material_manager = self._application.getMaterialManager()
|
self._material_manager = self._application.getMaterialManager()
|
||||||
|
self._quality_manager = self._application.getQualityManager()
|
||||||
self._container_name_filters = {}
|
self._container_name_filters = {}
|
||||||
|
|
||||||
@pyqtSlot(str, str, result=str)
|
@pyqtSlot(str, str, result=str)
|
||||||
@ -312,11 +313,19 @@ class ContainerManager(QObject):
|
|||||||
|
|
||||||
self._machine_manager.blurSettings.emit()
|
self._machine_manager.blurSettings.emit()
|
||||||
|
|
||||||
global_stack = self._machine_manager.activeMachine
|
current_quality_changes_name = global_stack.qualityChanges.getName()
|
||||||
|
current_quality_type = global_stack.quality.getMetaDataEntry("quality_type")
|
||||||
extruder_stacks = list(global_stack.extruders.values())
|
extruder_stacks = list(global_stack.extruders.values())
|
||||||
for stack in [global_stack] + extruder_stacks:
|
for stack in [global_stack] + extruder_stacks:
|
||||||
# Find the quality_changes container for this stack and merge the contents of the top container into it.
|
# Find the quality_changes container for this stack and merge the contents of the top container into it.
|
||||||
quality_changes = stack.qualityChanges
|
quality_changes = stack.qualityChanges
|
||||||
|
|
||||||
|
if quality_changes.getId() == "empty_quality_changes":
|
||||||
|
quality_changes = self._quality_manager._createQualityChanges(current_quality_type, current_quality_changes_name,
|
||||||
|
global_stack, stack)
|
||||||
|
self._container_registry.addContainer(quality_changes)
|
||||||
|
stack.qualityChanges = quality_changes
|
||||||
|
|
||||||
if not quality_changes or self._container_registry.isReadOnly(quality_changes.getId()):
|
if not quality_changes or self._container_registry.isReadOnly(quality_changes.getId()):
|
||||||
Logger.log("e", "Could not update quality of a nonexistant or read only quality profile in stack %s", stack.getId())
|
Logger.log("e", "Could not update quality of a nonexistant or read only quality profile in stack %s", stack.getId())
|
||||||
continue
|
continue
|
||||||
@ -459,7 +468,7 @@ class ContainerManager(QObject):
|
|||||||
container_list = [n.getContainer() for n in quality_changes_group.getAllNodes() if n.getContainer() is not None]
|
container_list = [n.getContainer() for n in quality_changes_group.getAllNodes() if n.getContainer() is not None]
|
||||||
self._container_registry.exportQualityProfile(container_list, path, file_type)
|
self._container_registry.exportQualityProfile(container_list, path, file_type)
|
||||||
|
|
||||||
__instance = None
|
__instance = None # type: ContainerManager
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getInstance(cls, *args, **kwargs) -> "ContainerManager":
|
def getInstance(cls, *args, **kwargs) -> "ContainerManager":
|
||||||
|
@ -356,6 +356,8 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
return catalog.i18nc("@info:status", "Profile is missing a quality type.")
|
return catalog.i18nc("@info:status", "Profile is missing a quality type.")
|
||||||
|
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
if global_stack is None:
|
||||||
|
return None
|
||||||
definition_id = getMachineDefinitionIDForQualitySearch(global_stack.definition)
|
definition_id = getMachineDefinitionIDForQualitySearch(global_stack.definition)
|
||||||
profile.setDefinition(definition_id)
|
profile.setDefinition(definition_id)
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from UM.Settings.SettingInstance import SettingInstance
|
|||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext
|
from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext
|
||||||
|
|
||||||
from typing import Optional, List, TYPE_CHECKING, Union
|
from typing import Optional, List, TYPE_CHECKING, Union, Dict
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from cura.Settings.ExtruderStack import ExtruderStack
|
from cura.Settings.ExtruderStack import ExtruderStack
|
||||||
@ -43,7 +43,6 @@ class ExtruderManager(QObject):
|
|||||||
self._selected_object_extruders = []
|
self._selected_object_extruders = []
|
||||||
self._addCurrentMachineExtruders()
|
self._addCurrentMachineExtruders()
|
||||||
|
|
||||||
#Application.getInstance().globalContainerStackChanged.connect(self._globalContainerStackChanged)
|
|
||||||
Selection.selectionChanged.connect(self.resetSelectedObjectExtruders)
|
Selection.selectionChanged.connect(self.resetSelectedObjectExtruders)
|
||||||
|
|
||||||
## Signal to notify other components when the list of extruders for a machine definition changes.
|
## Signal to notify other components when the list of extruders for a machine definition changes.
|
||||||
@ -60,42 +59,47 @@ class ExtruderManager(QObject):
|
|||||||
# \return The unique ID of the currently active extruder stack.
|
# \return The unique ID of the currently active extruder stack.
|
||||||
@pyqtProperty(str, notify = activeExtruderChanged)
|
@pyqtProperty(str, notify = activeExtruderChanged)
|
||||||
def activeExtruderStackId(self) -> Optional[str]:
|
def activeExtruderStackId(self) -> Optional[str]:
|
||||||
if not Application.getInstance().getGlobalContainerStack():
|
if not self._application.getGlobalContainerStack():
|
||||||
return None # No active machine, so no active extruder.
|
return None # No active machine, so no active extruder.
|
||||||
try:
|
try:
|
||||||
return self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId()
|
return self._extruder_trains[self._application.getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId()
|
||||||
except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
|
except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
## Return extruder count according to extruder trains.
|
## Return extruder count according to extruder trains.
|
||||||
@pyqtProperty(int, notify = extrudersChanged)
|
@pyqtProperty(int, notify = extrudersChanged)
|
||||||
def extruderCount(self):
|
def extruderCount(self):
|
||||||
if not Application.getInstance().getGlobalContainerStack():
|
if not self._application.getGlobalContainerStack():
|
||||||
return 0 # No active machine, so no extruders.
|
return 0 # No active machine, so no extruders.
|
||||||
try:
|
try:
|
||||||
return len(self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()])
|
return len(self._extruder_trains[self._application.getGlobalContainerStack().getId()])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
## Gets a dict with the extruder stack ids with the extruder number as the key.
|
## Gets a dict with the extruder stack ids with the extruder number as the key.
|
||||||
@pyqtProperty("QVariantMap", notify = extrudersChanged)
|
@pyqtProperty("QVariantMap", notify = extrudersChanged)
|
||||||
def extruderIds(self):
|
def extruderIds(self) -> Dict[str, str]:
|
||||||
extruder_stack_ids = {}
|
extruder_stack_ids = {}
|
||||||
|
|
||||||
global_stack_id = Application.getInstance().getGlobalContainerStack().getId()
|
global_container_stack = self._application.getGlobalContainerStack()
|
||||||
|
if global_container_stack:
|
||||||
|
global_stack_id = global_container_stack.getId()
|
||||||
|
|
||||||
if global_stack_id in self._extruder_trains:
|
if global_stack_id in self._extruder_trains:
|
||||||
for position in self._extruder_trains[global_stack_id]:
|
for position in self._extruder_trains[global_stack_id]:
|
||||||
extruder_stack_ids[position] = self._extruder_trains[global_stack_id][position].getId()
|
extruder_stack_ids[position] = self._extruder_trains[global_stack_id][position].getId()
|
||||||
|
|
||||||
return extruder_stack_ids
|
return extruder_stack_ids
|
||||||
|
|
||||||
@pyqtSlot(str, result = str)
|
@pyqtSlot(str, result = str)
|
||||||
def getQualityChangesIdByExtruderStackId(self, extruder_stack_id: str) -> str:
|
def getQualityChangesIdByExtruderStackId(self, extruder_stack_id: str) -> str:
|
||||||
for position in self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()]:
|
global_container_stack = self._application.getGlobalContainerStack()
|
||||||
extruder = self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][position]
|
if global_container_stack is not None:
|
||||||
if extruder.getId() == extruder_stack_id:
|
for position in self._extruder_trains[global_container_stack.getId()]:
|
||||||
return extruder.qualityChanges.getId()
|
extruder = self._extruder_trains[global_container_stack.getId()][position]
|
||||||
|
if extruder.getId() == extruder_stack_id:
|
||||||
|
return extruder.qualityChanges.getId()
|
||||||
|
return ""
|
||||||
|
|
||||||
## Changes the active extruder by index.
|
## Changes the active extruder by index.
|
||||||
#
|
#
|
||||||
@ -141,7 +145,7 @@ class ExtruderManager(QObject):
|
|||||||
selected_nodes.append(node)
|
selected_nodes.append(node)
|
||||||
|
|
||||||
# Then, figure out which nodes are used by those selected nodes.
|
# Then, figure out which nodes are used by those selected nodes.
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = self._application.getGlobalContainerStack()
|
||||||
current_extruder_trains = self._extruder_trains.get(global_stack.getId())
|
current_extruder_trains = self._extruder_trains.get(global_stack.getId())
|
||||||
for node in selected_nodes:
|
for node in selected_nodes:
|
||||||
extruder = node.callDecoration("getActiveExtruder")
|
extruder = node.callDecoration("getActiveExtruder")
|
||||||
@ -164,7 +168,7 @@ class ExtruderManager(QObject):
|
|||||||
|
|
||||||
@pyqtSlot(result = QObject)
|
@pyqtSlot(result = QObject)
|
||||||
def getActiveExtruderStack(self) -> Optional["ExtruderStack"]:
|
def getActiveExtruderStack(self) -> Optional["ExtruderStack"]:
|
||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
global_container_stack = self._application.getGlobalContainerStack()
|
||||||
|
|
||||||
if global_container_stack:
|
if global_container_stack:
|
||||||
if global_container_stack.getId() in self._extruder_trains:
|
if global_container_stack.getId() in self._extruder_trains:
|
||||||
@ -175,7 +179,7 @@ class ExtruderManager(QObject):
|
|||||||
|
|
||||||
## Get an extruder stack by index
|
## Get an extruder stack by index
|
||||||
def getExtruderStack(self, index) -> Optional["ExtruderStack"]:
|
def getExtruderStack(self, index) -> Optional["ExtruderStack"]:
|
||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
global_container_stack = self._application.getGlobalContainerStack()
|
||||||
if global_container_stack:
|
if global_container_stack:
|
||||||
if global_container_stack.getId() in self._extruder_trains:
|
if global_container_stack.getId() in self._extruder_trains:
|
||||||
if str(index) in self._extruder_trains[global_container_stack.getId()]:
|
if str(index) in self._extruder_trains[global_container_stack.getId()]:
|
||||||
@ -186,7 +190,9 @@ class ExtruderManager(QObject):
|
|||||||
def getExtruderStacks(self) -> List["ExtruderStack"]:
|
def getExtruderStacks(self) -> List["ExtruderStack"]:
|
||||||
result = []
|
result = []
|
||||||
for i in range(self.extruderCount):
|
for i in range(self.extruderCount):
|
||||||
result.append(self.getExtruderStack(i))
|
stack = self.getExtruderStack(i)
|
||||||
|
if stack:
|
||||||
|
result.append(stack)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def registerExtruder(self, extruder_train, machine_id):
|
def registerExtruder(self, extruder_train, machine_id):
|
||||||
@ -252,7 +258,7 @@ class ExtruderManager(QObject):
|
|||||||
support_bottom_enabled = False
|
support_bottom_enabled = False
|
||||||
support_roof_enabled = False
|
support_roof_enabled = False
|
||||||
|
|
||||||
scene_root = Application.getInstance().getController().getScene().getRoot()
|
scene_root = self._application.getController().getScene().getRoot()
|
||||||
|
|
||||||
# If no extruders are registered in the extruder manager yet, return an empty array
|
# If no extruders are registered in the extruder manager yet, return an empty array
|
||||||
if len(self.extruderIds) == 0:
|
if len(self.extruderIds) == 0:
|
||||||
@ -301,10 +307,10 @@ class ExtruderManager(QObject):
|
|||||||
|
|
||||||
# The platform adhesion extruder. Not used if using none.
|
# The platform adhesion extruder. Not used if using none.
|
||||||
if global_stack.getProperty("adhesion_type", "value") != "none":
|
if global_stack.getProperty("adhesion_type", "value") != "none":
|
||||||
extruder_nr = str(global_stack.getProperty("adhesion_extruder_nr", "value"))
|
extruder_str_nr = str(global_stack.getProperty("adhesion_extruder_nr", "value"))
|
||||||
if extruder_nr == "-1":
|
if extruder_str_nr == "-1":
|
||||||
extruder_nr = Application.getInstance().getMachineManager().defaultExtruderPosition
|
extruder_str_nr = self._application.getMachineManager().defaultExtruderPosition
|
||||||
used_extruder_stack_ids.add(self.extruderIds[extruder_nr])
|
used_extruder_stack_ids.add(self.extruderIds[extruder_str_nr])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids]
|
return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids]
|
||||||
@ -335,7 +341,7 @@ class ExtruderManager(QObject):
|
|||||||
# The first element is the global container stack, followed by any extruder stacks.
|
# The first element is the global container stack, followed by any extruder stacks.
|
||||||
# \return \type{List[ContainerStack]}
|
# \return \type{List[ContainerStack]}
|
||||||
def getActiveGlobalAndExtruderStacks(self) -> Optional[List[Union["ExtruderStack", "GlobalStack"]]]:
|
def getActiveGlobalAndExtruderStacks(self) -> Optional[List[Union["ExtruderStack", "GlobalStack"]]]:
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = self._application.getGlobalContainerStack()
|
||||||
if not global_stack:
|
if not global_stack:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -347,7 +353,7 @@ class ExtruderManager(QObject):
|
|||||||
#
|
#
|
||||||
# \return \type{List[ContainerStack]} a list of
|
# \return \type{List[ContainerStack]} a list of
|
||||||
def getActiveExtruderStacks(self) -> List["ExtruderStack"]:
|
def getActiveExtruderStacks(self) -> List["ExtruderStack"]:
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = self._application.getGlobalContainerStack()
|
||||||
if not global_stack:
|
if not global_stack:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@ -461,10 +467,6 @@ class ExtruderManager(QObject):
|
|||||||
if global_stack.definitionChanges.hasProperty(key, "value"):
|
if global_stack.definitionChanges.hasProperty(key, "value"):
|
||||||
global_stack.definitionChanges.removeInstance(key, postpone_emit = True)
|
global_stack.definitionChanges.removeInstance(key, postpone_emit = True)
|
||||||
|
|
||||||
# Update material diameter for extruders
|
|
||||||
for position in extruder_positions_to_update:
|
|
||||||
self.updateMaterialForDiameter(position, global_stack = global_stack)
|
|
||||||
|
|
||||||
## Get all extruder values for a certain setting.
|
## Get all extruder values for a certain setting.
|
||||||
#
|
#
|
||||||
# This is exposed to SettingFunction so it can be used in value functions.
|
# This is exposed to SettingFunction so it can be used in value functions.
|
||||||
@ -556,96 +558,6 @@ class ExtruderManager(QObject):
|
|||||||
def getInstanceExtruderValues(self, key):
|
def getInstanceExtruderValues(self, key):
|
||||||
return ExtruderManager.getExtruderValues(key)
|
return ExtruderManager.getExtruderValues(key)
|
||||||
|
|
||||||
## Updates the material container to a material that matches the material diameter set for the printer
|
|
||||||
def updateMaterialForDiameter(self, extruder_position: int, global_stack = None):
|
|
||||||
if not global_stack:
|
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
|
||||||
if not global_stack:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not global_stack.getMetaDataEntry("has_materials", False):
|
|
||||||
return
|
|
||||||
|
|
||||||
extruder_stack = global_stack.extruders[str(extruder_position)]
|
|
||||||
|
|
||||||
material_diameter = extruder_stack.material.getProperty("material_diameter", "value")
|
|
||||||
if not material_diameter:
|
|
||||||
# in case of "empty" material
|
|
||||||
material_diameter = 0
|
|
||||||
|
|
||||||
material_approximate_diameter = str(round(material_diameter))
|
|
||||||
material_diameter = extruder_stack.definitionChanges.getProperty("material_diameter", "value")
|
|
||||||
setting_provider = extruder_stack
|
|
||||||
if not material_diameter:
|
|
||||||
if extruder_stack.definition.hasProperty("material_diameter", "value"):
|
|
||||||
material_diameter = extruder_stack.definition.getProperty("material_diameter", "value")
|
|
||||||
else:
|
|
||||||
material_diameter = global_stack.definition.getProperty("material_diameter", "value")
|
|
||||||
setting_provider = global_stack
|
|
||||||
|
|
||||||
if isinstance(material_diameter, SettingFunction):
|
|
||||||
material_diameter = material_diameter(setting_provider)
|
|
||||||
|
|
||||||
machine_approximate_diameter = str(round(material_diameter))
|
|
||||||
|
|
||||||
if material_approximate_diameter != machine_approximate_diameter:
|
|
||||||
Logger.log("i", "The the currently active material(s) do not match the diameter set for the printer. Finding alternatives.")
|
|
||||||
|
|
||||||
if global_stack.getMetaDataEntry("has_machine_materials", False):
|
|
||||||
materials_definition = global_stack.definition.getId()
|
|
||||||
has_material_variants = global_stack.getMetaDataEntry("has_variants", False)
|
|
||||||
else:
|
|
||||||
materials_definition = "fdmprinter"
|
|
||||||
has_material_variants = False
|
|
||||||
|
|
||||||
old_material = extruder_stack.material
|
|
||||||
search_criteria = {
|
|
||||||
"type": "material",
|
|
||||||
"approximate_diameter": machine_approximate_diameter,
|
|
||||||
"material": old_material.getMetaDataEntry("material", "value"),
|
|
||||||
"brand": old_material.getMetaDataEntry("brand", "value"),
|
|
||||||
"supplier": old_material.getMetaDataEntry("supplier", "value"),
|
|
||||||
"color_name": old_material.getMetaDataEntry("color_name", "value"),
|
|
||||||
"definition": materials_definition
|
|
||||||
}
|
|
||||||
if has_material_variants:
|
|
||||||
search_criteria["variant"] = extruder_stack.variant.getId()
|
|
||||||
|
|
||||||
container_registry = Application.getInstance().getContainerRegistry()
|
|
||||||
empty_material = container_registry.findInstanceContainers(id = "empty_material")[0]
|
|
||||||
|
|
||||||
if old_material == empty_material:
|
|
||||||
search_criteria.pop("material", None)
|
|
||||||
search_criteria.pop("supplier", None)
|
|
||||||
search_criteria.pop("brand", None)
|
|
||||||
search_criteria.pop("definition", None)
|
|
||||||
search_criteria["id"] = extruder_stack.getMetaDataEntry("preferred_material")
|
|
||||||
|
|
||||||
materials = container_registry.findInstanceContainers(**search_criteria)
|
|
||||||
if not materials:
|
|
||||||
# Same material with new diameter is not found, search for generic version of the same material type
|
|
||||||
search_criteria.pop("supplier", None)
|
|
||||||
search_criteria.pop("brand", None)
|
|
||||||
search_criteria["color_name"] = "Generic"
|
|
||||||
materials = container_registry.findInstanceContainers(**search_criteria)
|
|
||||||
if not materials:
|
|
||||||
# Generic material with new diameter is not found, search for preferred material
|
|
||||||
search_criteria.pop("color_name", None)
|
|
||||||
search_criteria.pop("material", None)
|
|
||||||
search_criteria["id"] = extruder_stack.getMetaDataEntry("preferred_material")
|
|
||||||
materials = container_registry.findInstanceContainers(**search_criteria)
|
|
||||||
if not materials:
|
|
||||||
# Preferred material with new diameter is not found, search for any material
|
|
||||||
search_criteria.pop("id", None)
|
|
||||||
materials = container_registry.findInstanceContainers(**search_criteria)
|
|
||||||
if not materials:
|
|
||||||
# Just use empty material as a final fallback
|
|
||||||
materials = [empty_material]
|
|
||||||
|
|
||||||
Logger.log("i", "Selecting new material: %s", materials[0].getId())
|
|
||||||
|
|
||||||
extruder_stack.material = materials[0]
|
|
||||||
|
|
||||||
## Get the value for a setting from a specific extruder.
|
## Get the value for a setting from a specific extruder.
|
||||||
#
|
#
|
||||||
# This is exposed to SettingFunction to use in value functions.
|
# This is exposed to SettingFunction to use in value functions.
|
||||||
@ -736,7 +648,7 @@ class ExtruderManager(QObject):
|
|||||||
|
|
||||||
return resolved_value
|
return resolved_value
|
||||||
|
|
||||||
__instance = None
|
__instance = None # type: ExtruderManager
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getInstance(cls, *args, **kwargs) -> "ExtruderManager":
|
def getInstance(cls, *args, **kwargs) -> "ExtruderManager":
|
||||||
|
@ -53,8 +53,8 @@ class MachineManager(QObject):
|
|||||||
self._global_container_stack = None # type: Optional[GlobalStack]
|
self._global_container_stack = None # type: Optional[GlobalStack]
|
||||||
|
|
||||||
self._current_root_material_id = {} # type: Dict[str, str]
|
self._current_root_material_id = {} # type: Dict[str, str]
|
||||||
self._current_quality_group = None
|
self._current_quality_group = None # type: Optional[QualityGroup]
|
||||||
self._current_quality_changes_group = None
|
self._current_quality_changes_group = None # type: Optional[QualityChangesGroup]
|
||||||
|
|
||||||
self._default_extruder_position = "0" # to be updated when extruders are switched on and off
|
self._default_extruder_position = "0" # to be updated when extruders are switched on and off
|
||||||
|
|
||||||
@ -307,6 +307,11 @@ class MachineManager(QObject):
|
|||||||
for position, extruder in global_stack.extruders.items():
|
for position, extruder in global_stack.extruders.items():
|
||||||
material_dict[position] = extruder.material.getMetaDataEntry("base_file")
|
material_dict[position] = extruder.material.getMetaDataEntry("base_file")
|
||||||
self._current_root_material_id = material_dict
|
self._current_root_material_id = material_dict
|
||||||
|
|
||||||
|
# Update materials to make sure that the diameters match with the machine's
|
||||||
|
for position in global_stack.extruders:
|
||||||
|
self.updateMaterialWithVariant(position)
|
||||||
|
|
||||||
global_quality = global_stack.quality
|
global_quality = global_stack.quality
|
||||||
quality_type = global_quality.getMetaDataEntry("quality_type")
|
quality_type = global_quality.getMetaDataEntry("quality_type")
|
||||||
global_quality_changes = global_stack.qualityChanges
|
global_quality_changes = global_stack.qualityChanges
|
||||||
@ -626,6 +631,8 @@ class MachineManager(QObject):
|
|||||||
## Copy the value of the setting of the current extruder to all other extruders as well as the global container.
|
## Copy the value of the setting of the current extruder to all other extruders as well as the global container.
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def copyValueToExtruders(self, key: str) -> None:
|
def copyValueToExtruders(self, key: str) -> None:
|
||||||
|
if self._active_container_stack is None or self._global_container_stack is None:
|
||||||
|
return
|
||||||
new_value = self._active_container_stack.getProperty(key, "value")
|
new_value = self._active_container_stack.getProperty(key, "value")
|
||||||
extruder_stacks = [stack for stack in ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())]
|
extruder_stacks = [stack for stack in ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())]
|
||||||
|
|
||||||
@ -637,6 +644,8 @@ class MachineManager(QObject):
|
|||||||
## Copy the value of all manually changed settings of the current extruder to all other extruders.
|
## Copy the value of all manually changed settings of the current extruder to all other extruders.
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def copyAllValuesToExtruders(self) -> None:
|
def copyAllValuesToExtruders(self) -> None:
|
||||||
|
if self._active_container_stack is None or self._global_container_stack is None:
|
||||||
|
return
|
||||||
extruder_stacks = list(self._global_container_stack.extruders.values())
|
extruder_stacks = list(self._global_container_stack.extruders.values())
|
||||||
for extruder_stack in extruder_stacks:
|
for extruder_stack in extruder_stacks:
|
||||||
if extruder_stack != self._active_container_stack:
|
if extruder_stack != self._active_container_stack:
|
||||||
@ -807,6 +816,8 @@ class MachineManager(QObject):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def getIncompatibleSettingsOnEnabledExtruders(self, container: InstanceContainer) -> List[str]:
|
def getIncompatibleSettingsOnEnabledExtruders(self, container: InstanceContainer) -> List[str]:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return []
|
||||||
extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
|
extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
|
||||||
result = [] # type: List[str]
|
result = [] # type: List[str]
|
||||||
for setting_instance in container.findInstances():
|
for setting_instance in container.findInstances():
|
||||||
@ -831,6 +842,8 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed
|
## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed
|
||||||
def correctExtruderSettings(self) -> None:
|
def correctExtruderSettings(self) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
for setting_key in self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.userChanges):
|
for setting_key in self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.userChanges):
|
||||||
self._global_container_stack.userChanges.removeInstance(setting_key)
|
self._global_container_stack.userChanges.removeInstance(setting_key)
|
||||||
add_user_changes = self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.qualityChanges)
|
add_user_changes = self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.qualityChanges)
|
||||||
@ -848,6 +861,8 @@ class MachineManager(QObject):
|
|||||||
## Set the amount of extruders on the active machine (global stack)
|
## Set the amount of extruders on the active machine (global stack)
|
||||||
# \param extruder_count int the number of extruders to set
|
# \param extruder_count int the number of extruders to set
|
||||||
def setActiveMachineExtruderCount(self, extruder_count: int) -> None:
|
def setActiveMachineExtruderCount(self, extruder_count: int) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
extruder_manager = self._application.getExtruderManager()
|
extruder_manager = self._application.getExtruderManager()
|
||||||
|
|
||||||
definition_changes_container = self._global_container_stack.definitionChanges
|
definition_changes_container = self._global_container_stack.definitionChanges
|
||||||
@ -909,6 +924,8 @@ class MachineManager(QObject):
|
|||||||
return extruder
|
return extruder
|
||||||
|
|
||||||
def updateDefaultExtruder(self) -> None:
|
def updateDefaultExtruder(self) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
extruder_items = sorted(self._global_container_stack.extruders.items())
|
extruder_items = sorted(self._global_container_stack.extruders.items())
|
||||||
old_position = self._default_extruder_position
|
old_position = self._default_extruder_position
|
||||||
new_default_position = "0"
|
new_default_position = "0"
|
||||||
@ -921,6 +938,8 @@ class MachineManager(QObject):
|
|||||||
self.extruderChanged.emit()
|
self.extruderChanged.emit()
|
||||||
|
|
||||||
def updateNumberExtrudersEnabled(self) -> None:
|
def updateNumberExtrudersEnabled(self) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
definition_changes_container = self._global_container_stack.definitionChanges
|
definition_changes_container = self._global_container_stack.definitionChanges
|
||||||
machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
|
machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
|
||||||
extruder_count = 0
|
extruder_count = 0
|
||||||
@ -933,6 +952,8 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
@pyqtProperty(int, notify = numberExtrudersEnabledChanged)
|
@pyqtProperty(int, notify = numberExtrudersEnabledChanged)
|
||||||
def numberExtrudersEnabled(self) -> int:
|
def numberExtrudersEnabled(self) -> int:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return 1
|
||||||
return self._global_container_stack.definitionChanges.getProperty("extruders_enabled_count", "value")
|
return self._global_container_stack.definitionChanges.getProperty("extruders_enabled_count", "value")
|
||||||
|
|
||||||
@pyqtProperty(str, notify = extruderChanged)
|
@pyqtProperty(str, notify = extruderChanged)
|
||||||
@ -942,6 +963,8 @@ class MachineManager(QObject):
|
|||||||
## This will fire the propertiesChanged for all settings so they will be updated in the front-end
|
## This will fire the propertiesChanged for all settings so they will be updated in the front-end
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def forceUpdateAllSettings(self) -> None:
|
def forceUpdateAllSettings(self) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
property_names = ["value", "resolve", "validationState"]
|
property_names = ["value", "resolve", "validationState"]
|
||||||
for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
||||||
@ -951,8 +974,9 @@ class MachineManager(QObject):
|
|||||||
@pyqtSlot(int, bool)
|
@pyqtSlot(int, bool)
|
||||||
def setExtruderEnabled(self, position: int, enabled: bool) -> None:
|
def setExtruderEnabled(self, position: int, enabled: bool) -> None:
|
||||||
extruder = self.getExtruder(position)
|
extruder = self.getExtruder(position)
|
||||||
if not extruder:
|
if not extruder or self._global_container_stack is None:
|
||||||
Logger.log("w", "Could not find extruder on position %s", position)
|
Logger.log("w", "Could not find extruder on position %s", position)
|
||||||
|
return
|
||||||
|
|
||||||
extruder.setEnabled(enabled)
|
extruder.setEnabled(enabled)
|
||||||
self.updateDefaultExtruder()
|
self.updateDefaultExtruder()
|
||||||
@ -988,6 +1012,8 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
@pyqtSlot(str, str, str)
|
@pyqtSlot(str, str, str)
|
||||||
def setSettingForAllExtruders(self, setting_name: str, property_name: str, property_value: str) -> None:
|
def setSettingForAllExtruders(self, setting_name: str, property_name: str, property_value: str) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
for key, extruder in self._global_container_stack.extruders.items():
|
for key, extruder in self._global_container_stack.extruders.items():
|
||||||
container = extruder.userChanges
|
container = extruder.userChanges
|
||||||
container.setProperty(setting_name, property_name, property_value)
|
container.setProperty(setting_name, property_name, property_value)
|
||||||
@ -996,6 +1022,8 @@ class MachineManager(QObject):
|
|||||||
# \param setting_name The ID of the setting to reset.
|
# \param setting_name The ID of the setting to reset.
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def resetSettingForAllExtruders(self, setting_name: str) -> None:
|
def resetSettingForAllExtruders(self, setting_name: str) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
for key, extruder in self._global_container_stack.extruders.items():
|
for key, extruder in self._global_container_stack.extruders.items():
|
||||||
container = extruder.userChanges
|
container = extruder.userChanges
|
||||||
container.removeInstance(setting_name)
|
container.removeInstance(setting_name)
|
||||||
@ -1038,6 +1066,8 @@ class MachineManager(QObject):
|
|||||||
# for all stacks in the currently active machine.
|
# for all stacks in the currently active machine.
|
||||||
#
|
#
|
||||||
def _setEmptyQuality(self) -> None:
|
def _setEmptyQuality(self) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
self._current_quality_group = None
|
self._current_quality_group = None
|
||||||
self._current_quality_changes_group = None
|
self._current_quality_changes_group = None
|
||||||
self._global_container_stack.quality = self._empty_quality_container
|
self._global_container_stack.quality = self._empty_quality_container
|
||||||
@ -1050,11 +1080,13 @@ class MachineManager(QObject):
|
|||||||
self.activeQualityChangesGroupChanged.emit()
|
self.activeQualityChangesGroupChanged.emit()
|
||||||
|
|
||||||
def _setQualityGroup(self, quality_group: Optional[QualityGroup], empty_quality_changes: bool = True) -> None:
|
def _setQualityGroup(self, quality_group: Optional[QualityGroup], empty_quality_changes: bool = True) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
if quality_group is None:
|
if quality_group is None:
|
||||||
self._setEmptyQuality()
|
self._setEmptyQuality()
|
||||||
return
|
return
|
||||||
|
|
||||||
if quality_group.node_for_global.getContainer() is None:
|
if quality_group.node_for_global is None or quality_group.node_for_global.getContainer() is None:
|
||||||
return
|
return
|
||||||
for node in quality_group.nodes_for_extruders.values():
|
for node in quality_group.nodes_for_extruders.values():
|
||||||
if node.getContainer() is None:
|
if node.getContainer() is None:
|
||||||
@ -1082,7 +1114,8 @@ class MachineManager(QObject):
|
|||||||
nodes = [quality_changes_group.node_for_global] + list(quality_changes_group.nodes_for_extruders.values())
|
nodes = [quality_changes_group.node_for_global] + list(quality_changes_group.nodes_for_extruders.values())
|
||||||
containers = [n.getContainer() for n in nodes if n is not None]
|
containers = [n.getContainer() for n in nodes if n is not None]
|
||||||
for container in containers:
|
for container in containers:
|
||||||
container.setMetaDataEntry("quality_type", "not_supported")
|
if container:
|
||||||
|
container.setMetaDataEntry("quality_type", "not_supported")
|
||||||
quality_changes_group.quality_type = "not_supported"
|
quality_changes_group.quality_type = "not_supported"
|
||||||
|
|
||||||
def _setQualityChangesGroup(self, quality_changes_group: QualityChangesGroup) -> None:
|
def _setQualityChangesGroup(self, quality_changes_group: QualityChangesGroup) -> None:
|
||||||
@ -1130,20 +1163,24 @@ class MachineManager(QObject):
|
|||||||
self.activeQualityChangesGroupChanged.emit()
|
self.activeQualityChangesGroupChanged.emit()
|
||||||
|
|
||||||
def _setVariantNode(self, position: str, container_node: ContainerNode) -> None:
|
def _setVariantNode(self, position: str, container_node: ContainerNode) -> None:
|
||||||
if container_node.getContainer() is None:
|
if container_node.getContainer() is None or self._global_container_stack is None:
|
||||||
return
|
return
|
||||||
self._global_container_stack.extruders[position].variant = container_node.getContainer()
|
self._global_container_stack.extruders[position].variant = container_node.getContainer()
|
||||||
self.activeVariantChanged.emit()
|
self.activeVariantChanged.emit()
|
||||||
|
|
||||||
def _setGlobalVariant(self, container_node: ContainerNode) -> None:
|
def _setGlobalVariant(self, container_node: ContainerNode) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
self._global_container_stack.variant = container_node.getContainer()
|
self._global_container_stack.variant = container_node.getContainer()
|
||||||
if not self._global_container_stack.variant:
|
if not self._global_container_stack.variant:
|
||||||
self._global_container_stack.variant = self._application.empty_variant_container
|
self._global_container_stack.variant = self._application.empty_variant_container
|
||||||
|
|
||||||
def _setMaterial(self, position: str, container_node: ContainerNode = None) -> None:
|
def _setMaterial(self, position: str, container_node: ContainerNode = None) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
if container_node and container_node.getContainer():
|
if container_node and container_node.getContainer():
|
||||||
self._global_container_stack.extruders[position].material = container_node.getContainer()
|
self._global_container_stack.extruders[position].material = container_node.getContainer()
|
||||||
root_material_id = container_node.metadata["base_file"]
|
root_material_id = container_node.getMetaDataEntry("base_file", None)
|
||||||
else:
|
else:
|
||||||
self._global_container_stack.extruders[position].material = self._empty_material_container
|
self._global_container_stack.extruders[position].material = self._empty_material_container
|
||||||
root_material_id = None
|
root_material_id = None
|
||||||
@ -1154,12 +1191,13 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
def activeMaterialsCompatible(self) -> bool:
|
def activeMaterialsCompatible(self) -> bool:
|
||||||
# check material - variant compatibility
|
# check material - variant compatibility
|
||||||
if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)):
|
if self._global_container_stack is not None:
|
||||||
for position, extruder in self._global_container_stack.extruders.items():
|
if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)):
|
||||||
if extruder.isEnabled and not extruder.material.getMetaDataEntry("compatible"):
|
for position, extruder in self._global_container_stack.extruders.items():
|
||||||
return False
|
if extruder.isEnabled and not extruder.material.getMetaDataEntry("compatible"):
|
||||||
if not extruder.material.getMetaDataEntry("compatible"):
|
return False
|
||||||
return False
|
if not extruder.material.getMetaDataEntry("compatible"):
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
## Update current quality type and machine after setting material
|
## Update current quality type and machine after setting material
|
||||||
@ -1202,7 +1240,7 @@ class MachineManager(QObject):
|
|||||||
current_quality_type, quality_type)
|
current_quality_type, quality_type)
|
||||||
self._setQualityGroup(candidate_quality_groups[quality_type], empty_quality_changes = True)
|
self._setQualityGroup(candidate_quality_groups[quality_type], empty_quality_changes = True)
|
||||||
|
|
||||||
def _updateMaterialWithVariant(self, position: Optional[str]) -> None:
|
def updateMaterialWithVariant(self, position: Optional[str]) -> None:
|
||||||
if self._global_container_stack is None:
|
if self._global_container_stack is None:
|
||||||
return
|
return
|
||||||
if position is None:
|
if position is None:
|
||||||
@ -1210,8 +1248,8 @@ class MachineManager(QObject):
|
|||||||
else:
|
else:
|
||||||
position_list = [position]
|
position_list = [position]
|
||||||
|
|
||||||
for position in position_list:
|
for position_item in position_list:
|
||||||
extruder = self._global_container_stack.extruders[position]
|
extruder = self._global_container_stack.extruders[position_item]
|
||||||
|
|
||||||
current_material_base_name = extruder.material.getMetaDataEntry("base_file")
|
current_material_base_name = extruder.material.getMetaDataEntry("base_file")
|
||||||
current_variant_name = None
|
current_variant_name = None
|
||||||
@ -1229,25 +1267,25 @@ class MachineManager(QObject):
|
|||||||
material_diameter)
|
material_diameter)
|
||||||
|
|
||||||
if not candidate_materials:
|
if not candidate_materials:
|
||||||
self._setMaterial(position, container_node = None)
|
self._setMaterial(position_item, container_node = None)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if current_material_base_name in candidate_materials:
|
if current_material_base_name in candidate_materials:
|
||||||
new_material = candidate_materials[current_material_base_name]
|
new_material = candidate_materials[current_material_base_name]
|
||||||
self._setMaterial(position, new_material)
|
self._setMaterial(position_item, new_material)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# The current material is not available, find the preferred one
|
# The current material is not available, find the preferred one
|
||||||
material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, current_variant_name)
|
material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, current_variant_name)
|
||||||
if material_node is not None:
|
if material_node is not None:
|
||||||
self._setMaterial(position, material_node)
|
self._setMaterial(position_item, material_node)
|
||||||
|
|
||||||
## Given a printer definition name, select the right machine instance. In case it doesn't exist, create a new
|
## Given a printer definition name, select the right machine instance. In case it doesn't exist, create a new
|
||||||
# instance with the same network key.
|
# instance with the same network key.
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def switchPrinterType(self, machine_name: str) -> None:
|
def switchPrinterType(self, machine_name: str) -> None:
|
||||||
# Don't switch if the user tries to change to the same type of printer
|
# Don't switch if the user tries to change to the same type of printer
|
||||||
if self.activeMachineDefinitionName == machine_name:
|
if self._global_container_stack is None or self.self.activeMachineDefinitionName == machine_name:
|
||||||
return
|
return
|
||||||
# Get the definition id corresponding to this machine name
|
# Get the definition id corresponding to this machine name
|
||||||
machine_definition_id = CuraContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId()
|
machine_definition_id = CuraContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId()
|
||||||
@ -1272,6 +1310,8 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
@pyqtSlot(QObject)
|
@pyqtSlot(QObject)
|
||||||
def applyRemoteConfiguration(self, configuration: ConfigurationModel) -> None:
|
def applyRemoteConfiguration(self, configuration: ConfigurationModel) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
self.blurSettings.emit()
|
self.blurSettings.emit()
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
self.switchPrinterType(configuration.printerType)
|
self.switchPrinterType(configuration.printerType)
|
||||||
@ -1288,7 +1328,7 @@ class MachineManager(QObject):
|
|||||||
self._setMaterial(position, material_container_node)
|
self._setMaterial(position, material_container_node)
|
||||||
else:
|
else:
|
||||||
self._global_container_stack.extruders[position].material = self._empty_material_container
|
self._global_container_stack.extruders[position].material = self._empty_material_container
|
||||||
self._updateMaterialWithVariant(position)
|
self.updateMaterialWithVariant(position)
|
||||||
|
|
||||||
if configuration.buildplateConfiguration is not None:
|
if configuration.buildplateConfiguration is not None:
|
||||||
global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration)
|
global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration)
|
||||||
@ -1334,11 +1374,13 @@ class MachineManager(QObject):
|
|||||||
self.blurSettings.emit()
|
self.blurSettings.emit()
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
self._setGlobalVariant(container_node)
|
self._setGlobalVariant(container_node)
|
||||||
self._updateMaterialWithVariant(None) # Update all materials
|
self.updateMaterialWithVariant(None) # Update all materials
|
||||||
self._updateQualityWithMaterial()
|
self._updateQualityWithMaterial()
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def setMaterialById(self, position: str, root_material_id: str) -> None:
|
def setMaterialById(self, position: str, root_material_id: str) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
machine_definition_id = self._global_container_stack.definition.id
|
machine_definition_id = self._global_container_stack.definition.id
|
||||||
position = str(position)
|
position = str(position)
|
||||||
extruder_stack = self._global_container_stack.extruders[position]
|
extruder_stack = self._global_container_stack.extruders[position]
|
||||||
@ -1361,6 +1403,8 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def setVariantByName(self, position: str, variant_name: str) -> None:
|
def setVariantByName(self, position: str, variant_name: str) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
machine_definition_id = self._global_container_stack.definition.id
|
machine_definition_id = self._global_container_stack.definition.id
|
||||||
variant_node = self._variant_manager.getVariantNode(machine_definition_id, variant_name)
|
variant_node = self._variant_manager.getVariantNode(machine_definition_id, variant_name)
|
||||||
self.setVariant(position, variant_node)
|
self.setVariant(position, variant_node)
|
||||||
@ -1371,7 +1415,7 @@ class MachineManager(QObject):
|
|||||||
self.blurSettings.emit()
|
self.blurSettings.emit()
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
self._setVariantNode(position, container_node)
|
self._setVariantNode(position, container_node)
|
||||||
self._updateMaterialWithVariant(position)
|
self.updateMaterialWithVariant(position)
|
||||||
self._updateQualityWithMaterial()
|
self._updateQualityWithMaterial()
|
||||||
|
|
||||||
# See if we need to show the Discard or Keep changes screen
|
# See if we need to show the Discard or Keep changes screen
|
||||||
@ -1398,7 +1442,7 @@ class MachineManager(QObject):
|
|||||||
self._application.discardOrKeepProfileChanges()
|
self._application.discardOrKeepProfileChanges()
|
||||||
|
|
||||||
@pyqtProperty(QObject, fset = setQualityGroup, notify = activeQualityGroupChanged)
|
@pyqtProperty(QObject, fset = setQualityGroup, notify = activeQualityGroupChanged)
|
||||||
def activeQualityGroup(self) -> QualityGroup:
|
def activeQualityGroup(self) -> Optional[QualityGroup]:
|
||||||
return self._current_quality_group
|
return self._current_quality_group
|
||||||
|
|
||||||
@pyqtSlot(QObject)
|
@pyqtSlot(QObject)
|
||||||
@ -1413,13 +1457,15 @@ class MachineManager(QObject):
|
|||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def resetToUseDefaultQuality(self) -> None:
|
def resetToUseDefaultQuality(self) -> None:
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
self._setQualityGroup(self._current_quality_group)
|
self._setQualityGroup(self._current_quality_group)
|
||||||
for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
||||||
stack.userChanges.clear()
|
stack.userChanges.clear()
|
||||||
|
|
||||||
@pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged)
|
@pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged)
|
||||||
def activeQualityChangesGroup(self) -> QualityChangesGroup:
|
def activeQualityChangesGroup(self) -> Optional[QualityChangesGroup]:
|
||||||
return self._current_quality_changes_group
|
return self._current_quality_changes_group
|
||||||
|
|
||||||
@pyqtProperty(str, notify = activeQualityGroupChanged)
|
@pyqtProperty(str, notify = activeQualityGroupChanged)
|
||||||
@ -1435,5 +1481,5 @@ class MachineManager(QObject):
|
|||||||
if self._global_container_stack is None:
|
if self._global_container_stack is None:
|
||||||
return
|
return
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
self._updateMaterialWithVariant(None)
|
self.updateMaterialWithVariant(None)
|
||||||
self._updateQualityWithMaterial()
|
self._updateQualityWithMaterial()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal
|
from PyQt5.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal
|
||||||
from UM.FlameProfiler import pyqtSlot
|
from UM.FlameProfiler import pyqtSlot
|
||||||
@ -13,6 +14,7 @@ from UM.Logger import Logger
|
|||||||
# speed settings. If all the children of print_speed have a single value override, changing the speed won't
|
# speed settings. If all the children of print_speed have a single value override, changing the speed won't
|
||||||
# actually do anything, as only the 'leaf' settings are used by the engine.
|
# actually do anything, as only the 'leaf' settings are used by the engine.
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
|
from UM.Settings.Interfaces import ContainerInterface
|
||||||
from UM.Settings.SettingFunction import SettingFunction
|
from UM.Settings.SettingFunction import SettingFunction
|
||||||
from UM.Settings.SettingInstance import InstanceState
|
from UM.Settings.SettingInstance import InstanceState
|
||||||
|
|
||||||
@ -157,7 +159,7 @@ class SettingInheritanceManager(QObject):
|
|||||||
stack = self._active_container_stack
|
stack = self._active_container_stack
|
||||||
if not stack: #No active container stack yet!
|
if not stack: #No active container stack yet!
|
||||||
return False
|
return False
|
||||||
containers = []
|
containers = [] # type: List[ContainerInterface]
|
||||||
|
|
||||||
## Check if the setting has a user state. If not, it is never overwritten.
|
## Check if the setting has a user state. If not, it is never overwritten.
|
||||||
has_user_state = stack.getProperty(key, "state") == InstanceState.User
|
has_user_state = stack.getProperty(key, "state") == InstanceState.User
|
||||||
|
@ -63,7 +63,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
|||||||
instance_container = copy.deepcopy(self._stack.getContainer(0), memo)
|
instance_container = copy.deepcopy(self._stack.getContainer(0), memo)
|
||||||
|
|
||||||
# A unique name must be added, or replaceContainer will not replace it
|
# A unique name must be added, or replaceContainer will not replace it
|
||||||
instance_container.setMetaDataEntry("id", self._generateUniqueName)
|
instance_container.setMetaDataEntry("id", self._generateUniqueName())
|
||||||
|
|
||||||
## Set the copied instance as the first (and only) instance container of the stack.
|
## Set the copied instance as the first (and only) instance container of the stack.
|
||||||
deep_copy._stack.replaceContainer(0, instance_container)
|
deep_copy._stack.replaceContainer(0, instance_container)
|
||||||
|
@ -61,8 +61,11 @@ class SingleInstance:
|
|||||||
|
|
||||||
def startServer(self) -> None:
|
def startServer(self) -> None:
|
||||||
self._single_instance_server = QLocalServer()
|
self._single_instance_server = QLocalServer()
|
||||||
self._single_instance_server.newConnection.connect(self._onClientConnected)
|
if self._single_instance_server:
|
||||||
self._single_instance_server.listen("ultimaker-cura")
|
self._single_instance_server.newConnection.connect(self._onClientConnected)
|
||||||
|
self._single_instance_server.listen("ultimaker-cura")
|
||||||
|
else:
|
||||||
|
Logger.log("e", "Single instance server was not created.")
|
||||||
|
|
||||||
def _onClientConnected(self) -> None:
|
def _onClientConnected(self) -> None:
|
||||||
Logger.log("i", "New connection recevied on our single-instance server")
|
Logger.log("i", "New connection recevied on our single-instance server")
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import zipfile
|
import zipfile
|
||||||
import os
|
import os
|
||||||
from typing import List, Tuple
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
@ -13,6 +13,7 @@ from UM.Workspace.WorkspaceReader import WorkspaceReader
|
|||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.Message import Message
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Signal import postponeSignals, CompressTechnique
|
from UM.Signal import postponeSignals, CompressTechnique
|
||||||
from UM.Settings.ContainerFormatError import ContainerFormatError
|
from UM.Settings.ContainerFormatError import ContainerFormatError
|
||||||
@ -37,7 +38,7 @@ i18n_catalog = i18nCatalog("cura")
|
|||||||
|
|
||||||
|
|
||||||
class ContainerInfo:
|
class ContainerInfo:
|
||||||
def __init__(self, file_name: str, serialized: str, parser: ConfigParser):
|
def __init__(self, file_name: str, serialized: str, parser: ConfigParser) -> None:
|
||||||
self.file_name = file_name
|
self.file_name = file_name
|
||||||
self.serialized = serialized
|
self.serialized = serialized
|
||||||
self.parser = parser
|
self.parser = parser
|
||||||
@ -46,14 +47,14 @@ class ContainerInfo:
|
|||||||
|
|
||||||
|
|
||||||
class QualityChangesInfo:
|
class QualityChangesInfo:
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.name = None
|
self.name = None
|
||||||
self.global_info = None
|
self.global_info = None
|
||||||
self.extruder_info_dict = {}
|
self.extruder_info_dict = {} # type: Dict[str, ContainerInfo]
|
||||||
|
|
||||||
|
|
||||||
class MachineInfo:
|
class MachineInfo:
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.container_id = None
|
self.container_id = None
|
||||||
self.name = None
|
self.name = None
|
||||||
self.definition_id = None
|
self.definition_id = None
|
||||||
@ -65,11 +66,11 @@ class MachineInfo:
|
|||||||
self.definition_changes_info = None
|
self.definition_changes_info = None
|
||||||
self.user_changes_info = None
|
self.user_changes_info = None
|
||||||
|
|
||||||
self.extruder_info_dict = {}
|
self.extruder_info_dict = {} # type: Dict[str, ExtruderInfo]
|
||||||
|
|
||||||
|
|
||||||
class ExtruderInfo:
|
class ExtruderInfo:
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.position = None
|
self.position = None
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
self.variant_info = None
|
self.variant_info = None
|
||||||
@ -81,7 +82,7 @@ class ExtruderInfo:
|
|||||||
|
|
||||||
## Base implementation for reading 3MF workspace files.
|
## Base implementation for reading 3MF workspace files.
|
||||||
class ThreeMFWorkspaceReader(WorkspaceReader):
|
class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
MimeTypeDatabase.addMimeType(
|
MimeTypeDatabase.addMimeType(
|
||||||
@ -111,28 +112,26 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
# - variant
|
# - variant
|
||||||
self._ignored_instance_container_types = {"quality", "variant"}
|
self._ignored_instance_container_types = {"quality", "variant"}
|
||||||
|
|
||||||
self._resolve_strategies = {}
|
self._resolve_strategies = {} # type: Dict[str, str]
|
||||||
|
|
||||||
self._id_mapping = {}
|
self._id_mapping = {} # type: Dict[str, str]
|
||||||
|
|
||||||
# In Cura 2.5 and 2.6, the empty profiles used to have those long names
|
# In Cura 2.5 and 2.6, the empty profiles used to have those long names
|
||||||
self._old_empty_profile_id_dict = {"empty_%s" % k: "empty" for k in ["material", "variant"]}
|
self._old_empty_profile_id_dict = {"empty_%s" % k: "empty" for k in ["material", "variant"]}
|
||||||
|
|
||||||
self._is_same_machine_type = False
|
self._is_same_machine_type = False
|
||||||
self._old_new_materials = {}
|
self._old_new_materials = {} # type: Dict[str, str]
|
||||||
self._materials_to_select = {}
|
|
||||||
self._machine_info = None
|
self._machine_info = None
|
||||||
|
|
||||||
def _clearState(self):
|
def _clearState(self):
|
||||||
self._is_same_machine_type = False
|
self._is_same_machine_type = False
|
||||||
self._id_mapping = {}
|
self._id_mapping = {}
|
||||||
self._old_new_materials = {}
|
self._old_new_materials = {}
|
||||||
self._materials_to_select = {}
|
|
||||||
self._machine_info = None
|
self._machine_info = None
|
||||||
|
|
||||||
## Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
|
## Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
|
||||||
# This has nothing to do with speed, but with getting consistent new naming for instances & objects.
|
# This has nothing to do with speed, but with getting consistent new naming for instances & objects.
|
||||||
def getNewId(self, old_id):
|
def getNewId(self, old_id: str):
|
||||||
if old_id not in self._id_mapping:
|
if old_id not in self._id_mapping:
|
||||||
self._id_mapping[old_id] = self._container_registry.uniqueName(old_id)
|
self._id_mapping[old_id] = self._container_registry.uniqueName(old_id)
|
||||||
return self._id_mapping[old_id]
|
return self._id_mapping[old_id]
|
||||||
@ -470,6 +469,20 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
Logger.log("w", "File %s is not a valid workspace.", file_name)
|
Logger.log("w", "File %s is not a valid workspace.", file_name)
|
||||||
return WorkspaceReader.PreReadResult.failed
|
return WorkspaceReader.PreReadResult.failed
|
||||||
|
|
||||||
|
# Check if the machine definition exists. If not, indicate failure because we do not import definition files.
|
||||||
|
def_results = self._container_registry.findDefinitionContainersMetadata(id = machine_definition_id)
|
||||||
|
if not def_results:
|
||||||
|
message = Message(i18n_catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!",
|
||||||
|
"Project file <filename>{0}</filename> contains an unknown machine type"
|
||||||
|
" <message>{1}</message>. Cannot import the machine."
|
||||||
|
" Models will be imported instead.", file_name, machine_definition_id),
|
||||||
|
title = i18n_catalog.i18nc("@info:title", "Open Project File"))
|
||||||
|
message.show()
|
||||||
|
|
||||||
|
Logger.log("i", "Could unknown machine definition %s in project file %s, cannot import it.",
|
||||||
|
self._machine_info.definition_id, file_name)
|
||||||
|
return WorkspaceReader.PreReadResult.failed
|
||||||
|
|
||||||
# In case we use preRead() to check if a file is a valid project file, we don't want to show a dialog.
|
# In case we use preRead() to check if a file is a valid project file, we don't want to show a dialog.
|
||||||
if not show_dialog:
|
if not show_dialog:
|
||||||
return WorkspaceReader.PreReadResult.accepted
|
return WorkspaceReader.PreReadResult.accepted
|
||||||
@ -656,7 +669,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
else:
|
else:
|
||||||
material_container = materials[0]
|
material_container = materials[0]
|
||||||
old_material_root_id = material_container.getMetaDataEntry("base_file")
|
old_material_root_id = material_container.getMetaDataEntry("base_file")
|
||||||
if not self._container_registry.isReadOnly(old_material_root_id): # Only create new materials if they are not read only.
|
if old_material_root_id is not None and not self._container_registry.isReadOnly(old_material_root_id): # Only create new materials if they are not read only.
|
||||||
to_deserialize_material = True
|
to_deserialize_material = True
|
||||||
|
|
||||||
if self._resolve_strategies["material"] == "override":
|
if self._resolve_strategies["material"] == "override":
|
||||||
|
@ -55,7 +55,7 @@ class ChangeLog(Extension, QObject,):
|
|||||||
|
|
||||||
def loadChangeLogs(self):
|
def loadChangeLogs(self):
|
||||||
self._change_logs = collections.OrderedDict()
|
self._change_logs = collections.OrderedDict()
|
||||||
with open(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r",-1, "utf-8") as f:
|
with open(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r", encoding = "utf-8") as f:
|
||||||
open_version = None
|
open_version = None
|
||||||
open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog
|
open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog
|
||||||
for line in f:
|
for line in f:
|
||||||
|
@ -379,6 +379,14 @@ class CuraEngineBackend(QObject, Backend):
|
|||||||
else:
|
else:
|
||||||
self.backendStateChange.emit(BackendState.NotStarted)
|
self.backendStateChange.emit(BackendState.NotStarted)
|
||||||
|
|
||||||
|
if job.getResult() == StartSliceJob.StartJobResult.ObjectsWithDisabledExtruder:
|
||||||
|
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because there are objects associated with disabled Extruder %s." % job.getMessage()),
|
||||||
|
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||||
|
self._error_message.show()
|
||||||
|
self.backendStateChange.emit(BackendState.Error)
|
||||||
|
self.backendError.emit(job)
|
||||||
|
return
|
||||||
|
|
||||||
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
|
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
|
||||||
if Application.getInstance().platformActivity:
|
if Application.getInstance().platformActivity:
|
||||||
self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."),
|
self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."),
|
||||||
|
@ -32,6 +32,7 @@ class StartJobResult(IntEnum):
|
|||||||
MaterialIncompatible = 5
|
MaterialIncompatible = 5
|
||||||
BuildPlateError = 6
|
BuildPlateError = 6
|
||||||
ObjectSettingError = 7 #When an error occurs in per-object settings.
|
ObjectSettingError = 7 #When an error occurs in per-object settings.
|
||||||
|
ObjectsWithDisabledExtruder = 8
|
||||||
|
|
||||||
|
|
||||||
## Formatter class that handles token expansion in start/end gcod
|
## Formatter class that handles token expansion in start/end gcod
|
||||||
@ -213,16 +214,27 @@ class StartSliceJob(Job):
|
|||||||
|
|
||||||
extruders_enabled = {position: stack.isEnabled for position, stack in Application.getInstance().getGlobalContainerStack().extruders.items()}
|
extruders_enabled = {position: stack.isEnabled for position, stack in Application.getInstance().getGlobalContainerStack().extruders.items()}
|
||||||
filtered_object_groups = []
|
filtered_object_groups = []
|
||||||
|
has_model_with_disabled_extruders = False
|
||||||
|
associated_siabled_extruders = set()
|
||||||
for group in object_groups:
|
for group in object_groups:
|
||||||
stack = Application.getInstance().getGlobalContainerStack()
|
stack = Application.getInstance().getGlobalContainerStack()
|
||||||
skip_group = False
|
skip_group = False
|
||||||
for node in group:
|
for node in group:
|
||||||
if not extruders_enabled[node.callDecoration("getActiveExtruderPosition")]:
|
extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||||
|
if not extruders_enabled[extruder_position]:
|
||||||
skip_group = True
|
skip_group = True
|
||||||
|
has_model_with_disabled_extruders = True
|
||||||
|
associated_siabled_extruders.add(extruder_position)
|
||||||
break
|
break
|
||||||
if not skip_group:
|
if not skip_group:
|
||||||
filtered_object_groups.append(group)
|
filtered_object_groups.append(group)
|
||||||
|
|
||||||
|
if has_model_with_disabled_extruders:
|
||||||
|
self.setResult(StartJobResult.ObjectsWithDisabledExtruder)
|
||||||
|
associated_siabled_extruders = [str(c) for c in sorted([int(p) + 1 for p in associated_siabled_extruders])]
|
||||||
|
self.setMessage(", ".join(associated_siabled_extruders))
|
||||||
|
return
|
||||||
|
|
||||||
# There are cases when there is nothing to slice. This can happen due to one at a time slicing not being
|
# There are cases when there is nothing to slice. This can happen due to one at a time slicing not being
|
||||||
# able to find a possible sequence or because there are no objects on the build plate (or they are outside
|
# able to find a possible sequence or because there are no objects on the build plate (or they are outside
|
||||||
# the build volume)
|
# the build volume)
|
||||||
|
@ -57,7 +57,7 @@ class GCodeProfileReader(ProfileReader):
|
|||||||
# TODO: Consider moving settings to the start?
|
# TODO: Consider moving settings to the start?
|
||||||
serialized = "" # Will be filled with the serialized profile.
|
serialized = "" # Will be filled with the serialized profile.
|
||||||
try:
|
try:
|
||||||
with open(file_name, "r") as f:
|
with open(file_name, "r", encoding = "utf-8") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
if line.startswith(prefix):
|
if line.startswith(prefix):
|
||||||
# Remove the prefix and the newline from the line and add it to the rest.
|
# Remove the prefix and the newline from the line and add it to the rest.
|
||||||
|
@ -100,7 +100,7 @@ class LegacyProfileReader(ProfileReader):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(PluginRegistry.getInstance().getPluginPath("LegacyProfileReader"), "DictionaryOfDoom.json"), "r", -1, "utf-8") as f:
|
with open(os.path.join(PluginRegistry.getInstance().getPluginPath("LegacyProfileReader"), "DictionaryOfDoom.json"), "r", encoding = "utf-8") as f:
|
||||||
dict_of_doom = json.load(f) # Parse the Dictionary of Doom.
|
dict_of_doom = json.load(f) # Parse the Dictionary of Doom.
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
Logger.log("e", "Could not open DictionaryOfDoom.json for reading: %s", str(e))
|
Logger.log("e", "Could not open DictionaryOfDoom.json for reading: %s", str(e))
|
||||||
|
@ -158,4 +158,4 @@ class MachineSettingsAction(MachineAction):
|
|||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def updateMaterialForDiameter(self, extruder_position: int):
|
def updateMaterialForDiameter(self, extruder_position: int):
|
||||||
# Updates the material container to a material that matches the material diameter set for the printer
|
# Updates the material container to a material that matches the material diameter set for the printer
|
||||||
self._application.getExtruderManager().updateMaterialForDiameter(extruder_position)
|
self._application.getMachineManager().updateMaterialWithVariant(str(extruder_position))
|
||||||
|
@ -53,7 +53,7 @@ UM.PointingRectangle {
|
|||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
width: 40 * screenScaleFactor
|
width: maximumValue.toString().length * 12 * screenScaleFactor
|
||||||
text: sliderLabelRoot.value + startFrom // the current handle value, add 1 because layers is an array
|
text: sliderLabelRoot.value + startFrom // the current handle value, add 1 because layers is an array
|
||||||
horizontalAlignment: TextInput.AlignRight
|
horizontalAlignment: TextInput.AlignRight
|
||||||
|
|
||||||
@ -77,11 +77,12 @@ UM.PointingRectangle {
|
|||||||
if (valueLabel.text != "") {
|
if (valueLabel.text != "") {
|
||||||
// -startFrom because we need to convert back to an array structure
|
// -startFrom because we need to convert back to an array structure
|
||||||
sliderLabelRoot.setValue(parseInt(valueLabel.text) - startFrom)
|
sliderLabelRoot.setValue(parseInt(valueLabel.text) - startFrom)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validator: IntValidator {
|
validator: IntValidator {
|
||||||
bottom:startFrom
|
bottom: startFrom
|
||||||
top: sliderLabelRoot.maximumValue + startFrom // +startFrom because maybe we want to start in a different value rather than 0
|
top: sliderLabelRoot.maximumValue + startFrom // +startFrom because maybe we want to start in a different value rather than 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,12 +262,14 @@ class Toolbox(QObject, Extension):
|
|||||||
# list of old plugins
|
# list of old plugins
|
||||||
old_plugin_ids = self._plugin_registry.getInstalledPlugins()
|
old_plugin_ids = self._plugin_registry.getInstalledPlugins()
|
||||||
installed_package_ids = self._package_manager.getAllInstalledPackageIDs()
|
installed_package_ids = self._package_manager.getAllInstalledPackageIDs()
|
||||||
|
scheduled_to_remove_package_ids = self._package_manager.getToRemovePackageIDs()
|
||||||
|
|
||||||
self._old_plugin_ids = []
|
self._old_plugin_ids = []
|
||||||
self._old_plugin_metadata = []
|
self._old_plugin_metadata = []
|
||||||
|
|
||||||
for plugin_id in old_plugin_ids:
|
for plugin_id in old_plugin_ids:
|
||||||
if plugin_id not in installed_package_ids:
|
# Neither the installed packages nor the packages that are scheduled to remove are old plugins
|
||||||
|
if plugin_id not in installed_package_ids and plugin_id not in scheduled_to_remove_package_ids:
|
||||||
Logger.log('i', 'Found a plugin that was installed with the old plugin browser: %s', plugin_id)
|
Logger.log('i', 'Found a plugin that was installed with the old plugin browser: %s', plugin_id)
|
||||||
|
|
||||||
old_metadata = self._plugin_registry.getMetaData(plugin_id)
|
old_metadata = self._plugin_registry.getMetaData(plugin_id)
|
||||||
|
@ -13,7 +13,7 @@ def readHex(filename):
|
|||||||
"""
|
"""
|
||||||
data = []
|
data = []
|
||||||
extra_addr = 0
|
extra_addr = 0
|
||||||
f = io.open(filename, "r")
|
f = io.open(filename, "r", encoding = "utf-8")
|
||||||
for line in f:
|
for line in f:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if len(line) < 1:
|
if len(line) < 1:
|
||||||
|
@ -94,7 +94,7 @@ class VersionUpgrade22to24(VersionUpgrade):
|
|||||||
if variant_path.endswith("_variant.inst.cfg"):
|
if variant_path.endswith("_variant.inst.cfg"):
|
||||||
variant_path = variant_path[:-len("_variant.inst.cfg")] + "_settings.inst.cfg"
|
variant_path = variant_path[:-len("_variant.inst.cfg")] + "_settings.inst.cfg"
|
||||||
|
|
||||||
with open(os.path.join(machine_instances_dir, os.path.basename(variant_path)), "w") as fp:
|
with open(os.path.join(machine_instances_dir, os.path.basename(variant_path)), "w", encoding = "utf-8") as fp:
|
||||||
variant_config.write(fp)
|
variant_config.write(fp)
|
||||||
|
|
||||||
return config_name
|
return config_name
|
||||||
@ -105,9 +105,9 @@ class VersionUpgrade22to24(VersionUpgrade):
|
|||||||
|
|
||||||
result = []
|
result = []
|
||||||
for entry in os.scandir(variants_dir):
|
for entry in os.scandir(variants_dir):
|
||||||
if entry.name.endswith('.inst.cfg') and entry.is_file():
|
if entry.name.endswith(".inst.cfg") and entry.is_file():
|
||||||
config = configparser.ConfigParser(interpolation = None)
|
config = configparser.ConfigParser(interpolation = None)
|
||||||
with open(entry.path, "r") as fhandle:
|
with open(entry.path, "r", encoding = "utf-8") as fhandle:
|
||||||
config.read_file(fhandle)
|
config.read_file(fhandle)
|
||||||
if config.has_section("general") and config.has_option("general", "name"):
|
if config.has_section("general") and config.has_option("general", "name"):
|
||||||
result.append( { "path": entry.path, "name": config.get("general", "name") } )
|
result.append( { "path": entry.path, "name": config.get("general", "name") } )
|
||||||
|
@ -249,11 +249,11 @@ class VersionUpgrade25to26(VersionUpgrade):
|
|||||||
definition_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer)
|
definition_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer)
|
||||||
user_settings_dir = Resources.getPath(CuraApplication.ResourceTypes.UserInstanceContainer)
|
user_settings_dir = Resources.getPath(CuraApplication.ResourceTypes.UserInstanceContainer)
|
||||||
|
|
||||||
with open(os.path.join(definition_changes_dir, definition_changes_filename), "w") as f:
|
with open(os.path.join(definition_changes_dir, definition_changes_filename), "w", encoding = "utf-8") as f:
|
||||||
f.write(definition_changes_output.getvalue())
|
f.write(definition_changes_output.getvalue())
|
||||||
with open(os.path.join(user_settings_dir, user_settings_filename), "w") as f:
|
with open(os.path.join(user_settings_dir, user_settings_filename), "w", encoding = "utf-8") as f:
|
||||||
f.write(user_settings_output.getvalue())
|
f.write(user_settings_output.getvalue())
|
||||||
with open(os.path.join(extruder_stack_dir, extruder_filename), "w") as f:
|
with open(os.path.join(extruder_stack_dir, extruder_filename), "w", encoding = "utf-8") as f:
|
||||||
f.write(extruder_output.getvalue())
|
f.write(extruder_output.getvalue())
|
||||||
|
|
||||||
## Creates a definition changes container which doesn't contain anything for the Custom FDM Printers.
|
## Creates a definition changes container which doesn't contain anything for the Custom FDM Printers.
|
||||||
|
@ -1018,7 +1018,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def getProductIdMap(cls) -> Dict[str, List[str]]:
|
def getProductIdMap(cls) -> Dict[str, List[str]]:
|
||||||
product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json")
|
product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json")
|
||||||
with open(product_to_id_file) as f:
|
with open(product_to_id_file, encoding = "utf-8") as f:
|
||||||
product_to_id_map = json.load(f)
|
product_to_id_map = json.load(f)
|
||||||
product_to_id_map = {key: [value] for key, value in product_to_id_map.items()}
|
product_to_id_map = {key: [value] for key, value in product_to_id_map.items()}
|
||||||
return product_to_id_map
|
return product_to_id_map
|
||||||
|
@ -170,7 +170,7 @@ UM.PreferencesPage
|
|||||||
append({ text: "日本語", code: "ja_JP" })
|
append({ text: "日本語", code: "ja_JP" })
|
||||||
append({ text: "한국어", code: "ko_KR" })
|
append({ text: "한국어", code: "ko_KR" })
|
||||||
append({ text: "Nederlands", code: "nl_NL" })
|
append({ text: "Nederlands", code: "nl_NL" })
|
||||||
append({ text: "Polski", code: "pl_PL" })
|
//Polish is disabled for being incomplete: append({ text: "Polski", code: "pl_PL" })
|
||||||
append({ text: "Português do Brasil", code: "pt_BR" })
|
append({ text: "Português do Brasil", code: "pt_BR" })
|
||||||
append({ text: "Português", code: "pt_PT" })
|
append({ text: "Português", code: "pt_PT" })
|
||||||
append({ text: "Русский", code: "ru_RU" })
|
append({ text: "Русский", code: "ru_RU" })
|
||||||
@ -741,21 +741,6 @@ UM.PreferencesPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UM.TooltipArea
|
|
||||||
{
|
|
||||||
width: childrenRect.width
|
|
||||||
height: childrenRect.height
|
|
||||||
text: catalog.i18nc("@info:tooltip", "Should newly loaded models be arranged on the build plate? Used in conjunction with multi build plate (EXPERIMENTAL)")
|
|
||||||
|
|
||||||
CheckBox
|
|
||||||
{
|
|
||||||
id: arrangeOnLoadCheckbox
|
|
||||||
text: catalog.i18nc("@option:check", "Do not arrange objects on load")
|
|
||||||
checked: boolCheck(UM.Preferences.getValue("cura/not_arrange_objects_on_load"))
|
|
||||||
onCheckedChanged: UM.Preferences.setValue("cura/not_arrange_objects_on_load", checked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: UM.Preferences
|
target: UM.Preferences
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 80
|
speed_print = 80
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 80)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 80
|
speed_print = 80
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 80)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 80
|
speed_print = 80
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 80)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -17,6 +17,6 @@ top_bottom_thickness = 0.8
|
|||||||
infill_sparse_density = 20
|
infill_sparse_density = 20
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -41,13 +41,13 @@ retraction_speed = 40
|
|||||||
skirt_brim_speed = 40
|
skirt_brim_speed = 40
|
||||||
skirt_gap = 5
|
skirt_gap = 5
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_infill = 60
|
speed_infill = =speed_print
|
||||||
speed_print = 60
|
speed_print = 60
|
||||||
speed_support = 60
|
speed_support = 60
|
||||||
speed_topbottom = 30
|
speed_topbottom = =math.ceil(speed_print * 30 / 60)
|
||||||
speed_travel = 100
|
speed_travel = 100
|
||||||
speed_wall = 60
|
speed_wall = =speed_print
|
||||||
speed_wall_x = 60
|
speed_wall_x = =speed_print
|
||||||
support_angle = 60
|
support_angle = 60
|
||||||
support_enable = True
|
support_enable = True
|
||||||
support_interface_enable = True
|
support_interface_enable = True
|
||||||
|
@ -41,13 +41,13 @@ retraction_speed = 40
|
|||||||
skirt_brim_speed = 40
|
skirt_brim_speed = 40
|
||||||
skirt_gap = 5
|
skirt_gap = 5
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_infill = 50
|
speed_infill = =speed_print
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_support = 30
|
speed_support = 30
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
speed_travel = 50
|
speed_travel = 50
|
||||||
speed_wall = 50
|
speed_wall = =speed_print
|
||||||
speed_wall_x = 50
|
speed_wall_x = =speed_print
|
||||||
support_angle = 60
|
support_angle = 60
|
||||||
support_enable = True
|
support_enable = True
|
||||||
support_interface_enable = True
|
support_interface_enable = True
|
||||||
|
@ -41,13 +41,13 @@ retraction_speed = 40
|
|||||||
skirt_brim_speed = 40
|
skirt_brim_speed = 40
|
||||||
skirt_gap = 5
|
skirt_gap = 5
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_infill = 50
|
speed_infill = =speed_print
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_support = 30
|
speed_support = 30
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
speed_travel = 100
|
speed_travel = 100
|
||||||
speed_wall = 50
|
speed_wall = =speed_print
|
||||||
speed_wall_x = 50
|
speed_wall_x = =speed_print
|
||||||
support_angle = 60
|
support_angle = 60
|
||||||
support_enable = True
|
support_enable = True
|
||||||
support_interface_enable = True
|
support_interface_enable = True
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[general]
|
[general]
|
||||||
version = 4
|
version = 4
|
||||||
name = Coarse Quality
|
name = Coarse
|
||||||
definition = fdmprinter
|
definition = fdmprinter
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
@ -43,11 +43,11 @@ skirt_brim_minimal_length = 75
|
|||||||
skirt_gap = 1.5
|
skirt_gap = 1.5
|
||||||
skirt_line_count = 5
|
skirt_line_count = 5
|
||||||
speed_infill = =speed_print
|
speed_infill = =speed_print
|
||||||
speed_layer_0 = 25
|
speed_layer_0 = =math.ceil(speed_print * 25 / 50)
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_topbottom = 40
|
speed_topbottom = =math.ceil(speed_print * 40 / 50)
|
||||||
speed_travel = 200
|
speed_travel = 200
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 50)
|
||||||
speed_wall_x = =speed_print
|
speed_wall_x = =speed_print
|
||||||
support_angle = 70
|
support_angle = 70
|
||||||
support_type = buildplate
|
support_type = buildplate
|
||||||
|
@ -43,11 +43,11 @@ skirt_brim_minimal_length = 75
|
|||||||
skirt_gap = 1.5
|
skirt_gap = 1.5
|
||||||
skirt_line_count = 5
|
skirt_line_count = 5
|
||||||
speed_infill = =speed_print
|
speed_infill = =speed_print
|
||||||
speed_layer_0 = 25
|
speed_layer_0 = =math.ceil(speed_print * 25 / 50)
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_topbottom = 40
|
speed_topbottom = =math.ceil(speed_print * 40 / 50)
|
||||||
speed_travel = 200
|
speed_travel = 200
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 50)
|
||||||
speed_wall_x = =speed_print
|
speed_wall_x = =speed_print
|
||||||
support_angle = 70
|
support_angle = 70
|
||||||
support_type = buildplate
|
support_type = buildplate
|
||||||
|
@ -43,11 +43,11 @@ skirt_brim_minimal_length = 75
|
|||||||
skirt_gap = 1.5
|
skirt_gap = 1.5
|
||||||
skirt_line_count = 5
|
skirt_line_count = 5
|
||||||
speed_infill = =speed_print
|
speed_infill = =speed_print
|
||||||
speed_layer_0 = 25
|
speed_layer_0 = =math.ceil(speed_print * 25 / 50)
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_topbottom = 40
|
speed_topbottom = =math.ceil(speed_print * 40 / 50)
|
||||||
speed_travel = 200
|
speed_travel = 200
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 50)
|
||||||
speed_wall_x = =speed_print
|
speed_wall_x = =speed_print
|
||||||
support_angle = 70
|
support_angle = 70
|
||||||
support_type = buildplate
|
support_type = buildplate
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[general]
|
[general]
|
||||||
version = 4
|
version = 4
|
||||||
name = Draft Quality
|
name = Draft
|
||||||
definition = fdmprinter
|
definition = fdmprinter
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[general]
|
[general]
|
||||||
version = 4
|
version = 4
|
||||||
name = Extra Coarse Quality
|
name = Extra Coarse
|
||||||
definition = fdmprinter
|
definition = fdmprinter
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
@ -43,11 +43,11 @@ skirt_brim_minimal_length = 75
|
|||||||
skirt_gap = 1.5
|
skirt_gap = 1.5
|
||||||
skirt_line_count = 5
|
skirt_line_count = 5
|
||||||
speed_infill = =speed_print
|
speed_infill = =speed_print
|
||||||
speed_layer_0 = 25
|
speed_layer_0 = =math.ceil(speed_print * 25 / 30)
|
||||||
speed_print = 30
|
speed_print = 30
|
||||||
speed_topbottom = 40
|
speed_topbottom = =math.ceil(speed_print * 40 / 30)
|
||||||
speed_travel = 200
|
speed_travel = 200
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 30)
|
||||||
speed_wall_x = =speed_print
|
speed_wall_x = =speed_print
|
||||||
support_angle = 70
|
support_angle = 70
|
||||||
support_type = buildplate
|
support_type = buildplate
|
||||||
|
@ -43,11 +43,11 @@ skirt_brim_minimal_length = 75
|
|||||||
skirt_gap = 1.5
|
skirt_gap = 1.5
|
||||||
skirt_line_count = 5
|
skirt_line_count = 5
|
||||||
speed_infill = =speed_print
|
speed_infill = =speed_print
|
||||||
speed_layer_0 = 25
|
speed_layer_0 = =math.ceil(speed_print * 25 / 30)
|
||||||
speed_print = 30
|
speed_print = 30
|
||||||
speed_topbottom = 40
|
speed_topbottom = =math.ceil(speed_print * 40 / 30)
|
||||||
speed_travel = 200
|
speed_travel = 200
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 30)
|
||||||
speed_wall_x = =speed_print
|
speed_wall_x = =speed_print
|
||||||
support_angle = 70
|
support_angle = 70
|
||||||
support_type = buildplate
|
support_type = buildplate
|
||||||
|
@ -43,11 +43,11 @@ skirt_brim_minimal_length = 75
|
|||||||
skirt_gap = 1.5
|
skirt_gap = 1.5
|
||||||
skirt_line_count = 5
|
skirt_line_count = 5
|
||||||
speed_infill = =speed_print
|
speed_infill = =speed_print
|
||||||
speed_layer_0 = 25
|
speed_layer_0 = =math.ceil(speed_print * 25 / 30)
|
||||||
speed_print = 30
|
speed_print = 30
|
||||||
speed_topbottom = 40
|
speed_topbottom = =math.ceil(speed_print * 40 / 30)
|
||||||
speed_travel = 200
|
speed_travel = 200
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 30)
|
||||||
speed_wall_x = =speed_print
|
speed_wall_x = =speed_print
|
||||||
support_angle = 70
|
support_angle = 70
|
||||||
support_type = buildplate
|
support_type = buildplate
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[general]
|
[general]
|
||||||
version = 4
|
version = 4
|
||||||
name = Low Quality
|
name = Normal
|
||||||
definition = fdmprinter
|
definition = fdmprinter
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
@ -14,8 +14,8 @@ global_quality = True
|
|||||||
infill_sparse_density = 10
|
infill_sparse_density = 10
|
||||||
layer_height = 0.15
|
layer_height = 0.15
|
||||||
cool_min_layer_time = 3
|
cool_min_layer_time = 3
|
||||||
speed_wall_0 = 40
|
speed_wall_0 = =math.ceil(speed_print * 40 / 60)
|
||||||
speed_wall_x = 80
|
speed_wall_x = =math.ceil(speed_print * 80 / 60)
|
||||||
speed_infill = 100
|
speed_infill = =math.ceil(speed_print * 100 / 60)
|
||||||
wall_thickness = 1
|
wall_thickness = 1
|
||||||
speed_topbottom = 30
|
speed_topbottom = =math.ceil(speed_print * 30 / 60)
|
||||||
|
@ -12,5 +12,5 @@ global_quality = True
|
|||||||
|
|
||||||
[values]
|
[values]
|
||||||
layer_height = 0.06
|
layer_height = 0.06
|
||||||
speed_topbottom = 15
|
speed_topbottom = =math.ceil(speed_print * 15 / 60)
|
||||||
speed_infill = 80
|
speed_infill = =math.ceil(speed_print * 80 / 60)
|
||||||
|
@ -43,13 +43,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 25
|
skirt_brim_speed = 25
|
||||||
skirt_line_count = 2
|
skirt_line_count = 2
|
||||||
speed_layer_0 = 14
|
speed_layer_0 = =math.ceil(speed_print * 14 / 40)
|
||||||
speed_print = 40
|
speed_print = 40
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 40)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 40)
|
||||||
top_thickness = =top_bottom_thickness
|
top_thickness = =top_bottom_thickness
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -43,13 +43,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 25
|
skirt_brim_speed = 25
|
||||||
skirt_line_count = 2
|
skirt_line_count = 2
|
||||||
speed_layer_0 = 14
|
speed_layer_0 = =math.ceil(speed_print * 14 / 40)
|
||||||
speed_print = 40
|
speed_print = 40
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 40)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 40)
|
||||||
top_thickness = =top_bottom_thickness
|
top_thickness = =top_bottom_thickness
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -43,13 +43,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 25
|
skirt_brim_speed = 25
|
||||||
skirt_line_count = 2
|
skirt_line_count = 2
|
||||||
speed_layer_0 = 14
|
speed_layer_0 = =math.ceil(speed_print * 14 / 40)
|
||||||
speed_print = 40
|
speed_print = 40
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 40)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 40)
|
||||||
top_thickness = =top_bottom_thickness
|
top_thickness = =top_bottom_thickness
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -43,13 +43,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 25
|
skirt_brim_speed = 25
|
||||||
skirt_line_count = 2
|
skirt_line_count = 2
|
||||||
speed_layer_0 = 14
|
speed_layer_0 = =math.ceil(speed_print * 14 / 40)
|
||||||
speed_print = 40
|
speed_print = 40
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 40)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 40)
|
||||||
top_thickness = =top_bottom_thickness
|
top_thickness = =top_bottom_thickness
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -41,13 +41,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -41,13 +41,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -42,13 +42,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -42,13 +42,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -41,13 +41,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -41,13 +41,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -43,13 +43,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -43,13 +43,13 @@ skin_no_small_gaps_heuristic = False
|
|||||||
skirt_brim_minimal_length = 100
|
skirt_brim_minimal_length = 100
|
||||||
skirt_brim_speed = 20
|
skirt_brim_speed = 20
|
||||||
skirt_line_count = 3
|
skirt_line_count = 3
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 45)
|
||||||
speed_print = 45
|
speed_print = 45
|
||||||
speed_slowdown_layers = 1
|
speed_slowdown_layers = 1
|
||||||
speed_topbottom = 25
|
speed_topbottom = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
speed_travel_layer_0 = 60
|
speed_travel_layer_0 = 60
|
||||||
speed_wall = 25
|
speed_wall = =math.ceil(speed_print * 25 / 45)
|
||||||
speed_wall_x = 35
|
speed_wall_x = =math.ceil(speed_print * 35 / 45)
|
||||||
top_thickness = 0.8
|
top_thickness = 0.8
|
||||||
wall_thickness = 0.8
|
wall_thickness = 0.8
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.35
|
|||||||
layer_height_0 = 0.3
|
layer_height_0 = 0.3
|
||||||
|
|
||||||
speed_print = 70
|
speed_print = 70
|
||||||
speed_infill = 60
|
speed_infill = =math.ceil(speed_print * 60 / 70)
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 70)
|
||||||
speed_wall_0 = 30
|
speed_wall_0 = =math.ceil(speed_print * 30 / 70)
|
||||||
speed_wall_x = 50
|
speed_wall_x = =math.ceil(speed_print * 50 / 70)
|
||||||
speed_topbottom = 30
|
speed_topbottom = =math.ceil(speed_print * 30 / 70)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 246
|
material_print_temperature = 246
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.06
|
|||||||
layer_height_0 = 0.3
|
layer_height_0 = 0.3
|
||||||
|
|
||||||
speed_print = 40
|
speed_print = 40
|
||||||
speed_infill = 50
|
speed_infill = =math.ceil(speed_print * 50 / 40)
|
||||||
speed_layer_0 = 15
|
speed_layer_0 = =math.ceil(speed_print * 15 / 40)
|
||||||
speed_wall_0 = 20
|
speed_wall_0 = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_wall_x = 40
|
speed_wall_x = =speed_print
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 246
|
material_print_temperature = 246
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.1
|
|||||||
layer_height_0 = 0.3
|
layer_height_0 = 0.3
|
||||||
|
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_infill = 60
|
speed_infill = =math.ceil(speed_print * 60 / 50)
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 50)
|
||||||
speed_wall_0 = 25
|
speed_wall_0 = =math.ceil(speed_print * 25 / 50)
|
||||||
speed_wall_x = 45
|
speed_wall_x = =math.ceil(speed_print * 45 / 50)
|
||||||
speed_topbottom = 30
|
speed_topbottom = =math.ceil(speed_print * 30 / 50)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 246
|
material_print_temperature = 246
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.2
|
|||||||
layer_height_0 = 0.3
|
layer_height_0 = 0.3
|
||||||
|
|
||||||
speed_print = 70
|
speed_print = 70
|
||||||
speed_infill = 60
|
speed_infill = =math.ceil(speed_print * 60 / 70)
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 70)
|
||||||
speed_wall_0 = 30
|
speed_wall_0 = =math.ceil(speed_print * 30 / 70)
|
||||||
speed_wall_x = 50
|
speed_wall_x = =math.ceil(speed_print * 50 / 70)
|
||||||
speed_topbottom = 30
|
speed_topbottom = =math.ceil(speed_print * 30 / 70)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 246
|
material_print_temperature = 246
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.15
|
|||||||
layer_height_0 = 0.3
|
layer_height_0 = 0.3
|
||||||
|
|
||||||
speed_print = 60
|
speed_print = 60
|
||||||
speed_infill = 50
|
speed_infill = =math.ceil(speed_print * 50 / 60)
|
||||||
speed_layer_0 = 15
|
speed_layer_0 = =math.ceil(speed_print * 15 / 60)
|
||||||
speed_wall_0 = 20
|
speed_wall_0 = =math.ceil(speed_print * 20 / 60)
|
||||||
speed_wall_x = 40
|
speed_wall_x = =math.ceil(speed_print * 40 / 60)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 60)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 246
|
material_print_temperature = 246
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.06
|
|||||||
adhesion_type = skirt
|
adhesion_type = skirt
|
||||||
|
|
||||||
speed_print = 40
|
speed_print = 40
|
||||||
speed_infill = 50
|
speed_infill = =math.ceil(speed_print * 50 / 40)
|
||||||
speed_layer_0 = 15
|
speed_layer_0 = =math.ceil(speed_print * 15 / 40)
|
||||||
speed_wall_0 = 20
|
speed_wall_0 = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_wall_x = 40
|
speed_wall_x = =speed_print
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 40)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 214
|
material_print_temperature = 214
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.1
|
|||||||
adhesion_type = skirt
|
adhesion_type = skirt
|
||||||
|
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_infill = 60
|
speed_infill = =math.ceil(speed_print * 60 / 50)
|
||||||
speed_layer_0 = 20
|
speed_layer_0 = =math.ceil(speed_print * 20 / 50)
|
||||||
speed_wall_0 = 25
|
speed_wall_0 = =math.ceil(speed_print * 25 / 50)
|
||||||
speed_wall_x = 45
|
speed_wall_x = =math.ceil(speed_print * 45 / 50)
|
||||||
speed_topbottom = 30
|
speed_topbottom = =math.ceil(speed_print * 30 / 50)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 214
|
material_print_temperature = 214
|
||||||
|
@ -15,11 +15,11 @@ layer_height = 0.15
|
|||||||
adhesion_type = skirt
|
adhesion_type = skirt
|
||||||
|
|
||||||
speed_print = 60
|
speed_print = 60
|
||||||
speed_infill = 50
|
speed_infill = =math.ceil(speed_print * 50 / 60)
|
||||||
speed_layer_0 = 15
|
speed_layer_0 = =math.ceil(speed_print * 15 / 60)
|
||||||
speed_wall_0 = 20
|
speed_wall_0 = =math.ceil(speed_print * 20 / 60)
|
||||||
speed_wall_x = 40
|
speed_wall_x = =math.ceil(speed_print * 40 / 60)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 60)
|
||||||
speed_travel = 120
|
speed_travel = 120
|
||||||
|
|
||||||
material_print_temperature = 214
|
material_print_temperature = 214
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
@ -18,6 +18,6 @@ top_bottom_thickness = 0.72
|
|||||||
infill_sparse_density = 22
|
infill_sparse_density = 22
|
||||||
speed_print = 50
|
speed_print = 50
|
||||||
speed_layer_0 = =round(speed_print * 30 / 50)
|
speed_layer_0 = =round(speed_print * 30 / 50)
|
||||||
speed_topbottom = 20
|
speed_topbottom = =math.ceil(speed_print * 20 / 50)
|
||||||
cool_min_layer_time = 5
|
cool_min_layer_time = 5
|
||||||
cool_min_speed = 10
|
cool_min_speed = 10
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user