diff --git a/.gitignore b/.gitignore index 98eaa6f414..0a66b6eb33 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ LC_MESSAGES .cache *.qmlc .mypy_cache +.pytest_cache #MacOS .DS_Store @@ -25,6 +26,7 @@ LC_MESSAGES *.lprof *~ *.qm +.directory .idea cura.desktop diff --git a/cura/API/Backups.py b/cura/API/Backups.py index 5964557264..f31933c844 100644 --- a/cura/API/Backups.py +++ b/cura/API/Backups.py @@ -13,6 +13,7 @@ from cura.Backups.BackupsManager import BackupsManager # api = CuraAPI() # api.backups.createBackup() # api.backups.restoreBackup(my_zip_file, {"cura_release": "3.1"})`` + class Backups: manager = BackupsManager() # Re-used instance of the backups manager. diff --git a/cura/API/Interface/Settings.py b/cura/API/Interface/Settings.py new file mode 100644 index 0000000000..2889db7022 --- /dev/null +++ b/cura/API/Interface/Settings.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from cura.CuraApplication import CuraApplication + +## The Interface.Settings API provides a version-proof bridge between Cura's +# (currently) sidebar UI and plug-ins that hook into it. +# +# Usage: +# ``from cura.API import CuraAPI +# api = CuraAPI() +# api.interface.settings.getContextMenuItems() +# data = { +# "name": "My Plugin Action", +# "iconName": "my-plugin-icon", +# "actions": my_menu_actions, +# "menu_item": MyPluginAction(self) +# } +# api.interface.settings.addContextMenuItem(data)`` + +class Settings: + # Re-used instance of Cura: + application = CuraApplication.getInstance() # type: CuraApplication + + ## Add items to the sidebar context menu. + # \param menu_item dict containing the menu item to add. + def addContextMenuItem(self, menu_item: dict) -> None: + self.application.addSidebarCustomMenuItem(menu_item) + + ## Get all custom items currently added to the sidebar context menu. + # \return List containing all custom context menu items. + def getContextMenuItems(self) -> list: + return self.application.getSidebarCustomMenuItems() \ No newline at end of file diff --git a/cura/API/Interface/__init__.py b/cura/API/Interface/__init__.py new file mode 100644 index 0000000000..b38118949b --- /dev/null +++ b/cura/API/Interface/__init__.py @@ -0,0 +1,24 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from UM.PluginRegistry import PluginRegistry +from cura.API.Interface.Settings import Settings + +## The Interface class serves as a common root for the specific API +# methods for each interface element. +# +# Usage: +# ``from cura.API import CuraAPI +# api = CuraAPI() +# api.interface.settings.addContextMenuItem() +# api.interface.viewport.addOverlay() # Not implemented, just a hypothetical +# api.interface.toolbar.getToolButtonCount() # Not implemented, just a hypothetical +# # etc.`` + +class Interface: + + # For now we use the same API version to be consistent. + VERSION = PluginRegistry.APIVersion + + # API methods specific to the settings portion of the UI + settings = Settings() diff --git a/cura/API/__init__.py b/cura/API/__init__.py index 13f6722336..64d636903d 100644 --- a/cura/API/__init__.py +++ b/cura/API/__init__.py @@ -2,6 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from UM.PluginRegistry import PluginRegistry from cura.API.Backups import Backups +from cura.API.Interface import Interface ## The official Cura API that plug-ins can use to interact with Cura. # @@ -9,10 +10,14 @@ from cura.API.Backups import Backups # 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: # For now we use the same API version to be consistent. VERSION = PluginRegistry.APIVersion - # Backups API. + # Backups API backups = Backups() + + # Interface API + interface = Interface() diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 87f0eb543e..b029665abd 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -3,6 +3,7 @@ from cura.Scene.CuraSceneNode import CuraSceneNode from cura.Settings.ExtruderManager import ExtruderManager +from UM.Application import Application #To modify the maximum zoom level. from UM.i18n import i18nCatalog from UM.Scene.Platform import Platform from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator @@ -170,6 +171,12 @@ class BuildVolume(SceneNode): if shape: self._shape = shape + ## Get the length of the 3D diagonal through the build volume. + # + # This gives a sense of the scale of the build volume in general. + def getDiagonalSize(self) -> float: + return math.sqrt(self._width * self._width + self._height * self._height + self._depth * self._depth) + def getDisallowedAreas(self) -> List[Polygon]: return self._disallowed_areas @@ -235,6 +242,8 @@ class BuildVolume(SceneNode): # Mark the node as outside build volume if the set extruder is disabled extruder_position = node.callDecoration("getActiveExtruderPosition") + if extruder_position not in self._global_container_stack.extruders: + continue if not self._global_container_stack.extruders[extruder_position].isEnabled: node.setOutsideBuildArea(True) continue @@ -552,6 +561,12 @@ class BuildVolume(SceneNode): if self._engine_ready: self.rebuild() + camera = Application.getInstance().getController().getCameraTool() + if camera: + diagonal = self.getDiagonalSize() + if diagonal > 1: + camera.setZoomRange(min = 0.1, max = diagonal * 5) #You can zoom out up to 5 times the diagonal. This gives some space around the volume. + def _onEngineCreated(self): self._engine_ready = True self.rebuild() diff --git a/cura/CameraImageProvider.py b/cura/CameraImageProvider.py index ddf978f625..ff5c51f24b 100644 --- a/cura/CameraImageProvider.py +++ b/cura/CameraImageProvider.py @@ -4,15 +4,20 @@ from PyQt5.QtCore import QSize from UM.Application import Application + class CameraImageProvider(QQuickImageProvider): def __init__(self): - QQuickImageProvider.__init__(self, QQuickImageProvider.Image) + super().__init__(QQuickImageProvider.Image) ## Request a new image. def requestImage(self, id, size): for output_device in Application.getInstance().getOutputDeviceManager().getOutputDevices(): try: - return output_device.activePrinter.camera.getImage(), QSize(15, 15) + image = output_device.activePrinter.camera.getImage() + if image.isNull(): + image = QImage() + + return image, QSize(15, 15) except AttributeError: pass - return QImage(), QSize(15, 15) \ No newline at end of file + return QImage(), QSize(15, 15) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 1b2c6c576c..93a18318df 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -50,7 +50,8 @@ class CuraActions(QObject): scene = cura.CuraApplication.CuraApplication.getInstance().getController().getScene() camera = scene.getActiveCamera() if camera: - camera.setPosition(Vector(-80, 250, 700)) + diagonal_size = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getDiagonalSize() + camera.setPosition(Vector(-80, 250, 700) * diagonal_size / 375) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 3f0a5b9cb2..833f43e29c 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1,11 +1,10 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -import copy import os import sys import time -from typing import cast, TYPE_CHECKING, Optional +from typing import cast, TYPE_CHECKING import numpy @@ -68,9 +67,9 @@ from cura.Machines.Models.NozzleModel import NozzleModel from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfilesDropDownMenuModel from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel -from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel +from cura.Machines.Models.FavoriteMaterialsModel import FavoriteMaterialsModel from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel -from cura.Machines.Models.BrandMaterialsModel import BrandMaterialsModel +from cura.Machines.Models.MaterialBrandsModel import MaterialBrandsModel from cura.Machines.Models.QualityManagementModel import QualityManagementModel from cura.Machines.Models.QualitySettingsModel import QualitySettingsModel from cura.Machines.Models.MachineManagementModel import MachineManagementModel @@ -104,6 +103,8 @@ from cura.Settings.UserChangesModel import UserChangesModel from cura.Settings.ExtrudersModel import ExtrudersModel from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.ContainerManager import ContainerManager +from cura.Settings.SidebarCustomMenuItemsModel import SidebarCustomMenuItemsModel +import cura.Settings.cura_empty_instance_containers from cura.ObjectsModel import ObjectsModel @@ -117,11 +118,12 @@ if TYPE_CHECKING: numpy.seterr(all = "ignore") try: - from cura.CuraVersion import CuraVersion, CuraBuildType, CuraDebugMode + from cura.CuraVersion import CuraVersion, CuraBuildType, CuraDebugMode, CuraSDKVersion except ImportError: CuraVersion = "master" # [CodeStyle: Reflecting imported value] CuraBuildType = "" CuraDebugMode = False + CuraSDKVersion = "" class CuraApplication(QtApplication): @@ -213,7 +215,6 @@ class CuraApplication(QtApplication): self._message_box_callback = None self._message_box_callback_arguments = [] - self._preferred_mimetype = "" self._i18n_catalog = None self._currently_loading_files = [] @@ -226,6 +227,10 @@ class CuraApplication(QtApplication): self._need_to_show_user_agreement = True + self._sidebar_custom_menu_items = [] # type: list # Keeps list of custom menu items for the side bar + + self._plugins_loaded = False + # Backups self._auto_save = None self._save_data_enabled = True @@ -362,42 +367,23 @@ class CuraApplication(QtApplication): # Add empty variant, material and quality containers. # Since they are empty, they should never be serialized and instead just programmatically created. # We need them to simplify the switching between materials. - empty_container = self._container_registry.getEmptyInstanceContainer() - self.empty_container = empty_container + self.empty_container = cura.Settings.cura_empty_instance_containers.empty_container - empty_definition_changes_container = copy.deepcopy(empty_container) - empty_definition_changes_container.setMetaDataEntry("id", "empty_definition_changes") - empty_definition_changes_container.setMetaDataEntry("type", "definition_changes") - self._container_registry.addContainer(empty_definition_changes_container) - self.empty_definition_changes_container = empty_definition_changes_container + self._container_registry.addContainer( + cura.Settings.cura_empty_instance_containers.empty_definition_changes_container) + self.empty_definition_changes_container = cura.Settings.cura_empty_instance_containers.empty_definition_changes_container - empty_variant_container = copy.deepcopy(empty_container) - empty_variant_container.setMetaDataEntry("id", "empty_variant") - empty_variant_container.setMetaDataEntry("type", "variant") - self._container_registry.addContainer(empty_variant_container) - self.empty_variant_container = empty_variant_container + self._container_registry.addContainer(cura.Settings.cura_empty_instance_containers.empty_variant_container) + self.empty_variant_container = cura.Settings.cura_empty_instance_containers.empty_variant_container - empty_material_container = copy.deepcopy(empty_container) - empty_material_container.setMetaDataEntry("id", "empty_material") - empty_material_container.setMetaDataEntry("type", "material") - self._container_registry.addContainer(empty_material_container) - self.empty_material_container = empty_material_container + self._container_registry.addContainer(cura.Settings.cura_empty_instance_containers.empty_material_container) + self.empty_material_container = cura.Settings.cura_empty_instance_containers.empty_material_container - empty_quality_container = copy.deepcopy(empty_container) - empty_quality_container.setMetaDataEntry("id", "empty_quality") - empty_quality_container.setName("Not Supported") - empty_quality_container.setMetaDataEntry("quality_type", "not_supported") - empty_quality_container.setMetaDataEntry("type", "quality") - empty_quality_container.setMetaDataEntry("supported", False) - self._container_registry.addContainer(empty_quality_container) - self.empty_quality_container = empty_quality_container + self._container_registry.addContainer(cura.Settings.cura_empty_instance_containers.empty_quality_container) + self.empty_quality_container = cura.Settings.cura_empty_instance_containers.empty_quality_container - empty_quality_changes_container = copy.deepcopy(empty_container) - empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes") - empty_quality_changes_container.setMetaDataEntry("type", "quality_changes") - empty_quality_changes_container.setMetaDataEntry("quality_type", "not_supported") - self._container_registry.addContainer(empty_quality_changes_container) - self.empty_quality_changes_container = empty_quality_changes_container + self._container_registry.addContainer(cura.Settings.cura_empty_instance_containers.empty_quality_changes_container) + self.empty_quality_changes_container = cura.Settings.cura_empty_instance_containers.empty_quality_changes_container # Initializes the version upgrade manager with by providing the paths for each resource type and the latest # versions. @@ -494,7 +480,9 @@ class CuraApplication(QtApplication): preferences.addPreference("view/filter_current_build_plate", False) preferences.addPreference("cura/sidebar_collapsed", False) - self._need_to_show_user_agreement = not self.getPreferences().getValue("general/accepted_user_agreement") + preferences.addPreference("cura/favorite_materials", ";".join([])) + + self._need_to_show_user_agreement = not preferences.getValue("general/accepted_user_agreement") for key in [ "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin @@ -508,9 +496,6 @@ class CuraApplication(QtApplication): self.applicationShuttingDown.connect(self.saveSettings) self.engineCreatedSignal.connect(self._onEngineCreated) - self.globalContainerStackChanged.connect(self._onGlobalContainerChanged) - self._onGlobalContainerChanged() - self.getCuraSceneController().setActiveBuildPlate(0) # Initialize CuraApplication.Created = True @@ -625,7 +610,7 @@ class CuraApplication(QtApplication): # Cura has multiple locations where instance containers need to be saved, so we need to handle this differently. def saveSettings(self): if not self.started or not self._save_data_enabled: - # Do not do saving during application start or when data should not be safed on quit. + # Do not do saving during application start or when data should not be saved on quit. return ContainerRegistry.getInstance().saveDirtyContainers() self.savePreferences() @@ -774,7 +759,10 @@ class CuraApplication(QtApplication): # Initialize camera root = controller.getScene().getRoot() camera = Camera("3d", root) - camera.setPosition(Vector(-80, 250, 700)) + diagonal = self.getBuildVolume().getDiagonalSize() + if diagonal < 1: #No printer added yet. Set a default camera distance for normal-sized printers. + diagonal = 375 + camera.setPosition(Vector(-80, 250, 700) * diagonal / 375) camera.setPerspective(True) camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") @@ -908,6 +896,7 @@ class CuraApplication(QtApplication): engine.rootContext().setContextProperty("CuraApplication", self) engine.rootContext().setContextProperty("PrintInformation", self._print_information) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) + engine.rootContext().setContextProperty("CuraSDKVersion", CuraSDKVersion) qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") @@ -924,9 +913,9 @@ class CuraApplication(QtApplication): qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer") qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") + qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel") qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel") - qmlRegisterType(BrandMaterialsModel, "Cura", 1, 0, "BrandMaterialsModel") - qmlRegisterType(MaterialManagementModel, "Cura", 1, 0, "MaterialManagementModel") + qmlRegisterType(MaterialBrandsModel, "Cura", 1, 0, "MaterialBrandsModel") qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel") qmlRegisterType(MachineManagementModel, "Cura", 1, 0, "MachineManagementModel") @@ -942,6 +931,7 @@ class CuraApplication(QtApplication): qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel") qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.getInstance) + qmlRegisterType(SidebarCustomMenuItemsModel, "Cura", 1, 0, "SidebarCustomMenuItemsModel") # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work. actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml"))) @@ -989,30 +979,14 @@ class CuraApplication(QtApplication): self._camera_animation.setTarget(Selection.getSelectedObject(0).getWorldPosition()) self._camera_animation.start() - def _onGlobalContainerChanged(self): - if self._global_container_stack is not None: - machine_file_formats = [file_type.strip() for file_type in self._global_container_stack.getMetaDataEntry("file_formats").split(";")] - new_preferred_mimetype = "" - if machine_file_formats: - new_preferred_mimetype = machine_file_formats[0] - - if new_preferred_mimetype != self._preferred_mimetype: - self._preferred_mimetype = new_preferred_mimetype - self.preferredOutputMimetypeChanged.emit() - requestAddPrinter = pyqtSignal() activityChanged = pyqtSignal() sceneBoundingBoxChanged = pyqtSignal() - preferredOutputMimetypeChanged = pyqtSignal() @pyqtProperty(bool, notify = activityChanged) def platformActivity(self): return self._platform_activity - @pyqtProperty(str, notify=preferredOutputMimetypeChanged) - def preferredOutputMimetype(self): - return self._preferred_mimetype - @pyqtProperty(str, notify = sceneBoundingBoxChanged) def getSceneBoundingBoxString(self): return self._i18n_catalog.i18nc("@info 'width', 'depth' and 'height' are variable names that must NOT be translated; just translate the format of ##x##x## mm.", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_bounding_box.width.item(), 'depth': self._scene_bounding_box.depth.item(), 'height' : self._scene_bounding_box.height.item()} @@ -1599,12 +1573,13 @@ class CuraApplication(QtApplication): def _readMeshFinished(self, job): nodes = job.getResult() - filename = job.getFileName() - self._currently_loading_files.remove(filename) + file_name = job.getFileName() + file_name_lower = file_name.lower() + file_extension = file_name_lower.split(".")[-1] + self._currently_loading_files.remove(file_name) - self.fileLoaded.emit(filename) - arrange_objects_on_load = not self.getPreferences().getValue("cura/use_multi_build_plate") - target_build_plate = self.getMultiBuildPlateModel().activeBuildPlate if arrange_objects_on_load else -1 + self.fileLoaded.emit(file_name) + target_build_plate = self.getMultiBuildPlateModel().activeBuildPlate root = self.getController().getScene().getRoot() fixed_nodes = [] @@ -1635,15 +1610,11 @@ class CuraApplication(QtApplication): node.scale(original_node.getScale()) node.setSelectable(True) - node.setName(os.path.basename(filename)) + node.setName(os.path.basename(file_name)) self.getBuildVolume().checkBoundsAndUpdate(node) - is_non_sliceable = False - filename_lower = filename.lower() - for extension in self._non_sliceable_extensions: - if filename_lower.endswith(extension): - is_non_sliceable = True - break + is_non_sliceable = "." + file_extension in self._non_sliceable_extensions + if is_non_sliceable: self.callLater(lambda: self.getController().setActiveView("SimulationView")) @@ -1662,7 +1633,7 @@ class CuraApplication(QtApplication): if not child.getDecorator(ConvexHullDecorator): child.addDecorator(ConvexHullDecorator()) - if arrange_objects_on_load: + if file_extension != "3mf": if node.callDecoration("isSliceable"): # Only check position if it's not already blatantly obvious that it won't fit. if node.getBoundingBox() is None or self._volume.getBoundingBox() is None or node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth: @@ -1696,7 +1667,7 @@ class CuraApplication(QtApplication): if select_models_on_load: Selection.add(node) - self.fileCompleted.emit(filename) + self.fileCompleted.emit(file_name) def addNonSliceableExtension(self, extension): self._non_sliceable_extensions.append(extension) @@ -1732,3 +1703,10 @@ class CuraApplication(QtApplication): @pyqtSlot() def showMoreInformationDialogForAnonymousDataCollection(self): cast(SliceInfo, self._plugin_registry.getPluginObject("SliceInfoPlugin")).showMoreInfoDialog() + + def addSidebarCustomMenuItem(self, menu_item: dict) -> None: + self._sidebar_custom_menu_items.append(menu_item) + + def getSidebarCustomMenuItems(self) -> list: + return self._sidebar_custom_menu_items + diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index 9766e0c82a..f33934de0c 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -21,7 +21,7 @@ class LayerPolygon: __number_of_types = 11 __jump_map = numpy.logical_or(numpy.logical_or(numpy.arange(__number_of_types) == NoneType, numpy.arange(__number_of_types) == MoveCombingType), numpy.arange(__number_of_types) == MoveRetractionType) - + ## LayerPolygon, used in ProcessSlicedLayersJob # \param extruder # \param line_types array with line_types diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index 5d691fcef4..1463f2e40e 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -4,8 +4,8 @@ from collections import defaultdict, OrderedDict import copy import uuid -from typing import Dict, cast -from typing import Optional, TYPE_CHECKING +import json +from typing import Dict, Optional, TYPE_CHECKING from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot @@ -18,6 +18,7 @@ from UM.Util import parseBool from .MaterialNode import MaterialNode from .MaterialGroup import MaterialGroup +from .VariantType import VariantType if TYPE_CHECKING: from UM.Settings.DefinitionContainer import DefinitionContainer @@ -38,7 +39,8 @@ if TYPE_CHECKING: # class MaterialManager(QObject): - materialsUpdated = pyqtSignal() # Emitted whenever the material lookup tables are updated. + materialsUpdated = pyqtSignal() # Emitted whenever the material lookup tables are updated. + favoritesUpdated = pyqtSignal() # Emitted whenever the favorites are changed def __init__(self, container_registry, parent = None): super().__init__(parent) @@ -47,7 +49,7 @@ class MaterialManager(QObject): self._fallback_materials_map = dict() # material_type -> generic material metadata self._material_group_map = dict() # root_material_id -> MaterialGroup - self._diameter_machine_variant_material_map = dict() # approximate diameter str -> dict(machine_definition_id -> MaterialNode) + self._diameter_machine_nozzle_buildplate_material_map = dict() # approximate diameter str -> dict(machine_definition_id -> MaterialNode) # We're using these two maps to convert between the specific diameter material id and the generic material id # because the generic material ids are used in qualities and definitions, while the specific diameter material is meant @@ -75,6 +77,8 @@ class MaterialManager(QObject): self._container_registry.containerAdded.connect(self._onContainerMetadataChanged) self._container_registry.containerRemoved.connect(self._onContainerMetadataChanged) + self._favorites = set() + def initialize(self): # Find all materials and put them in a matrix for quick search. material_metadatas = {metadata["id"]: metadata for metadata in @@ -187,52 +191,83 @@ class MaterialManager(QObject): self._diameter_material_map[root_material_id] = default_root_material_id # Map #4 - # "machine" -> "variant_name" -> "root material ID" -> specific material InstanceContainer - # Construct the "machine" -> "variant" -> "root material ID" -> specific material InstanceContainer - self._diameter_machine_variant_material_map = dict() + # "machine" -> "nozzle name" -> "buildplate name" -> "root material ID" -> specific material InstanceContainer + self._diameter_machine_nozzle_buildplate_material_map = dict() for material_metadata in material_metadatas.values(): - # We don't store empty material in the lookup tables - if material_metadata["id"] == "empty_material": - continue - - root_material_id = material_metadata["base_file"] - definition = material_metadata["definition"] - approximate_diameter = material_metadata["approximate_diameter"] - - if approximate_diameter not in self._diameter_machine_variant_material_map: - self._diameter_machine_variant_material_map[approximate_diameter] = {} - - machine_variant_material_map = self._diameter_machine_variant_material_map[approximate_diameter] - if definition not in machine_variant_material_map: - machine_variant_material_map[definition] = MaterialNode() - - machine_node = machine_variant_material_map[definition] - variant_name = material_metadata.get("variant_name") - if not variant_name: - # if there is no variant, this material is for the machine, so put its metadata in the machine node. - machine_node.material_map[root_material_id] = MaterialNode(material_metadata) - else: - # this material is variant-specific, so we save it in a variant-specific node under the - # machine-specific node - - # Check first if the variant exist in the manager - existing_variant = self._application.getVariantManager().getVariantNode(definition, variant_name) - if existing_variant is not None: - if variant_name not in machine_node.children_map: - machine_node.children_map[variant_name] = MaterialNode() - - variant_node = machine_node.children_map[variant_name] - if root_material_id in variant_node.material_map: # We shouldn't have duplicated variant-specific materials for the same machine. - ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id) - continue - variant_node.material_map[root_material_id] = MaterialNode(material_metadata) - else: - # Add this container id to the wrong containers list in the registry - Logger.log("w", "Not adding {id} to the material manager because the variant does not exist.".format(id = material_metadata["id"])) - self._container_registry.addWrongContainerId(material_metadata["id"]) + self.__addMaterialMetadataIntoLookupTree(material_metadata) self.materialsUpdated.emit() + favorites = self._application.getPreferences().getValue("cura/favorite_materials") + for item in favorites.split(";"): + self._favorites.add(item) + self.favoritesUpdated.emit() + + def __addMaterialMetadataIntoLookupTree(self, material_metadata: dict) -> None: + material_id = material_metadata["id"] + + # We don't store empty material in the lookup tables + if material_id == "empty_material": + return + + root_material_id = material_metadata["base_file"] + definition = material_metadata["definition"] + approximate_diameter = material_metadata["approximate_diameter"] + + if approximate_diameter not in self._diameter_machine_nozzle_buildplate_material_map: + self._diameter_machine_nozzle_buildplate_material_map[approximate_diameter] = {} + + machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[ + approximate_diameter] + if definition not in machine_nozzle_buildplate_material_map: + machine_nozzle_buildplate_material_map[definition] = MaterialNode() + + # This is a list of information regarding the intermediate nodes: + # nozzle -> buildplate + nozzle_name = material_metadata.get("variant_name") + buildplate_name = material_metadata.get("buildplate_name") + intermediate_node_info_list = [(nozzle_name, VariantType.NOZZLE), + (buildplate_name, VariantType.BUILD_PLATE), + ] + + variant_manager = self._application.getVariantManager() + + machine_node = machine_nozzle_buildplate_material_map[definition] + current_node = machine_node + current_intermediate_node_info_idx = 0 + error_message = None # type: Optional[str] + while current_intermediate_node_info_idx < len(intermediate_node_info_list): + variant_name, variant_type = intermediate_node_info_list[current_intermediate_node_info_idx] + if variant_name is not None: + # The new material has a specific variant, so it needs to be added to that specific branch in the tree. + variant = variant_manager.getVariantNode(definition, variant_name, variant_type) + if variant is None: + error_message = "Material {id} contains a variant {name} that does not exist.".format( + id = material_metadata["id"], name = variant_name) + break + + # Update the current node to advance to a more specific branch + if variant_name not in current_node.children_map: + current_node.children_map[variant_name] = MaterialNode() + current_node = current_node.children_map[variant_name] + + current_intermediate_node_info_idx += 1 + + if error_message is not None: + Logger.log("e", "%s It will not be added into the material lookup tree.", error_message) + self._container_registry.addWrongContainerId(material_metadata["id"]) + return + + # Add the material to the current tree node, which is the deepest (the most specific) branch we can find. + # Sanity check: Make sure that there is no duplicated materials. + if root_material_id in current_node.material_map: + Logger.log("e", "Duplicated material [%s] with root ID [%s]. It has already been added.", + material_id, root_material_id) + ConfigurationErrorMessage.getInstance().addFaultyContainers(root_material_id) + return + + current_node.material_map[root_material_id] = MaterialNode(material_metadata) + def _updateMaps(self): Logger.log("i", "Updating material lookup data ...") self.initialize() @@ -263,45 +298,52 @@ class MaterialManager(QObject): # # 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], - diameter: float) -> Dict[str, MaterialNode]: + def getAvailableMaterials(self, machine_definition: "DefinitionContainer", nozzle_name: Optional[str], + buildplate_name: Optional[str], diameter: float) -> Dict[str, MaterialNode]: # round the diameter to get the approximate 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_nozzle_buildplate_material_map: Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s])", diameter, rounded_diameter) return dict() machine_definition_id = machine_definition.getId() - # If there are variant materials, get the variant material - machine_variant_material_map = self._diameter_machine_variant_material_map[rounded_diameter] - machine_node = machine_variant_material_map.get(machine_definition_id) - default_machine_node = machine_variant_material_map.get(self._default_machine_definition_id) - variant_node = None - if extruder_variant_name is not None and machine_node is not None: - variant_node = machine_node.getChildNode(extruder_variant_name) + # If there are nozzle-and-or-buildplate materials, get the nozzle-and-or-buildplate material + machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[rounded_diameter] + machine_node = machine_nozzle_buildplate_material_map.get(machine_definition_id) + default_machine_node = machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id) + nozzle_node = None + buildplate_node = None + if nozzle_name is not None and machine_node is not None: + nozzle_node = machine_node.getChildNode(nozzle_name) + # Get buildplate node if possible + if nozzle_node is not None and buildplate_name is not None: + buildplate_node = nozzle_node.getChildNode(buildplate_name) - nodes_to_check = [variant_node, machine_node, default_machine_node] + nodes_to_check = [buildplate_node, nozzle_node, machine_node, default_machine_node] # Fallback mechanism of finding materials: - # 1. variant-specific material - # 2. machine-specific material - # 3. generic material (for fdmprinter) + # 1. buildplate-specific material + # 2. nozzle-specific material + # 3. machine-specific material + # 4. generic material (for fdmprinter) machine_exclude_materials = machine_definition.getMetaDataEntry("exclude_materials", []) - material_id_metadata_dict = dict() # type: Dict[str, MaterialNode] - for node in nodes_to_check: - if node is not None: - # Only exclude the materials that are explicitly specified in the "exclude_materials" field. - # Do not exclude other materials that are of the same type. - for material_id, node in node.material_map.items(): - if material_id in machine_exclude_materials: - Logger.log("d", "Exclude material [%s] for machine [%s]", - material_id, machine_definition.getId()) - continue + material_id_metadata_dict = dict() # type: Dict[str, MaterialNode] + for current_node in nodes_to_check: + if current_node is None: + continue - if material_id not in material_id_metadata_dict: - material_id_metadata_dict[material_id] = node + # Only exclude the materials that are explicitly specified in the "exclude_materials" field. + # Do not exclude other materials that are of the same type. + for material_id, node in current_node.material_map.items(): + if material_id in machine_exclude_materials: + Logger.log("d", "Exclude material [%s] for machine [%s]", + material_id, machine_definition.getId()) + continue + + if material_id not in material_id_metadata_dict: + material_id_metadata_dict[material_id] = node return material_id_metadata_dict @@ -310,13 +352,14 @@ class MaterialManager(QObject): # def getAvailableMaterialsForMachineExtruder(self, machine: "GlobalStack", extruder_stack: "ExtruderStack") -> Optional[dict]: - variant_name = None + buildplate_name = machine.getBuildplateName() + nozzle_name = None if extruder_stack.variant.getId() != "empty_variant": - variant_name = extruder_stack.variant.getName() + nozzle_name = extruder_stack.variant.getName() diameter = extruder_stack.approximateMaterialDiameter # Fetch the available materials (ContainerNode) for the current active machine and extruder setup. - return self.getAvailableMaterials(machine.definition, variant_name, diameter) + return self.getAvailableMaterials(machine.definition, nozzle_name, buildplate_name, diameter) # # Gets MaterialNode for the given extruder and machine with the given material name. @@ -324,32 +367,36 @@ class MaterialManager(QObject): # 1. the given machine doesn't have materials; # 2. cannot find any material InstanceContainers with the given settings. # - def getMaterialNode(self, machine_definition_id: str, extruder_variant_name: Optional[str], - diameter: float, root_material_id: str) -> Optional["InstanceContainer"]: + def getMaterialNode(self, machine_definition_id: str, nozzle_name: Optional[str], + buildplate_name: Optional[str], diameter: float, root_material_id: str) -> Optional["InstanceContainer"]: # round the diameter to get the approximate 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_nozzle_buildplate_material_map: Logger.log("i", "Cannot find materials with diameter [%s] (rounded to [%s]) for root material id [%s]", diameter, rounded_diameter, root_material_id) return None - # If there are variant materials, get the variant material - machine_variant_material_map = self._diameter_machine_variant_material_map[rounded_diameter] - machine_node = machine_variant_material_map.get(machine_definition_id) - variant_node = None + # If there are nozzle materials, get the nozzle-specific material + machine_nozzle_buildplate_material_map = self._diameter_machine_nozzle_buildplate_material_map[rounded_diameter] + machine_node = machine_nozzle_buildplate_material_map.get(machine_definition_id) + nozzle_node = None + buildplate_node = None # Fallback for "fdmprinter" if the machine-specific materials cannot be found if machine_node is None: - machine_node = machine_variant_material_map.get(self._default_machine_definition_id) - if machine_node is not None and extruder_variant_name is not None: - variant_node = machine_node.getChildNode(extruder_variant_name) + machine_node = machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id) + if machine_node is not None and nozzle_name is not None: + nozzle_node = machine_node.getChildNode(nozzle_name) + if nozzle_node is not None and buildplate_name is not None: + buildplate_node = nozzle_node.getChildNode(buildplate_name) # Fallback mechanism of finding materials: - # 1. variant-specific material - # 2. machine-specific material - # 3. generic material (for fdmprinter) - nodes_to_check = [variant_node, machine_node, - machine_variant_material_map.get(self._default_machine_definition_id)] + # 1. buildplate-specific material + # 2. nozzle-specific material + # 3. machine-specific material + # 4. generic material (for fdmprinter) + nodes_to_check = [buildplate_node, nozzle_node, machine_node, + machine_nozzle_buildplate_material_map.get(self._default_machine_definition_id)] material_node = None for node in nodes_to_check: @@ -366,7 +413,8 @@ class MaterialManager(QObject): # 1. the given machine doesn't have materials; # 2. cannot find any material InstanceContainers with the given settings. # - def getMaterialNodeByType(self, global_stack: "GlobalStack", position: str, extruder_variant_name: str, material_guid: str) -> Optional["MaterialNode"]: + def getMaterialNodeByType(self, global_stack: "GlobalStack", position: str, nozzle_name: str, + buildplate_name: Optional[str], material_guid: str) -> Optional["MaterialNode"]: node = None machine_definition = global_stack.definition extruder_definition = global_stack.extruders[position].definition @@ -385,7 +433,7 @@ class MaterialManager(QObject): Logger.log("i", "Cannot find materials with guid [%s] ", material_guid) return None - node = self.getMaterialNode(machine_definition.getId(), extruder_variant_name, + node = self.getMaterialNode(machine_definition.getId(), nozzle_name, buildplate_name, material_diameter, root_material_id) return node @@ -413,13 +461,17 @@ class MaterialManager(QObject): else: return None - ## Get default material for given global stack, extruder position and extruder variant name + ## Get default material for given global stack, extruder position and extruder nozzle name # you can provide the extruder_definition and then the position is ignored (useful when building up global stack in CuraStackBuilder) - def getDefaultMaterial(self, global_stack: "GlobalStack", position: str, extruder_variant_name: Optional[str], extruder_definition: Optional["DefinitionContainer"] = None) -> Optional["MaterialNode"]: + def getDefaultMaterial(self, global_stack: "GlobalStack", position: str, nozzle_name: Optional[str], + extruder_definition: Optional["DefinitionContainer"] = None) -> Optional["MaterialNode"]: node = None + + buildplate_name = global_stack.getBuildplateName() machine_definition = global_stack.definition if extruder_definition is None: extruder_definition = global_stack.extruders[position].definition + if extruder_definition and parseBool(global_stack.getMetaDataEntry("has_materials", False)): # At this point the extruder_definition is not None material_diameter = extruder_definition.getProperty("material_diameter", "value") @@ -428,7 +480,7 @@ class MaterialManager(QObject): approximate_material_diameter = str(round(material_diameter)) root_material_id = machine_definition.getMetaDataEntry("preferred_material") root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_material_diameter) - node = self.getMaterialNode(machine_definition.getId(), extruder_variant_name, + node = self.getMaterialNode(machine_definition.getId(), nozzle_name, buildplate_name, material_diameter, root_material_id) return node @@ -515,8 +567,8 @@ class MaterialManager(QObject): if container_to_copy.getMetaDataEntry("definition") != "fdmprinter": new_id += "_" + container_to_copy.getMetaDataEntry("definition") if container_to_copy.getMetaDataEntry("variant_name"): - variant_name = container_to_copy.getMetaDataEntry("variant_name") - new_id += "_" + variant_name.replace(" ", "_") + nozzle_name = container_to_copy.getMetaDataEntry("variant_name") + new_id += "_" + nozzle_name.replace(" ", "_") new_container = copy.deepcopy(container_to_copy) new_container.getMetaData()["id"] = new_id @@ -565,3 +617,25 @@ class MaterialManager(QObject): new_base_id = new_id, new_metadata = new_metadata) return new_id + + @pyqtSlot(str) + def addFavorite(self, root_material_id: str): + self._favorites.add(root_material_id) + self.favoritesUpdated.emit() + + # Ensure all settings are saved. + self._application.getPreferences().setValue("cura/favorite_materials", ";".join(list(self._favorites))) + self._application.saveSettings() + + @pyqtSlot(str) + def removeFavorite(self, root_material_id: str): + self._favorites.remove(root_material_id) + self.favoritesUpdated.emit() + + # Ensure all settings are saved. + self._application.getPreferences().setValue("cura/favorite_materials", ";".join(list(self._favorites))) + self._application.saveSettings() + + @pyqtSlot() + def getFavorites(self): + return self._favorites \ No newline at end of file diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index 4759c8b5b0..1b20e1188c 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -2,45 +2,63 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty - -from UM.Application import Application from UM.Qt.ListModel import ListModel -# -# This is the base model class for GenericMaterialsModel and BrandMaterialsModel -# Those 2 models are used by the material drop down menu to show generic materials and branded materials separately. -# The extruder position defined here is being used to bound a menu to the correct extruder. This is used in the top -# bar menu "Settings" -> "Extruder nr" -> "Material" -> this menu -# +## This is the base model class for GenericMaterialsModel and MaterialBrandsModel. +# Those 2 models are used by the material drop down menu to show generic materials and branded materials separately. +# The extruder position defined here is being used to bound a menu to the correct extruder. This is used in the top +# bar menu "Settings" -> "Extruder nr" -> "Material" -> this menu class BaseMaterialsModel(ListModel): - RootMaterialIdRole = Qt.UserRole + 1 - IdRole = Qt.UserRole + 2 - NameRole = Qt.UserRole + 3 - BrandRole = Qt.UserRole + 4 - MaterialRole = Qt.UserRole + 5 - ColorRole = Qt.UserRole + 6 - ContainerNodeRole = Qt.UserRole + 7 extruderPositionChanged = pyqtSignal() def __init__(self, parent = None): super().__init__(parent) - self._application = Application.getInstance() - self._machine_manager = self._application.getMachineManager() - self.addRoleName(self.RootMaterialIdRole, "root_material_id") - self.addRoleName(self.IdRole, "id") - self.addRoleName(self.NameRole, "name") - self.addRoleName(self.BrandRole, "brand") - self.addRoleName(self.MaterialRole, "material") - self.addRoleName(self.ColorRole, "color_name") - self.addRoleName(self.ContainerNodeRole, "container_node") + from cura.CuraApplication import CuraApplication + + self._application = CuraApplication.getInstance() + + # Make these managers available to all material models + self._container_registry = self._application.getInstance().getContainerRegistry() + self._machine_manager = self._application.getMachineManager() + self._material_manager = self._application.getMaterialManager() + + # Update the stack and the model data when the machine changes + self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack) + + # Update this model when switching machines + self._machine_manager.activeStackChanged.connect(self._update) + + # Update this model when list of materials changes + self._material_manager.materialsUpdated.connect(self._update) + + # Update this model when list of favorites changes + self._material_manager.favoritesUpdated.connect(self._update) + + self.addRoleName(Qt.UserRole + 1, "root_material_id") + self.addRoleName(Qt.UserRole + 2, "id") + self.addRoleName(Qt.UserRole + 3, "GUID") + self.addRoleName(Qt.UserRole + 4, "name") + self.addRoleName(Qt.UserRole + 5, "brand") + self.addRoleName(Qt.UserRole + 6, "description") + self.addRoleName(Qt.UserRole + 7, "material") + self.addRoleName(Qt.UserRole + 8, "color_name") + self.addRoleName(Qt.UserRole + 9, "color_code") + self.addRoleName(Qt.UserRole + 10, "density") + self.addRoleName(Qt.UserRole + 11, "diameter") + self.addRoleName(Qt.UserRole + 12, "approximate_diameter") + self.addRoleName(Qt.UserRole + 13, "adhesion_info") + self.addRoleName(Qt.UserRole + 14, "is_read_only") + self.addRoleName(Qt.UserRole + 15, "container_node") + self.addRoleName(Qt.UserRole + 16, "is_favorite") self._extruder_position = 0 self._extruder_stack = None - # Update the stack and the model data when the machine changes - self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack) + + self._available_materials = None + self._favorite_ids = None def _updateExtruderStack(self): global_stack = self._machine_manager.activeMachine @@ -65,8 +83,55 @@ class BaseMaterialsModel(ListModel): def extruderPosition(self) -> int: return self._extruder_position - # - # This is an abstract method that needs to be implemented by - # + ## This is an abstract method that needs to be implemented by the specific + # models themselves. def _update(self): pass + + ## This method is used by all material models in the beginning of the + # _update() method in order to prevent errors. It's the same in all models + # so it's placed here for easy access. + def _canUpdate(self): + global_stack = self._machine_manager.activeMachine + + if global_stack is None: + return False + + extruder_position = str(self._extruder_position) + + if extruder_position not in global_stack.extruders: + return False + + extruder_stack = global_stack.extruders[extruder_position] + + self._available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack) + if self._available_materials is None: + return False + + return True + + ## This is another convenience function which is shared by all material + # models so it's put here to avoid having so much duplicated code. + def _createMaterialItem(self, root_material_id, container_node): + metadata = container_node.metadata + item = { + "root_material_id": root_material_id, + "id": metadata["id"], + "container_id": metadata["id"], # TODO: Remove duplicate in material manager qml + "GUID": metadata["GUID"], + "name": metadata["name"], + "brand": metadata["brand"], + "description": metadata["description"], + "material": metadata["material"], + "color_name": metadata["color_name"], + "color_code": metadata.get("color_code", ""), + "density": metadata.get("properties", {}).get("density", ""), + "diameter": metadata.get("properties", {}).get("diameter", ""), + "approximate_diameter": metadata["approximate_diameter"], + "adhesion_info": metadata["adhesion_info"], + "is_read_only": self._container_registry.isReadOnly(metadata["id"]), + "container_node": container_node, + "is_favorite": root_material_id in self._favorite_ids + } + return item + diff --git a/cura/Machines/Models/BrandMaterialsModel.py b/cura/Machines/Models/BrandMaterialsModel.py deleted file mode 100644 index ad48b3ea21..0000000000 --- a/cura/Machines/Models/BrandMaterialsModel.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright (c) 2018 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. - -from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty - -from UM.Qt.ListModel import ListModel -from UM.Logger import Logger -from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel - - -# -# This is an intermediate model to group materials with different colours for a same brand and type. -# -class MaterialsModelGroupedByType(ListModel): - NameRole = Qt.UserRole + 1 - ColorsRole = Qt.UserRole + 2 - - def __init__(self, parent = None): - super().__init__(parent) - - self.addRoleName(self.NameRole, "name") - self.addRoleName(self.ColorsRole, "colors") - - -# -# This model is used to show branded materials in the material drop down menu. -# The structure of the menu looks like this: -# Brand -> Material Type -> list of materials -# -# To illustrate, a branded material menu may look like this: -# Ultimaker -> PLA -> Yellow PLA -# -> Black PLA -# -> ... -# -> ABS -> White ABS -# ... -# -class BrandMaterialsModel(ListModel): - NameRole = Qt.UserRole + 1 - MaterialsRole = Qt.UserRole + 2 - - extruderPositionChanged = pyqtSignal() - - def __init__(self, parent = None): - super().__init__(parent) - - self.addRoleName(self.NameRole, "name") - self.addRoleName(self.MaterialsRole, "materials") - - self._extruder_position = 0 - self._extruder_stack = None - - from cura.CuraApplication import CuraApplication - self._machine_manager = CuraApplication.getInstance().getMachineManager() - self._extruder_manager = CuraApplication.getInstance().getExtruderManager() - self._material_manager = CuraApplication.getInstance().getMaterialManager() - - self._machine_manager.globalContainerChanged.connect(self._updateExtruderStack) - self._machine_manager.activeStackChanged.connect(self._update) #Update when switching machines. - self._material_manager.materialsUpdated.connect(self._update) #Update when the list of materials changes. - self._update() - - def _updateExtruderStack(self): - global_stack = self._machine_manager.activeMachine - if global_stack is None: - return - - if self._extruder_stack is not None: - self._extruder_stack.pyqtContainersChanged.disconnect(self._update) - self._extruder_stack = global_stack.extruders.get(str(self._extruder_position)) - if self._extruder_stack is not None: - self._extruder_stack.pyqtContainersChanged.connect(self._update) - # Force update the model when the extruder stack changes - self._update() - - def setExtruderPosition(self, position: int): - if self._extruder_stack is None or self._extruder_position != position: - self._extruder_position = position - self._updateExtruderStack() - self.extruderPositionChanged.emit() - - @pyqtProperty(int, fset=setExtruderPosition, notify=extruderPositionChanged) - def extruderPosition(self) -> int: - return self._extruder_position - - def _update(self): - Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) - global_stack = self._machine_manager.activeMachine - if global_stack is None: - self.setItems([]) - return - extruder_position = str(self._extruder_position) - if extruder_position not in global_stack.extruders: - self.setItems([]) - return - extruder_stack = global_stack.extruders[str(self._extruder_position)] - - available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, - extruder_stack) - if available_material_dict is None: - self.setItems([]) - return - - brand_item_list = [] - brand_group_dict = {} - for root_material_id, container_node in available_material_dict.items(): - metadata = container_node.metadata - brand = metadata["brand"] - # Only add results for generic materials - if brand.lower() == "generic": - continue - - # Do not include the materials from a to-be-removed package - if bool(metadata.get("removed", False)): - continue - - if brand not in brand_group_dict: - brand_group_dict[brand] = {} - - material_type = metadata["material"] - if material_type not in brand_group_dict[brand]: - brand_group_dict[brand][material_type] = [] - - item = {"root_material_id": root_material_id, - "id": metadata["id"], - "name": metadata["name"], - "brand": metadata["brand"], - "material": metadata["material"], - "color_name": metadata["color_name"], - "container_node": container_node - } - brand_group_dict[brand][material_type].append(item) - - for brand, material_dict in brand_group_dict.items(): - brand_item = {"name": brand, - "materials": MaterialsModelGroupedByType(self)} - - material_type_item_list = [] - for material_type, material_list in material_dict.items(): - material_type_item = {"name": material_type, - "colors": BaseMaterialsModel(self)} - material_type_item["colors"].clear() - - # Sort materials by name - material_list = sorted(material_list, key = lambda x: x["name"].upper()) - material_type_item["colors"].setItems(material_list) - - material_type_item_list.append(material_type_item) - - # Sort material type by name - material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper()) - brand_item["materials"].setItems(material_type_item_list) - - brand_item_list.append(brand_item) - - # Sort brand by name - brand_item_list = sorted(brand_item_list, key = lambda x: x["name"].upper()) - self.setItems(brand_item_list) diff --git a/cura/Machines/Models/BuildPlateModel.py b/cura/Machines/Models/BuildPlateModel.py index e1b4f40d8e..82b9db4d64 100644 --- a/cura/Machines/Models/BuildPlateModel.py +++ b/cura/Machines/Models/BuildPlateModel.py @@ -8,7 +8,7 @@ from UM.Logger import Logger from UM.Qt.ListModel import ListModel from UM.Util import parseBool -from cura.Machines.VariantManager import VariantType +from cura.Machines.VariantType import VariantType class BuildPlateModel(ListModel): diff --git a/cura/Machines/Models/FavoriteMaterialsModel.py b/cura/Machines/Models/FavoriteMaterialsModel.py new file mode 100644 index 0000000000..be3f0f605f --- /dev/null +++ b/cura/Machines/Models/FavoriteMaterialsModel.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from UM.Logger import Logger +from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel + +class FavoriteMaterialsModel(BaseMaterialsModel): + + def __init__(self, parent = None): + super().__init__(parent) + self._update() + + def _update(self): + + # Perform standard check and reset if the check fails + if not self._canUpdate(): + self.setItems([]) + return + + # Get updated list of favorites + self._favorite_ids = self._material_manager.getFavorites() + + item_list = [] + + for root_material_id, container_node in self._available_materials.items(): + metadata = container_node.metadata + + # Do not include the materials from a to-be-removed package + if bool(metadata.get("removed", False)): + continue + + # Only add results for favorite materials + if root_material_id not in self._favorite_ids: + continue + + item = self._createMaterialItem(root_material_id, container_node) + item_list.append(item) + + # Sort the item list alphabetically by name + item_list = sorted(item_list, key = lambda d: d["brand"].upper()) + + self.setItems(item_list) diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index f14b039c91..27e6fdfd7c 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -4,63 +4,39 @@ from UM.Logger import Logger from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel - class GenericMaterialsModel(BaseMaterialsModel): def __init__(self, parent = None): super().__init__(parent) - - from cura.CuraApplication import CuraApplication - self._machine_manager = CuraApplication.getInstance().getMachineManager() - self._extruder_manager = CuraApplication.getInstance().getExtruderManager() - self._material_manager = CuraApplication.getInstance().getMaterialManager() - - self._machine_manager.activeStackChanged.connect(self._update) #Update when switching machines. - self._material_manager.materialsUpdated.connect(self._update) #Update when the list of materials changes. self._update() def _update(self): - Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) - global_stack = self._machine_manager.activeMachine - if global_stack is None: + # Perform standard check and reset if the check fails + if not self._canUpdate(): self.setItems([]) return - extruder_position = str(self._extruder_position) - if extruder_position not in global_stack.extruders: - self.setItems([]) - return - extruder_stack = global_stack.extruders[extruder_position] - available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, - extruder_stack) - if available_material_dict is None: - self.setItems([]) - return + # Get updated list of favorites + self._favorite_ids = self._material_manager.getFavorites() item_list = [] - for root_material_id, container_node in available_material_dict.items(): - metadata = container_node.metadata - # Only add results for generic materials - if metadata["brand"].lower() != "generic": - continue + for root_material_id, container_node in self._available_materials.items(): + metadata = container_node.metadata # Do not include the materials from a to-be-removed package if bool(metadata.get("removed", False)): continue - item = {"root_material_id": root_material_id, - "id": metadata["id"], - "name": metadata["name"], - "brand": metadata["brand"], - "material": metadata["material"], - "color_name": metadata["color_name"], - "container_node": container_node - } + # Only add results for generic materials + if metadata["brand"].lower() != "generic": + continue + + item = self._createMaterialItem(root_material_id, container_node) item_list.append(item) - # Sort the item list by material name alphabetically + # Sort the item list alphabetically by name item_list = sorted(item_list, key = lambda d: d["name"].upper()) self.setItems(item_list) diff --git a/cura/Machines/Models/MaterialBrandsModel.py b/cura/Machines/Models/MaterialBrandsModel.py new file mode 100644 index 0000000000..3f917abb16 --- /dev/null +++ b/cura/Machines/Models/MaterialBrandsModel.py @@ -0,0 +1,107 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty +from UM.Qt.ListModel import ListModel +from UM.Logger import Logger +from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel + +class MaterialTypesModel(ListModel): + + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(Qt.UserRole + 1, "name") + self.addRoleName(Qt.UserRole + 2, "colors") + +class MaterialBrandsModel(BaseMaterialsModel): + + extruderPositionChanged = pyqtSignal() + + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(Qt.UserRole + 1, "name") + self.addRoleName(Qt.UserRole + 2, "material_types") + + self._update() + + def _update(self): + + # Perform standard check and reset if the check fails + if not self._canUpdate(): + self.setItems([]) + return + + # Get updated list of favorites + self._favorite_ids = self._material_manager.getFavorites() + + brand_item_list = [] + brand_group_dict = {} + + # Part 1: Generate the entire tree of brands -> material types -> spcific materials + for root_material_id, container_node in self._available_materials.items(): + metadata = container_node.metadata + + # Do not include the materials from a to-be-removed package + if bool(metadata.get("removed", False)): + continue + + # Add brands we haven't seen yet to the dict, skipping generics + brand = metadata["brand"] + if brand.lower() == "generic": + continue + if brand not in brand_group_dict: + brand_group_dict[brand] = {} + + # Add material types we haven't seen yet to the dict + material_type = metadata["material"] + if material_type not in brand_group_dict[brand]: + brand_group_dict[brand][material_type] = [] + + # Now handle the individual materials + item = self._createMaterialItem(root_material_id, container_node) + brand_group_dict[brand][material_type].append(item) + + # Part 2: Organize the tree into models + # + # Normally, the structure of the menu looks like this: + # Brand -> Material Type -> Specific Material + # + # To illustrate, a branded material menu may look like this: + # Ultimaker ┳ PLA ┳ Yellow PLA + # ┃ ┣ Black PLA + # ┃ ┗ ... + # ┃ + # ┗ ABS ┳ White ABS + # ┗ ... + for brand, material_dict in brand_group_dict.items(): + + material_type_item_list = [] + brand_item = { + "name": brand, + "material_types": MaterialTypesModel(self) + } + + for material_type, material_list in material_dict.items(): + material_type_item = { + "name": material_type, + "colors": BaseMaterialsModel(self) + } + material_type_item["colors"].clear() + + # Sort materials by name + material_list = sorted(material_list, key = lambda x: x["name"].upper()) + material_type_item["colors"].setItems(material_list) + + material_type_item_list.append(material_type_item) + + # Sort material type by name + material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper()) + brand_item["material_types"].setItems(material_type_item_list) + + brand_item_list.append(brand_item) + + # Sort brand by name + brand_item_list = sorted(brand_item_list, key = lambda x: x["name"].upper()) + self.setItems(brand_item_list) diff --git a/cura/Machines/Models/MaterialManagementModel.py b/cura/Machines/Models/MaterialManagementModel.py deleted file mode 100644 index 46e9cb887a..0000000000 --- a/cura/Machines/Models/MaterialManagementModel.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright (c) 2018 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. - -from PyQt5.QtCore import Qt - -from UM.Logger import Logger -from UM.Qt.ListModel import ListModel - - -# -# This model is for the Material management page. -# -class MaterialManagementModel(ListModel): - RootMaterialIdRole = Qt.UserRole + 1 - DisplayNameRole = Qt.UserRole + 2 - BrandRole = Qt.UserRole + 3 - MaterialTypeRole = Qt.UserRole + 4 - ColorNameRole = Qt.UserRole + 5 - ColorCodeRole = Qt.UserRole + 6 - ContainerNodeRole = Qt.UserRole + 7 - ContainerIdRole = Qt.UserRole + 8 - - DescriptionRole = Qt.UserRole + 9 - AdhesionInfoRole = Qt.UserRole + 10 - ApproximateDiameterRole = Qt.UserRole + 11 - GuidRole = Qt.UserRole + 12 - DensityRole = Qt.UserRole + 13 - DiameterRole = Qt.UserRole + 14 - IsReadOnlyRole = Qt.UserRole + 15 - - def __init__(self, parent = None): - super().__init__(parent) - - self.addRoleName(self.RootMaterialIdRole, "root_material_id") - self.addRoleName(self.DisplayNameRole, "name") - self.addRoleName(self.BrandRole, "brand") - self.addRoleName(self.MaterialTypeRole, "material") - self.addRoleName(self.ColorNameRole, "color_name") - self.addRoleName(self.ColorCodeRole, "color_code") - self.addRoleName(self.ContainerNodeRole, "container_node") - self.addRoleName(self.ContainerIdRole, "container_id") - - self.addRoleName(self.DescriptionRole, "description") - self.addRoleName(self.AdhesionInfoRole, "adhesion_info") - self.addRoleName(self.ApproximateDiameterRole, "approximate_diameter") - self.addRoleName(self.GuidRole, "guid") - self.addRoleName(self.DensityRole, "density") - self.addRoleName(self.DiameterRole, "diameter") - self.addRoleName(self.IsReadOnlyRole, "is_read_only") - - from cura.CuraApplication import CuraApplication - self._container_registry = CuraApplication.getInstance().getContainerRegistry() - self._machine_manager = CuraApplication.getInstance().getMachineManager() - self._extruder_manager = CuraApplication.getInstance().getExtruderManager() - self._material_manager = CuraApplication.getInstance().getMaterialManager() - - self._machine_manager.globalContainerChanged.connect(self._update) - self._extruder_manager.activeExtruderChanged.connect(self._update) - self._material_manager.materialsUpdated.connect(self._update) - - self._update() - - def _update(self): - Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) - - global_stack = self._machine_manager.activeMachine - if global_stack is None: - self.setItems([]) - return - active_extruder_stack = self._machine_manager.activeStack - - available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, - active_extruder_stack) - if available_material_dict is None: - self.setItems([]) - return - - material_list = [] - for root_material_id, container_node in available_material_dict.items(): - keys_to_fetch = ("name", - "brand", - "material", - "color_name", - "color_code", - "description", - "adhesion_info", - "approximate_diameter",) - - item = {"root_material_id": container_node.metadata["base_file"], - "container_node": container_node, - "guid": container_node.metadata["GUID"], - "container_id": container_node.metadata["id"], - "density": container_node.metadata.get("properties", {}).get("density", ""), - "diameter": container_node.metadata.get("properties", {}).get("diameter", ""), - "is_read_only": self._container_registry.isReadOnly(container_node.metadata["id"]), - } - - for key in keys_to_fetch: - item[key] = container_node.metadata.get(key, "") - - material_list.append(item) - - material_list = sorted(material_list, key = lambda k: (k["brand"].upper(), k["name"].upper())) - self.setItems(material_list) diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index 0879998b7d..9d97106d6b 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -8,6 +8,8 @@ from UM.Logger import Logger from UM.Qt.ListModel import ListModel from UM.Util import parseBool +from cura.Machines.VariantType import VariantType + class NozzleModel(ListModel): IdRole = Qt.UserRole + 1 @@ -43,7 +45,6 @@ class NozzleModel(ListModel): self.setItems([]) return - from cura.Machines.VariantManager import VariantType variant_node_dict = self._variant_manager.getVariantNodes(global_stack, VariantType.NOZZLE) if not variant_node_dict: self.setItems([]) diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index 82a11f9960..cb2776429f 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -45,7 +45,7 @@ class QualityManager(QObject): self._empty_quality_container = self._application.empty_quality_container self._empty_quality_changes_container = self._application.empty_quality_changes_container - self._machine_variant_material_quality_type_to_quality_dict = {} # for quality lookup + self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # for quality lookup self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup self._default_machine_definition_id = "fdmprinter" @@ -64,10 +64,10 @@ class QualityManager(QObject): def initialize(self): # Initialize the lookup tree for quality profiles with following structure: - # -> -> - # -> + # -> -> -> + # -> - self._machine_variant_material_quality_type_to_quality_dict = {} # for quality lookup + self._machine_nozzle_buildplate_material_quality_type_to_quality_dict = {} # for quality lookup self._machine_quality_type_to_quality_changes_dict = {} # for quality_changes lookup quality_metadata_list = self._container_registry.findContainersMetadata(type = "quality") @@ -79,53 +79,41 @@ class QualityManager(QObject): quality_type = metadata["quality_type"] root_material_id = metadata.get("material") - variant_name = metadata.get("variant") + nozzle_name = metadata.get("variant") + buildplate_name = metadata.get("buildplate") is_global_quality = metadata.get("global_quality", False) - is_global_quality = is_global_quality or (root_material_id is None and variant_name is None) + is_global_quality = is_global_quality or (root_material_id is None and nozzle_name is None and buildplate_name is None) # Sanity check: material+variant and is_global_quality cannot be present at the same time - if is_global_quality and (root_material_id or variant_name): + if is_global_quality and (root_material_id or nozzle_name): ConfigurationErrorMessage.getInstance().addFaultyContainers(metadata["id"]) continue - 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() - machine_node = cast(QualityNode, self._machine_variant_material_quality_type_to_quality_dict[definition_id]) + if definition_id not in self._machine_nozzle_buildplate_material_quality_type_to_quality_dict: + self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[definition_id] = QualityNode() + machine_node = cast(QualityNode, self._machine_nozzle_buildplate_material_quality_type_to_quality_dict[definition_id]) if is_global_quality: # For global qualities, save data in the machine node machine_node.addQualityMetadata(quality_type, metadata) continue - if variant_name is not None: - # If variant_name is specified in the quality/quality_changes profile, check if material is specified, - # too. - if variant_name not in machine_node.children_map: - machine_node.children_map[variant_name] = QualityNode() - variant_node = cast(QualityNode, machine_node.children_map[variant_name]) + current_node = machine_node + intermediate_node_info_list = [nozzle_name, buildplate_name, root_material_id] + current_intermediate_node_info_idx = 0 - if root_material_id is None: - # If only variant_name is specified but material is not, add the quality/quality_changes metadata - # into the current variant node. - variant_node.addQualityMetadata(quality_type, metadata) - else: - # If only variant_name and material are both specified, go one level deeper: create a material node - # under the current variant node, and then add the quality/quality_changes metadata into the - # material node. - if root_material_id not in variant_node.children_map: - variant_node.children_map[root_material_id] = QualityNode() - material_node = cast(QualityNode, variant_node.children_map[root_material_id]) + while current_intermediate_node_info_idx < len(intermediate_node_info_list): + node_name = intermediate_node_info_list[current_intermediate_node_info_idx] + if node_name is not None: + # There is specific information, update the current node to go deeper so we can add this quality + # at the most specific branch in the lookup tree. + if node_name not in current_node.children_map: + current_node.children_map[node_name] = QualityNode() + current_node = cast(QualityNode, current_node.children_map[node_name]) - material_node.addQualityMetadata(quality_type, metadata) + current_intermediate_node_info_idx += 1 - else: - # If variant_name is not specified, check if material is specified. - if root_material_id is not None: - if root_material_id not in machine_node.children_map: - machine_node.children_map[root_material_id] = QualityNode() - material_node = cast(QualityNode, machine_node.children_map[root_material_id]) - - material_node.addQualityMetadata(quality_type, metadata) + current_node.addQualityMetadata(quality_type, metadata) # Initialize the lookup tree for quality_changes profiles with following structure: # -> -> @@ -217,8 +205,8 @@ class QualityManager(QObject): # To find the quality container for the GlobalStack, check in the following fall-back manner: # (1) the machine-specific node # (2) the generic node - machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(machine_definition_id) - default_machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(self._default_machine_definition_id) + machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(machine_definition_id) + default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(self._default_machine_definition_id) nodes_to_check = [machine_node, default_machine_node] # Iterate over all quality_types in the machine node @@ -238,16 +226,19 @@ class QualityManager(QObject): quality_group_dict[quality_type] = quality_group break + buildplate_name = machine.getBuildplateName() + # Iterate over all extruders to find quality containers for each extruder for position, extruder in machine.extruders.items(): - variant_name = None + nozzle_name = None if extruder.variant.getId() != "empty_variant": - variant_name = extruder.variant.getName() + nozzle_name = extruder.variant.getName() # This is a list of root material IDs to use for searching for suitable quality profiles. # The root material IDs in this list are in prioritized order. root_material_id_list = [] has_material = False # flag indicating whether this extruder has a material assigned + root_material_id = None if extruder.material.getId() != "empty_material": has_material = True root_material_id = extruder.material.getMetaDataEntry("base_file") @@ -264,36 +255,51 @@ class QualityManager(QObject): # Here we construct a list of nodes we want to look for qualities with the highest priority first. # The use case is that, when we look for qualities for a machine, we first want to search in the following # order: - # 1. machine-variant-and-material-specific qualities if exist - # 2. machine-variant-specific qualities if exist - # 3. machine-material-specific qualities if exist - # 4. machine-specific qualities if exist - # 5. generic qualities if exist + # 1. machine-nozzle-buildplate-and-material-specific qualities if exist + # 2. machine-nozzle-and-material-specific qualities if exist + # 3. machine-nozzle-specific qualities if exist + # 4. machine-material-specific qualities if exist + # 5. machine-specific global qualities if exist, otherwise generic global qualities + # NOTE: We DO NOT fail back to generic global qualities if machine-specific global qualities exist. + # This is because when a machine defines its own global qualities such as Normal, Fine, etc., + # it is intended to maintain those specific qualities ONLY. If we still fail back to the generic + # global qualities, there can be unimplemented quality types e.g. "coarse", and this is not + # correct. # Each points above can be represented as a node in the lookup tree, so here we simply put those nodes into # the list with priorities as the order. Later, we just need to loop over each node in this list and fetch # qualities from there. + node_info_list_0 = [nozzle_name, buildplate_name, root_material_id] nodes_to_check = [] - if variant_name: - # In this case, we have both a specific variant and a specific material - variant_node = machine_node.getChildNode(variant_name) - if variant_node and has_material: - for root_material_id in root_material_id_list: - material_node = variant_node.getChildNode(root_material_id) + # This function tries to recursively find the deepest (the most specific) branch and add those nodes to + # the search list in the order described above. So, by iterating over that search node list, we first look + # in the more specific branches and then the less specific (generic) ones. + def addNodesToCheck(node, nodes_to_check_list, node_info_list, node_info_idx): + if node_info_idx < len(node_info_list): + node_name = node_info_list[node_info_idx] + if node_name is not None: + current_node = node.getChildNode(node_name) + if current_node is not None and has_material: + addNodesToCheck(current_node, nodes_to_check_list, node_info_list, node_info_idx + 1) + + if has_material: + for rmid in root_material_id_list: + material_node = node.getChildNode(rmid) if material_node: - nodes_to_check.append(material_node) + nodes_to_check_list.append(material_node) break - nodes_to_check.append(variant_node) - # In this case, we only have a specific material but NOT a variant - if has_material: - for root_material_id in root_material_id_list: - material_node = machine_node.getChildNode(root_material_id) - if material_node: - nodes_to_check.append(material_node) - break + nodes_to_check_list.append(node) + + addNodesToCheck(machine_node, nodes_to_check, node_info_list_0, 0) + + # The last fall back will be the global qualities (either from the machine-specific node or the generic + # node), but we only use one. For details see the overview comments above. + if machine_node.quality_type_map: + nodes_to_check += [machine_node] + else: + nodes_to_check += [default_machine_node] - nodes_to_check += [machine_node, default_machine_node] for node in nodes_to_check: if node and node.quality_type_map: if has_variant_materials: @@ -309,8 +315,8 @@ class QualityManager(QObject): quality_group_dict[quality_type] = quality_group quality_group = quality_group_dict[quality_type] - quality_group.nodes_for_extruders[position] = quality_node - break + if position not in quality_group.nodes_for_extruders: + quality_group.nodes_for_extruders[position] = quality_node # Update availabilities for each quality group self._updateQualityGroupsAvailability(machine, quality_group_dict.values()) @@ -323,8 +329,8 @@ class QualityManager(QObject): # To find the quality container for the GlobalStack, check in the following fall-back manner: # (1) the machine-specific node # (2) the generic node - machine_node = self._machine_variant_material_quality_type_to_quality_dict.get(machine_definition_id) - default_machine_node = self._machine_variant_material_quality_type_to_quality_dict.get( + machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get(machine_definition_id) + default_machine_node = self._machine_nozzle_buildplate_material_quality_type_to_quality_dict.get( self._default_machine_definition_id) nodes_to_check = [machine_node, default_machine_node] diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index 036c79d6c7..969fed670e 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -1,7 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from enum import Enum from collections import OrderedDict from typing import Optional, TYPE_CHECKING @@ -11,20 +10,13 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Util import parseBool from cura.Machines.ContainerNode import ContainerNode +from cura.Machines.VariantType import VariantType, ALL_VARIANT_TYPES from cura.Settings.GlobalStack import GlobalStack if TYPE_CHECKING: from UM.Settings.DefinitionContainer import DefinitionContainer -class VariantType(Enum): - BUILD_PLATE = "buildplate" - NOZZLE = "nozzle" - - -ALL_VARIANT_TYPES = (VariantType.BUILD_PLATE, VariantType.NOZZLE) - - # # VariantManager is THE place to look for a specific variant. It maintains two variant lookup tables with the following # structure: diff --git a/cura/Machines/VariantType.py b/cura/Machines/VariantType.py new file mode 100644 index 0000000000..82bb86d7d9 --- /dev/null +++ b/cura/Machines/VariantType.py @@ -0,0 +1,15 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from enum import Enum + + +class VariantType(Enum): + BUILD_PLATE = "buildplate" + NOZZLE = "nozzle" + + +ALL_VARIANT_TYPES = (VariantType.BUILD_PLATE, VariantType.NOZZLE) + + +__all__ = ["VariantType", "ALL_VARIANT_TYPES"] diff --git a/cura/OneAtATimeIterator.py b/cura/OneAtATimeIterator.py index 84d65bae8e..a08f3ed2bf 100644 --- a/cura/OneAtATimeIterator.py +++ b/cura/OneAtATimeIterator.py @@ -1,112 +1,149 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from UM.Scene.Iterator import Iterator -from UM.Scene.SceneNode import SceneNode -from functools import cmp_to_key -from UM.Application import Application +import sys + +from shapely import affinity +from shapely.geometry import Polygon + +from UM.Scene.Iterator.Iterator import Iterator +from UM.Scene.SceneNode import SceneNode + + +# Iterator that determines the object print order when one-at a time mode is enabled. +# +# In one-at-a-time mode, only one extruder can be enabled to print. In order to maximize the number of objects we can +# print, we need to print from the corner that's closest to the extruder that's being used. Here is an illustration: +# +# +--------------------------------+ +# | | +# | | +# | | - Rectangle represents the complete print head including fans, etc. +# | X X | y - X's are the nozzles +# | (1) (2) | ^ +# | | | +# +--------------------------------+ +--> x +# +# In this case, the nozzles are symmetric, nozzle (1) is closer to the bottom left corner while (2) is closer to the +# bottom right. If we use nozzle (1) to print, then we better off printing from the bottom left corner so the print +# head will not collide into an object on its top-right side, which is a very large unused area. Following the same +# logic, if we are printing with nozzle (2), then it's better to print from the bottom-right side. +# +# This iterator determines the print order following the rules above. +# +class OneAtATimeIterator(Iterator): -## Iterator that returns a list of nodes in the order that they need to be printed -# If there is no solution an empty list is returned. -# Take note that the list of nodes can have children (that may or may not contain mesh data) -class OneAtATimeIterator(Iterator.Iterator): def __init__(self, scene_node): - super().__init__(scene_node) # Call super to make multiple inheritence work. - self._hit_map = [[]] + from cura.CuraApplication import CuraApplication + self._global_stack = CuraApplication.getInstance().getGlobalContainerStack() self._original_node_list = [] - + + super().__init__(scene_node) # Call super to make multiple inheritance work. + + def getMachineNearestCornerToExtruder(self, global_stack): + head_and_fans_coordinates = global_stack.getHeadAndFansCoordinates() + + used_extruder = None + for extruder in global_stack.extruders.values(): + if extruder.isEnabled: + used_extruder = extruder + break + + extruder_offsets = [used_extruder.getProperty("machine_nozzle_offset_x", "value"), + used_extruder.getProperty("machine_nozzle_offset_y", "value")] + + # find the corner that's closest to the origin + min_distance2 = sys.maxsize + min_coord = None + for coord in head_and_fans_coordinates: + x = coord[0] - extruder_offsets[0] + y = coord[1] - extruder_offsets[1] + + distance2 = x**2 + y**2 + if distance2 <= min_distance2: + min_distance2 = distance2 + min_coord = coord + + return min_coord + + def _checkForCollisions(self) -> bool: + all_nodes = [] + for node in self._scene_node.getChildren(): + if not issubclass(type(node), SceneNode): + continue + convex_hull = node.callDecoration("getConvexHullHead") + if not convex_hull: + continue + + bounding_box = node.getBoundingBox() + if not bounding_box: + continue + from UM.Math.Polygon import Polygon + bounding_box_polygon = Polygon([[bounding_box.left, bounding_box.front], + [bounding_box.left, bounding_box.back], + [bounding_box.right, bounding_box.back], + [bounding_box.right, bounding_box.front]]) + + all_nodes.append({"node": node, + "bounding_box": bounding_box_polygon, + "convex_hull": convex_hull}) + + has_collisions = False + for i, node_dict in enumerate(all_nodes): + for j, other_node_dict in enumerate(all_nodes): + if i == j: + continue + if node_dict["bounding_box"].intersectsPolygon(other_node_dict["convex_hull"]): + has_collisions = True + break + + if has_collisions: + break + + return has_collisions + def _fillStack(self): + min_coord = self.getMachineNearestCornerToExtruder(self._global_stack) + transform_x = -int(round(min_coord[0] / abs(min_coord[0]))) + transform_y = -int(round(min_coord[1] / abs(min_coord[1]))) + + machine_size = [self._global_stack.getProperty("machine_width", "value"), + self._global_stack.getProperty("machine_depth", "value")] + + def flip_x(polygon): + tm2 = [-1, 0, 0, 1, 0, 0] + return affinity.affine_transform(affinity.translate(polygon, xoff = -machine_size[0]), tm2) + + def flip_y(polygon): + tm2 = [1, 0, 0, -1, 0, 0] + return affinity.affine_transform(affinity.translate(polygon, yoff = -machine_size[1]), tm2) + + if self._checkForCollisions(): + self._node_stack = [] + return + node_list = [] for node in self._scene_node.getChildren(): if not issubclass(type(node), SceneNode): continue - if node.callDecoration("getConvexHull"): - node_list.append(node) + convex_hull = node.callDecoration("getConvexHull") + if convex_hull: + xmin = min(x for x, _ in convex_hull._points) + xmax = max(x for x, _ in convex_hull._points) + ymin = min(y for _, y in convex_hull._points) + ymax = max(y for _, y in convex_hull._points) + convex_hull_polygon = Polygon.from_bounds(xmin, ymin, xmax, ymax) + if transform_x < 0: + convex_hull_polygon = flip_x(convex_hull_polygon) + if transform_y < 0: + convex_hull_polygon = flip_y(convex_hull_polygon) - if len(node_list) < 2: - self._node_stack = node_list[:] - return + node_list.append({"node": node, + "min_coord": [convex_hull_polygon.bounds[0], convex_hull_polygon.bounds[1]], + }) - # Copy the list - self._original_node_list = node_list[:] - - ## Initialise the hit map (pre-compute all hits between all objects) - self._hit_map = [[self._checkHit(i,j) for i in node_list] for j in node_list] - - # Check if we have to files that block eachother. If this is the case, there is no solution! - for a in range(0,len(node_list)): - for b in range(0,len(node_list)): - if a != b and self._hit_map[a][b] and self._hit_map[b][a]: - return - - # Sort the original list so that items that block the most other objects are at the beginning. - # This does not decrease the worst case running time, but should improve it in most cases. - sorted(node_list, key = cmp_to_key(self._calculateScore)) - - todo_node_list = [_ObjectOrder([], node_list)] - while len(todo_node_list) > 0: - current = todo_node_list.pop() - for node in current.todo: - # Check if the object can be placed with what we have and still allows for a solution in the future - if not self._checkHitMultiple(node, current.order) and not self._checkBlockMultiple(node, current.todo): - # We found a possible result. Create new todo & order list. - new_todo_list = current.todo[:] - new_todo_list.remove(node) - new_order = current.order[:] + [node] - if len(new_todo_list) == 0: - # We have no more nodes to check, so quit looking. - todo_node_list = None - self._node_stack = new_order - - return - todo_node_list.append(_ObjectOrder(new_order, new_todo_list)) - self._node_stack = [] #No result found! - - - # Check if first object can be printed before the provided list (using the hit map) - def _checkHitMultiple(self, node, other_nodes): - node_index = self._original_node_list.index(node) - for other_node in other_nodes: - other_node_index = self._original_node_list.index(other_node) - if self._hit_map[node_index][other_node_index]: - return True - return False - - def _checkBlockMultiple(self, node, other_nodes): - node_index = self._original_node_list.index(node) - for other_node in other_nodes: - other_node_index = self._original_node_list.index(other_node) - if self._hit_map[other_node_index][node_index] and node_index != other_node_index: - return True - return False - - ## Calculate score simply sums the number of other objects it 'blocks' - def _calculateScore(self, a, b): - score_a = sum(self._hit_map[self._original_node_list.index(a)]) - score_b = sum(self._hit_map[self._original_node_list.index(b)]) - return score_a - score_b - - # Checks if A can be printed before B - def _checkHit(self, a, b): - if a == b: - return False - - overlap = a.callDecoration("getConvexHullBoundary").intersectsPolygon(b.callDecoration("getConvexHullHeadFull")) - if overlap: - return True - else: - return False - - -## Internal object used to keep track of a possible order in which to print objects. -class _ObjectOrder(): - def __init__(self, order, todo): - """ - :param order: List of indexes in which to print objects, ordered by printing order. - :param todo: List of indexes which are not yet inserted into the order list. - """ - self.order = order - self.todo = todo + node_list = sorted(node_list, key = lambda d: d["min_coord"]) + self._node_stack = [d["node"] for d in node_list] diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 1b8ba575db..8527da1b8a 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -267,6 +267,7 @@ class PrintInformation(QObject): new_active_build_plate = self._multi_build_plate_model.activeBuildPlate if new_active_build_plate != self._active_build_plate: self._active_build_plate = new_active_build_plate + self._updateJobName() self._initVariablesWithBuildPlate(self._active_build_plate) @@ -299,7 +300,7 @@ class PrintInformation(QObject): def _updateJobName(self): if self._base_name == "": - self._job_name = "unnamed" + self._job_name = "Untitled" self._is_user_specified_job_name = False self.jobNameChanged.emit() return @@ -320,6 +321,15 @@ class PrintInformation(QObject): else: self._job_name = base_name + # In case there are several buildplates, a suffix is attached + if self._multi_build_plate_model.maxBuildPlate > 0: + connector = "_#" + suffix = connector + str(self._active_build_plate + 1) + if connector in self._job_name: + self._job_name = self._job_name.split(connector)[0] # get the real name + if self._active_build_plate != 0: + self._job_name += suffix + self.jobNameChanged.emit() @pyqtSlot(str) @@ -369,8 +379,9 @@ class PrintInformation(QObject): def baseName(self): return self._base_name - ## Created an acronymn-like abbreviated machine name from the currently active machine name - # Called each time the global stack is switched + ## Created an acronym-like abbreviated machine name from the currently + # active machine name. + # Called each time the global stack is switched. def _setAbbreviatedMachineName(self): global_container_stack = self._application.getGlobalContainerStack() if not global_container_stack: diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 6fafa368bb..f10d6bd75b 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -120,7 +120,7 @@ class PrinterOutputModel(QObject): @pyqtProperty(QVariant, notify = headPositionChanged) def headPosition(self): - return {"x": self._head_position.x, "y": self._head_position.y, "z": self.head_position_z} + return {"x": self._head_position.x, "y": self._head_position.y, "z": self.head_position.z} def updateHeadPosition(self, x, y, z): if self._head_position.x != x or self._head_position.y != y or self._head_position.z != z: diff --git a/cura/Scene/ConvexHullDecorator.py b/cura/Scene/ConvexHullDecorator.py index 66bc8a7fc3..367144abfc 100644 --- a/cura/Scene/ConvexHullDecorator.py +++ b/cura/Scene/ConvexHullDecorator.py @@ -229,7 +229,7 @@ class ConvexHullDecorator(SceneNodeDecorator): return offset_hull def _getHeadAndFans(self): - return Polygon(numpy.array(self._global_stack.getProperty("machine_head_with_fans_polygon", "value"), numpy.float32)) + return Polygon(numpy.array(self._global_stack.getHeadAndFansCoordinates(), numpy.float32)) def _compute2DConvexHeadFull(self): return self._compute2DConvexHull().getMinkowskiHull(self._getHeadAndFans()) diff --git a/cura/Settings/CuraContainerStack.py b/cura/Settings/CuraContainerStack.py index bd3380dfb2..c8d1d9e370 100755 --- a/cura/Settings/CuraContainerStack.py +++ b/cura/Settings/CuraContainerStack.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Any, cast, List, Optional, Union +from typing import Any, cast, List, Optional from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject from UM.Application import Application @@ -13,6 +13,7 @@ from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.DefinitionContainer import DefinitionContainer from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.Interfaces import ContainerInterface, DefinitionContainerInterface +from cura.Settings import cura_empty_instance_containers from . import Exceptions @@ -39,14 +40,12 @@ class CuraContainerStack(ContainerStack): def __init__(self, container_id: str) -> None: super().__init__(container_id) - self._container_registry = ContainerRegistry.getInstance() #type: ContainerRegistry + self._empty_instance_container = cura_empty_instance_containers.empty_container #type: InstanceContainer - self._empty_instance_container = self._container_registry.getEmptyInstanceContainer() #type: InstanceContainer - - self._empty_quality_changes = self._container_registry.findInstanceContainers(id = "empty_quality_changes")[0] #type: InstanceContainer - self._empty_quality = self._container_registry.findInstanceContainers(id = "empty_quality")[0] #type: InstanceContainer - self._empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0] #type: InstanceContainer - self._empty_variant = self._container_registry.findInstanceContainers(id = "empty_variant")[0] #type: InstanceContainer + self._empty_quality_changes = cura_empty_instance_containers.empty_quality_changes_container #type: InstanceContainer + self._empty_quality = cura_empty_instance_containers.empty_quality_container #type: InstanceContainer + self._empty_material = cura_empty_instance_containers.empty_material_container #type: InstanceContainer + self._empty_variant = cura_empty_instance_containers.empty_variant_container #type: InstanceContainer self._containers = [self._empty_instance_container for i in range(len(_ContainerIndexes.IndexTypeMap))] #type: List[ContainerInterface] self._containers[_ContainerIndexes.QualityChanges] = self._empty_quality_changes diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 841d45ed31..12fe732e3e 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -8,7 +8,7 @@ from UM.Logger import Logger from UM.Settings.Interfaces import DefinitionContainerInterface from UM.Settings.InstanceContainer import InstanceContainer -from cura.Machines.VariantManager import VariantType +from cura.Machines.VariantType import VariantType from .GlobalStack import GlobalStack from .ExtruderStack import ExtruderStack @@ -108,16 +108,27 @@ class CuraStackBuilder: preferred_quality_type = machine_definition.getMetaDataEntry("preferred_quality_type") quality_group_dict = quality_manager.getQualityGroups(new_global_stack) - quality_group = quality_group_dict.get(preferred_quality_type) - - new_global_stack.quality = quality_group.node_for_global.getContainer() - if not new_global_stack.quality: + if not quality_group_dict: + # There is no available quality group, set all quality containers to empty. new_global_stack.quality = application.empty_quality_container - for position, extruder_stack in new_global_stack.extruders.items(): - if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[position].getContainer(): - extruder_stack.quality = quality_group.nodes_for_extruders[position].getContainer() - else: + for extruder_stack in new_global_stack.extruders.values(): extruder_stack.quality = application.empty_quality_container + else: + # Set the quality containers to the preferred quality type if available, otherwise use the first quality + # type that's available. + if preferred_quality_type not in quality_group_dict: + Logger.log("w", "The preferred quality {quality_type} doesn't exist for this set-up. Choosing a random one.".format(quality_type = preferred_quality_type)) + preferred_quality_type = next(iter(quality_group_dict)) + quality_group = quality_group_dict.get(preferred_quality_type) + + new_global_stack.quality = quality_group.node_for_global.getContainer() + if not new_global_stack.quality: + new_global_stack.quality = application.empty_quality_container + for position, extruder_stack in new_global_stack.extruders.items(): + if position in quality_group.nodes_for_extruders and quality_group.nodes_for_extruders[position].getContainer(): + extruder_stack.quality = quality_group.nodes_for_extruders[position].getContainer() + else: + extruder_stack.quality = application.empty_quality_container # Register the global stack after the extruder stacks are created. This prevents the registry from adding another # extruder stack because the global stack didn't have one yet (which is enforced since Cura 3.1). diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 47846fc1dd..ca687e358b 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -139,9 +139,6 @@ class ExtruderStack(CuraContainerStack): super().deserialize(contents, file_name) if "enabled" not in self.getMetaData(): self.setMetaDataEntry("enabled", "True") - stacks = ContainerRegistry.getInstance().findContainerStacks(id=self.getMetaDataEntry("machine", "")) - if stacks: - self.setNextStack(stacks[0]) def _onPropertiesChanged(self, key: str, properties: Dict[str, Any]) -> None: # When there is a setting that is not settable per extruder that depends on a value from a setting that is, diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index 66f3290b85..36084b7d4d 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -55,6 +55,16 @@ class GlobalStack(CuraContainerStack): return "machine_stack" return configuration_type + def getBuildplateName(self) -> Optional[str]: + name = None + if self.variant.getId() != "empty_variant": + name = self.variant.getName() + return name + + @pyqtProperty(str, constant = True) + def preferred_output_file_formats(self) -> str: + return self.getMetaDataEntry("file_formats") + ## Add an extruder to the list of extruders of this stack. # # \param extruder The extruder to add. @@ -96,6 +106,9 @@ class GlobalStack(CuraContainerStack): # Handle the "resolve" property. #TODO: Why the hell does this involve threading? + # Answer: Because if multiple threads start resolving properties that have the same underlying properties that's + # related, without taking a note of which thread a resolve paths belongs to, they can bump into each other and + # generate unexpected behaviours. if self._shouldResolve(key, property_name, context): current_thread = threading.current_thread() self._resolving_settings[current_thread.name].add(key) @@ -172,6 +185,9 @@ class GlobalStack(CuraContainerStack): return False return True + def getHeadAndFansCoordinates(self): + return self.getProperty("machine_head_with_fans_polygon", "value") + ## private: global_stack_mime = MimeType( diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index ff585deb54..d65bbfddd9 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -21,9 +21,6 @@ from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique import cura.CuraApplication -from cura.Machines.ContainerNode import ContainerNode #For typing. -from cura.Machines.QualityChangesGroup import QualityChangesGroup #For typing. -from cura.Machines.QualityGroup import QualityGroup #For typing. from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.ConfigurationModel import ConfigurationModel @@ -44,12 +41,16 @@ if TYPE_CHECKING: from cura.Machines.MaterialManager import MaterialManager from cura.Machines.QualityManager import QualityManager from cura.Machines.VariantManager import VariantManager + from cura.Machines.ContainerNode import ContainerNode + from cura.Machines.QualityChangesGroup import QualityChangesGroup + from cura.Machines.QualityGroup import QualityGroup + class MachineManager(QObject): def __init__(self, parent: QObject = None) -> None: super().__init__(parent) - self._active_container_stack = None # type: Optional[ExtruderManager] + self._active_container_stack = None # type: Optional[ExtruderStack] self._global_container_stack = None # type: Optional[GlobalStack] self._current_root_material_id = {} # type: Dict[str, str] @@ -1087,7 +1088,7 @@ class MachineManager(QObject): self.activeQualityGroupChanged.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: @@ -1118,7 +1119,7 @@ class MachineManager(QObject): self.activeQualityGroupChanged.emit() self.activeQualityChangesGroupChanged.emit() - def _fixQualityChangesGroupToNotSupported(self, quality_changes_group: QualityChangesGroup) -> None: + def _fixQualityChangesGroupToNotSupported(self, quality_changes_group: "QualityChangesGroup") -> None: 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] for container in containers: @@ -1126,7 +1127,7 @@ class MachineManager(QObject): container.setMetaDataEntry("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: if self._global_container_stack is None: return #Can't change that. quality_type = quality_changes_group.quality_type @@ -1170,20 +1171,20 @@ class MachineManager(QObject): self.activeQualityGroupChanged.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 or self._global_container_stack is None: return self._global_container_stack.extruders[position].variant = container_node.getContainer() 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() if not self._global_container_stack.variant: 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: Optional["ContainerNode"] = None) -> None: if self._global_container_stack is None: return if container_node and container_node.getContainer(): @@ -1256,13 +1257,17 @@ class MachineManager(QObject): else: position_list = [position] + buildplate_name = None + if self._global_container_stack.variant.getId() != "empty_variant": + buildplate_name = self._global_container_stack.variant.getName() + for position_item in position_list: extruder = self._global_container_stack.extruders[position_item] current_material_base_name = extruder.material.getMetaDataEntry("base_file") - current_variant_name = None + current_nozzle_name = None if extruder.variant.getId() != self._empty_variant_container.getId(): - current_variant_name = extruder.variant.getMetaDataEntry("name") + current_nozzle_name = extruder.variant.getMetaDataEntry("name") from UM.Settings.Interfaces import PropertyEvaluationContext from cura.Settings.CuraContainerStack import _ContainerIndexes @@ -1271,7 +1276,8 @@ class MachineManager(QObject): material_diameter = extruder.getProperty("material_diameter", "value", context) candidate_materials = self._material_manager.getAvailableMaterials( self._global_container_stack.definition, - current_variant_name, + current_nozzle_name, + buildplate_name, material_diameter) if not candidate_materials: @@ -1284,7 +1290,7 @@ class MachineManager(QObject): continue # The current material is not available, find the preferred one - material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, position_item, current_variant_name) + material_node = self._material_manager.getDefaultMaterial(self._global_container_stack, position_item, current_nozzle_name) if material_node is not None: self._setMaterial(position_item, material_node) @@ -1326,7 +1332,12 @@ class MachineManager(QObject): for extruder_configuration in configuration.extruderConfigurations: position = str(extruder_configuration.position) variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), extruder_configuration.hotendID) - material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, position, extruder_configuration.hotendID, extruder_configuration.material.guid) + material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, + position, + extruder_configuration.hotendID, + configuration.buildplateConfiguration, + extruder_configuration.material.guid) + if variant_container_node: self._setVariantNode(position, variant_container_node) else: @@ -1378,7 +1389,7 @@ class MachineManager(QObject): return bool(containers) @pyqtSlot("QVariant") - def setGlobalVariant(self, container_node: ContainerNode) -> None: + def setGlobalVariant(self, container_node: "ContainerNode") -> None: self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self._setGlobalVariant(container_node) @@ -1389,12 +1400,17 @@ class MachineManager(QObject): def setMaterialById(self, position: str, root_material_id: str) -> None: if self._global_container_stack is None: return + buildplate_name = None + if self._global_container_stack.variant.getId() != "empty_variant": + buildplate_name = self._global_container_stack.variant.getName() + machine_definition_id = self._global_container_stack.definition.id position = str(position) extruder_stack = self._global_container_stack.extruders[position] - variant_name = extruder_stack.variant.getName() + nozzle_name = extruder_stack.variant.getName() material_diameter = extruder_stack.approximateMaterialDiameter - material_node = self._material_manager.getMaterialNode(machine_definition_id, variant_name, material_diameter, root_material_id) + material_node = self._material_manager.getMaterialNode(machine_definition_id, nozzle_name, buildplate_name, + material_diameter, root_material_id) self.setMaterial(position, material_node) ## global_stack: if you want to provide your own global_stack instead of the current active one @@ -1423,7 +1439,7 @@ class MachineManager(QObject): self.setVariant(position, variant_node) @pyqtSlot(str, "QVariant") - def setVariant(self, position: str, container_node: ContainerNode) -> None: + def setVariant(self, position: str, container_node: "ContainerNode") -> None: position = str(position) self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): @@ -1447,7 +1463,7 @@ class MachineManager(QObject): ## Optionally provide global_stack if you want to use your own # The active global_stack is treated differently. @pyqtSlot(QObject) - def setQualityGroup(self, quality_group: QualityGroup, no_dialog: bool = False, global_stack: Optional["GlobalStack"] = None) -> None: + def setQualityGroup(self, quality_group: "QualityGroup", no_dialog: bool = False, global_stack: Optional["GlobalStack"] = None) -> None: if global_stack is not None and global_stack != self._global_container_stack: if quality_group is None: Logger.log("e", "Could not set quality group because quality group is None") @@ -1455,9 +1471,14 @@ class MachineManager(QObject): if quality_group.node_for_global is None: Logger.log("e", "Could not set quality group [%s] because it has no node_for_global", str(quality_group)) return + # This is not changing the quality for the active machine !!!!!!!! global_stack.quality = quality_group.node_for_global.getContainer() for extruder_nr, extruder_stack in global_stack.extruders.items(): - extruder_stack.quality = quality_group.nodes_for_extruders[extruder_nr].getContainer() + quality_container = self._empty_quality_container + if extruder_nr in quality_group.nodes_for_extruders: + container = quality_group.nodes_for_extruders[extruder_nr].getContainer() + quality_container = container if container is not None else quality_container + extruder_stack.quality = quality_container return self.blurSettings.emit() @@ -1469,11 +1490,11 @@ class MachineManager(QObject): self._application.discardOrKeepProfileChanges() @pyqtProperty(QObject, fset = setQualityGroup, notify = activeQualityGroupChanged) - def activeQualityGroup(self) -> Optional[QualityGroup]: + def activeQualityGroup(self) -> Optional["QualityGroup"]: return self._current_quality_group @pyqtSlot(QObject) - def setQualityChangesGroup(self, quality_changes_group: QualityChangesGroup, no_dialog: bool = False) -> None: + def setQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup", no_dialog: bool = False) -> None: self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self._setQualityChangesGroup(quality_changes_group) @@ -1492,7 +1513,7 @@ class MachineManager(QObject): stack.userChanges.clear() @pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged) - def activeQualityChangesGroup(self) -> Optional[QualityChangesGroup]: + def activeQualityChangesGroup(self) -> Optional["QualityChangesGroup"]: return self._current_quality_changes_group @pyqtProperty(str, notify = activeQualityGroupChanged) diff --git a/cura/Settings/SidebarCustomMenuItemsModel.py b/cura/Settings/SidebarCustomMenuItemsModel.py new file mode 100644 index 0000000000..ec926363f5 --- /dev/null +++ b/cura/Settings/SidebarCustomMenuItemsModel.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from typing import Any + +from UM.Qt.ListModel import ListModel +from PyQt5.QtCore import pyqtSlot, Qt + + +class SidebarCustomMenuItemsModel(ListModel): + name_role = Qt.UserRole + 1 + actions_role = Qt.UserRole + 2 + menu_item_role = Qt.UserRole + 3 + menu_item_icon_name_role = Qt.UserRole + 5 + + def __init__(self, parent=None): + super().__init__(parent) + self.addRoleName(self.name_role, "name") + self.addRoleName(self.actions_role, "actions") + self.addRoleName(self.menu_item_role, "menu_item") + self.addRoleName(self.menu_item_icon_name_role, "iconName") + self._updateExtensionList() + + def _updateExtensionList(self)-> None: + from cura.CuraApplication import CuraApplication + for menu_item in CuraApplication.getInstance().getSidebarCustomMenuItems(): + + self.appendItem({ + "name": menu_item["name"], + "icon_name": menu_item["icon_name"], + "actions": menu_item["actions"], + "menu_item": menu_item["menu_item"] + }) + + @pyqtSlot(str, "QVariantList", "QVariantMap") + def callMenuItemMethod(self, menu_item_name: str, menu_item_actions: list, kwargs: Any) -> None: + for item in self._items: + if menu_item_name == item["name"]: + for method in menu_item_actions: + getattr(item["menu_item"], method)(kwargs) + break \ No newline at end of file diff --git a/cura/Settings/cura_empty_instance_containers.py b/cura/Settings/cura_empty_instance_containers.py new file mode 100644 index 0000000000..d76407ed79 --- /dev/null +++ b/cura/Settings/cura_empty_instance_containers.py @@ -0,0 +1,56 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import copy + +from UM.Settings.constant_instance_containers import EMPTY_CONTAINER_ID, empty_container + + +# Empty definition changes +EMPTY_DEFINITION_CHANGES_CONTAINER_ID = "empty_definition_changes" +empty_definition_changes_container = copy.deepcopy(empty_container) +empty_definition_changes_container.setMetaDataEntry("id", EMPTY_DEFINITION_CHANGES_CONTAINER_ID) +empty_definition_changes_container.setMetaDataEntry("type", "definition_changes") + +# Empty variant +EMPTY_VARIANT_CONTAINER_ID = "empty_variant" +empty_variant_container = copy.deepcopy(empty_container) +empty_variant_container.setMetaDataEntry("id", EMPTY_VARIANT_CONTAINER_ID) +empty_variant_container.setMetaDataEntry("type", "variant") + +# Empty material +EMPTY_MATERIAL_CONTAINER_ID = "empty_material" +empty_material_container = copy.deepcopy(empty_container) +empty_material_container.setMetaDataEntry("id", EMPTY_MATERIAL_CONTAINER_ID) +empty_material_container.setMetaDataEntry("type", "material") + +# Empty quality +EMPTY_QUALITY_CONTAINER_ID = "empty_quality" +empty_quality_container = copy.deepcopy(empty_container) +empty_quality_container.setMetaDataEntry("id", EMPTY_QUALITY_CONTAINER_ID) +empty_quality_container.setName("Not Supported") +empty_quality_container.setMetaDataEntry("quality_type", "not_supported") +empty_quality_container.setMetaDataEntry("type", "quality") +empty_quality_container.setMetaDataEntry("supported", False) + +# Empty quality changes +EMPTY_QUALITY_CHANGES_CONTAINER_ID = "empty_quality_changes" +empty_quality_changes_container = copy.deepcopy(empty_container) +empty_quality_changes_container.setMetaDataEntry("id", EMPTY_QUALITY_CHANGES_CONTAINER_ID) +empty_quality_changes_container.setMetaDataEntry("type", "quality_changes") +empty_quality_changes_container.setMetaDataEntry("quality_type", "not_supported") + + +__all__ = ["EMPTY_CONTAINER_ID", + "empty_container", # For convenience + "EMPTY_DEFINITION_CHANGES_CONTAINER_ID", + "empty_definition_changes_container", + "EMPTY_VARIANT_CONTAINER_ID", + "empty_variant_container", + "EMPTY_MATERIAL_CONTAINER_ID", + "empty_material_container", + "EMPTY_QUALITY_CHANGES_CONTAINER_ID", + "empty_quality_changes_container", + "EMPTY_QUALITY_CONTAINER_ID", + "empty_quality_container" + ] diff --git a/cura_app.py b/cura_app.py index c3c766fdb1..164e32e738 100755 --- a/cura_app.py +++ b/cura_app.py @@ -131,6 +131,7 @@ faulthandler.enable(all_threads = True) # first seems to prevent Sip from going into a state where it # tries to create PyQt objects on a non-main thread. import Arcus #@UnusedImport +import Savitar #@UnusedImport from cura.CuraApplication import CuraApplication app = CuraApplication() diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 0280600834..9ba82364e8 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -59,7 +59,7 @@ class ThreeMFReader(MeshReader): if transformation == "": return Matrix() - splitted_transformation = transformation.split() + split_transformation = transformation.split() ## Transformation is saved as: ## M00 M01 M02 0.0 ## M10 M11 M12 0.0 @@ -68,20 +68,20 @@ class ThreeMFReader(MeshReader): ## We switch the row & cols as that is how everyone else uses matrices! temp_mat = Matrix() # Rotation & Scale - temp_mat._data[0, 0] = splitted_transformation[0] - temp_mat._data[1, 0] = splitted_transformation[1] - temp_mat._data[2, 0] = splitted_transformation[2] - temp_mat._data[0, 1] = splitted_transformation[3] - temp_mat._data[1, 1] = splitted_transformation[4] - temp_mat._data[2, 1] = splitted_transformation[5] - temp_mat._data[0, 2] = splitted_transformation[6] - temp_mat._data[1, 2] = splitted_transformation[7] - temp_mat._data[2, 2] = splitted_transformation[8] + temp_mat._data[0, 0] = split_transformation[0] + temp_mat._data[1, 0] = split_transformation[1] + temp_mat._data[2, 0] = split_transformation[2] + temp_mat._data[0, 1] = split_transformation[3] + temp_mat._data[1, 1] = split_transformation[4] + temp_mat._data[2, 1] = split_transformation[5] + temp_mat._data[0, 2] = split_transformation[6] + temp_mat._data[1, 2] = split_transformation[7] + temp_mat._data[2, 2] = split_transformation[8] # Translation - temp_mat._data[0, 3] = splitted_transformation[9] - temp_mat._data[1, 3] = splitted_transformation[10] - temp_mat._data[2, 3] = splitted_transformation[11] + temp_mat._data[0, 3] = split_transformation[9] + temp_mat._data[1, 3] = split_transformation[10] + temp_mat._data[2, 3] = split_transformation[11] return temp_mat diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index f72029524e..6d55e0643d 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -24,6 +24,7 @@ from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.Job import Job from UM.Preferences import Preferences +from cura.Machines.VariantType import VariantType from cura.Settings.CuraStackBuilder import CuraStackBuilder from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.GlobalStack import GlobalStack @@ -84,14 +85,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): def __init__(self) -> None: super().__init__() - MimeTypeDatabase.addMimeType( - MimeType( - name="application/x-curaproject+xml", - comment="Cura Project File", - suffixes=["curaproject.3mf"] - ) - ) - self._supported_extensions = [".3mf"] self._dialog = WorkspaceDialog() self._3mf_mesh_reader = None @@ -629,6 +622,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader): type = "extruder_train") extruder_stack_dict = {stack.getMetaDataEntry("position"): stack for stack in extruder_stacks} + # Make sure that those extruders have the global stack as the next stack or later some value evaluation + # will fail. + for stack in extruder_stacks: + stack.setNextStack(global_stack, connect_signals = False) + Logger.log("d", "Workspace loading is checking definitions...") # Get all the definition files & check if they exist. If not, add them. definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)] @@ -720,8 +718,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): nodes = [] base_file_name = os.path.basename(file_name) - if base_file_name.endswith(".curaproject.3mf"): - base_file_name = base_file_name[:base_file_name.rfind(".curaproject.3mf")] self.setWorkspaceName(base_file_name) return nodes @@ -889,7 +885,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): parser = self._machine_info.variant_info.parser variant_name = parser["general"]["name"] - from cura.Machines.VariantManager import VariantType variant_type = VariantType.BUILD_PLATE node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type) @@ -905,7 +900,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader): parser = extruder_info.variant_info.parser variant_name = parser["general"]["name"] - from cura.Machines.VariantManager import VariantType variant_type = VariantType.NOZZLE node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type) @@ -929,12 +923,16 @@ class ThreeMFWorkspaceReader(WorkspaceReader): root_material_id = extruder_info.root_material_id root_material_id = self._old_new_materials.get(root_material_id, root_material_id) + build_plate_id = global_stack.variant.getId() + # get material diameter of this extruder machine_material_diameter = extruder_stack.materialDiameter material_node = material_manager.getMaterialNode(global_stack.definition.getId(), extruder_stack.variant.getName(), + build_plate_id, machine_material_diameter, root_material_id) + if material_node is not None and material_node.getContainer() is not None: extruder_stack.material = material_node.getContainer() diff --git a/plugins/3MFReader/__init__.py b/plugins/3MFReader/__init__.py index 3a4fde4ab8..ce94bbe69c 100644 --- a/plugins/3MFReader/__init__.py +++ b/plugins/3MFReader/__init__.py @@ -18,11 +18,7 @@ catalog = i18nCatalog("cura") def getMetaData() -> Dict: - # Workaround for osx not supporting double file extensions correctly. - if Platform.isOSX(): - workspace_extension = "3mf" - else: - workspace_extension = "curaproject.3mf" + workspace_extension = "3mf" metaData = {} if "3MFReader.ThreeMFReader" in sys.modules: diff --git a/plugins/3MFReader/plugin.json b/plugins/3MFReader/plugin.json index 5d15123017..5e41975752 100644 --- a/plugins/3MFReader/plugin.json +++ b/plugins/3MFReader/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for reading 3MF files.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/3MFWriter/ThreeMFWriter.py b/plugins/3MFWriter/ThreeMFWriter.py index 8d54f475d6..640aabd30c 100644 --- a/plugins/3MFWriter/ThreeMFWriter.py +++ b/plugins/3MFWriter/ThreeMFWriter.py @@ -25,6 +25,9 @@ except ImportError: import zipfile import UM.Application +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + class ThreeMFWriter(MeshWriter): def __init__(self): @@ -173,6 +176,7 @@ class ThreeMFWriter(MeshWriter): archive.writestr(relations_file, b' \n' + ET.tostring(relations_element)) except Exception as e: Logger.logException("e", "Error writing zip file") + self.setInformation(catalog.i18nc("@error:zip", "Error writing 3mf file.")) return False finally: if not self._store_archive: diff --git a/plugins/3MFWriter/__init__.py b/plugins/3MFWriter/__init__.py index e779628f7e..4b8a03888d 100644 --- a/plugins/3MFWriter/__init__.py +++ b/plugins/3MFWriter/__init__.py @@ -15,11 +15,7 @@ from UM.Platform import Platform i18n_catalog = i18nCatalog("uranium") def getMetaData(): - # Workarround for osx not supporting double file extensions correctly. - if Platform.isOSX(): - workspace_extension = "3mf" - else: - workspace_extension = "curaproject.3mf" + workspace_extension = "3mf" metaData = {} @@ -36,7 +32,7 @@ def getMetaData(): "output": [{ "extension": workspace_extension, "description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"), - "mime_type": "application/x-curaproject+xml", + "mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml", "mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode }] } diff --git a/plugins/3MFWriter/plugin.json b/plugins/3MFWriter/plugin.json index 22d18b2cf1..9ec4fb0c20 100644 --- a/plugins/3MFWriter/plugin.json +++ b/plugins/3MFWriter/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for writing 3MF files.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/ChangeLogPlugin/plugin.json b/plugins/ChangeLogPlugin/plugin.json index e9414b9b71..e09a08564a 100644 --- a/plugins/ChangeLogPlugin/plugin.json +++ b/plugins/ChangeLogPlugin/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Shows changes since latest checked version.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index beec374d8d..9a5c95b04d 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -1,6 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import argparse #To run the engine in debug mode if the front-end is in debug mode. from collections import defaultdict import os from PyQt5.QtCore import QObject, QTimer, pyqtSlot @@ -179,7 +180,15 @@ class CuraEngineBackend(QObject, Backend): # \return list of commands and args / parameters. def getEngineCommand(self) -> List[str]: json_path = Resources.getPath(Resources.DefinitionContainers, "fdmprinter.def.json") - return [self._application.getPreferences().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", json_path, ""] + command = [self._application.getPreferences().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", json_path, ""] + + parser = argparse.ArgumentParser(prog = "cura", add_help = False) + parser.add_argument("--debug", action = "store_true", default = False, help = "Turn on the debug mode by setting this option.") + known_args = vars(parser.parse_known_args()[0]) + if known_args["debug"]: + command.append("-vvv") + + return command ## Emitted when we get a message containing print duration and material amount. # This also implies the slicing has finished. @@ -541,6 +550,9 @@ class CuraEngineBackend(QObject, Backend): ## Remove old layer data (if any) def _clearLayerData(self, build_plate_numbers: Set = None) -> None: + # Clear out any old gcode + self._scene.gcode_dict = {} # type: ignore + for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if node.callDecoration("getLayerData"): if not build_plate_numbers or node.callDecoration("getBuildPlateNumber") in build_plate_numbers: diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index eb392de121..1295390c22 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -41,7 +41,7 @@ class StartJobResult(IntEnum): ## Formatter class that handles token expansion in start/end gcode class GcodeStartEndFormatter(Formatter): - def get_value(self, key: str, *args: str, default_extruder_nr: str = "-1", **kwargs) -> str: #type: ignore # [CodeStyle: get_value is an overridden function from the Formatter class] + def get_value(self, key: str, args: str, kwargs: dict, default_extruder_nr: str = "-1") -> str: #type: ignore # [CodeStyle: get_value is an overridden function from the Formatter class] # The kwargs dictionary contains a dictionary for each stack (with a string of the extruder_nr as their key), # and a default_extruder_nr to use when no extruder_nr is specified @@ -220,8 +220,10 @@ class StartSliceJob(Job): stack = global_stack skip_group = False for node in group: + # Only check if the printing extruder is enabled for printing meshes + is_non_printing_mesh = node.callDecoration("evaluateIsNonPrintingMesh") extruder_position = node.callDecoration("getActiveExtruderPosition") - if not extruders_enabled[extruder_position]: + if not is_non_printing_mesh and not extruders_enabled[extruder_position]: skip_group = True has_model_with_disabled_extruders = True associated_disabled_extruders.add(extruder_position) diff --git a/plugins/CuraEngineBackend/plugin.json b/plugins/CuraEngineBackend/plugin.json index e5df06f228..111698d8d1 100644 --- a/plugins/CuraEngineBackend/plugin.json +++ b/plugins/CuraEngineBackend/plugin.json @@ -2,7 +2,7 @@ "name": "CuraEngine Backend", "author": "Ultimaker B.V.", "description": "Provides the link to the CuraEngine slicing backend.", - "api": 4, + "api": 5, "version": "1.0.0", "i18n-catalog": "cura" } diff --git a/plugins/CuraProfileReader/plugin.json b/plugins/CuraProfileReader/plugin.json index 004a1ade4d..66a2a6a56b 100644 --- a/plugins/CuraProfileReader/plugin.json +++ b/plugins/CuraProfileReader/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for importing Cura profiles.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/CuraProfileWriter/plugin.json b/plugins/CuraProfileWriter/plugin.json index d9accce770..16c8c34152 100644 --- a/plugins/CuraProfileWriter/plugin.json +++ b/plugins/CuraProfileWriter/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for exporting Cura profiles.", - "api": 4, + "api": 5, "i18n-catalog":"cura" } diff --git a/plugins/FirmwareUpdateChecker/plugin.json b/plugins/FirmwareUpdateChecker/plugin.json index d6a9f9fbd7..cbbd41e420 100644 --- a/plugins/FirmwareUpdateChecker/plugin.json +++ b/plugins/FirmwareUpdateChecker/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Checks for firmware updates.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/GCodeGzReader/plugin.json b/plugins/GCodeGzReader/plugin.json index e9f14724e0..3bd6a4097d 100644 --- a/plugins/GCodeGzReader/plugin.json +++ b/plugins/GCodeGzReader/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Reads g-code from a compressed archive.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/GCodeGzWriter/GCodeGzWriter.py b/plugins/GCodeGzWriter/GCodeGzWriter.py index 6ddecdb0bd..cbbfb8f986 100644 --- a/plugins/GCodeGzWriter/GCodeGzWriter.py +++ b/plugins/GCodeGzWriter/GCodeGzWriter.py @@ -10,10 +10,17 @@ from UM.Mesh.MeshWriter import MeshWriter #The class we're extending/implementin from UM.PluginRegistry import PluginRegistry from UM.Scene.SceneNode import SceneNode #For typing. +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + ## A file writer that writes gzipped g-code. # # If you're zipping g-code, you might as well use gzip! class GCodeGzWriter(MeshWriter): + + def __init__(self) -> None: + super().__init__(add_to_recent_files = False) + ## Writes the gzipped g-code to a stream. # # Note that even though the function accepts a collection of nodes, the @@ -28,12 +35,15 @@ class GCodeGzWriter(MeshWriter): def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode = MeshWriter.OutputMode.BinaryMode) -> bool: if mode != MeshWriter.OutputMode.BinaryMode: Logger.log("e", "GCodeGzWriter does not support text mode.") + self.setInformation(catalog.i18nc("@error:not supported", "GCodeGzWriter does not support text mode.")) return False #Get the g-code from the g-code writer. gcode_textio = StringIO() #We have to convert the g-code into bytes. - success = cast(MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")).write(gcode_textio, None) + gcode_writer = cast(MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")) + success = gcode_writer.write(gcode_textio, None) if not success: #Writing the g-code failed. Then I can also not write the gzipped g-code. + self.setInformation(gcode_writer.getInformation()) return False result = gzip.compress(gcode_textio.getvalue().encode("utf-8")) diff --git a/plugins/GCodeGzWriter/__init__.py b/plugins/GCodeGzWriter/__init__.py index e257bcb011..95949eee74 100644 --- a/plugins/GCodeGzWriter/__init__.py +++ b/plugins/GCodeGzWriter/__init__.py @@ -16,7 +16,8 @@ def getMetaData(): "extension": file_extension, "description": catalog.i18nc("@item:inlistbox", "Compressed G-code File"), "mime_type": "application/gzip", - "mode": GCodeGzWriter.GCodeGzWriter.OutputMode.BinaryMode + "mode": GCodeGzWriter.GCodeGzWriter.OutputMode.BinaryMode, + "hide_in_file_dialog": True, }] } } diff --git a/plugins/GCodeGzWriter/plugin.json b/plugins/GCodeGzWriter/plugin.json index 9774e9a25c..4c6497317b 100644 --- a/plugins/GCodeGzWriter/plugin.json +++ b/plugins/GCodeGzWriter/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Writes g-code to a compressed archive.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/GCodeProfileReader/plugin.json b/plugins/GCodeProfileReader/plugin.json index f8f7d4c291..9677628c85 100644 --- a/plugins/GCodeProfileReader/plugin.json +++ b/plugins/GCodeProfileReader/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for importing profiles from g-code files.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/GCodeReader/plugin.json b/plugins/GCodeReader/plugin.json index f72a8cc12c..75b4d0cd4f 100644 --- a/plugins/GCodeReader/plugin.json +++ b/plugins/GCodeReader/plugin.json @@ -3,6 +3,6 @@ "author": "Victor Larchenko", "version": "1.0.0", "description": "Allows loading and displaying G-code files.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index aea0698d19..5d5e3578cd 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -12,6 +12,8 @@ from UM.Settings.InstanceContainer import InstanceContainer from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") ## Writes g-code to a file. # @@ -45,7 +47,7 @@ class GCodeWriter(MeshWriter): _setting_keyword = ";SETTING_" def __init__(self): - super().__init__() + super().__init__(add_to_recent_files = False) self._application = Application.getInstance() @@ -62,11 +64,13 @@ class GCodeWriter(MeshWriter): def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode): if mode != MeshWriter.OutputMode.TextMode: Logger.log("e", "GCodeWriter does not support non-text mode.") + self.setInformation(catalog.i18nc("@error:not supported", "GCodeWriter does not support non-text mode.")) return False active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate scene = Application.getInstance().getController().getScene() if not hasattr(scene, "gcode_dict"): + self.setInformation(catalog.i18nc("@warning:status", "Please generate G-code before saving.")) return False gcode_dict = getattr(scene, "gcode_dict") gcode_list = gcode_dict.get(active_build_plate, None) @@ -82,6 +86,7 @@ class GCodeWriter(MeshWriter): stream.write(settings) return True + self.setInformation(catalog.i18nc("@warning:status", "Please generate G-code before saving.")) return False ## Create a new container with container 2 as base and container 1 written over it. diff --git a/plugins/GCodeWriter/plugin.json b/plugins/GCodeWriter/plugin.json index 5fcb1a3bd7..3bbbab8b95 100644 --- a/plugins/GCodeWriter/plugin.json +++ b/plugins/GCodeWriter/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Writes g-code to a file.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/ImageReader/plugin.json b/plugins/ImageReader/plugin.json index 2752c6e8f4..08195863e8 100644 --- a/plugins/ImageReader/plugin.json +++ b/plugins/ImageReader/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Enables ability to generate printable geometry from 2D image files.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/LegacyProfileReader/plugin.json b/plugins/LegacyProfileReader/plugin.json index 2dc71511a9..179f5444e0 100644 --- a/plugins/LegacyProfileReader/plugin.json +++ b/plugins/LegacyProfileReader/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for importing profiles from legacy Cura versions.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/MachineSettingsAction/plugin.json b/plugins/MachineSettingsAction/plugin.json index 703a145deb..571658e40a 100644 --- a/plugins/MachineSettingsAction/plugin.json +++ b/plugins/MachineSettingsAction/plugin.json @@ -3,6 +3,6 @@ "author": "fieldOfView", "version": "1.0.0", "description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/ModelChecker/plugin.json b/plugins/ModelChecker/plugin.json index a9190adcaa..3753c0cc88 100644 --- a/plugins/ModelChecker/plugin.json +++ b/plugins/ModelChecker/plugin.json @@ -2,7 +2,7 @@ "name": "Model Checker", "author": "Ultimaker B.V.", "version": "0.1", - "api": 4, + "api": 5, "description": "Checks models and print configuration for possible printing issues and give suggestions.", "i18n-catalog": "cura" } diff --git a/plugins/MonitorStage/plugin.json b/plugins/MonitorStage/plugin.json index cb3f55a80d..88b53840e0 100644 --- a/plugins/MonitorStage/plugin.json +++ b/plugins/MonitorStage/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides a monitor stage in Cura.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/PerObjectSettingsTool/plugin.json b/plugins/PerObjectSettingsTool/plugin.json index 3254662d33..15fde63387 100644 --- a/plugins/PerObjectSettingsTool/plugin.json +++ b/plugins/PerObjectSettingsTool/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides the Per Model Settings.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py index da971a8e61..b28a028325 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -1,5 +1,6 @@ -# Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V. +# Copyright (c) 2018 Jaime van Kessel, Ultimaker B.V. # The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. + from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot from UM.PluginRegistry import PluginRegistry @@ -260,6 +261,9 @@ class PostProcessingPlugin(QObject, Extension): # Create the plugin dialog component path = os.path.join(PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), "PostProcessingPlugin.qml") self._view = Application.getInstance().createQmlComponent(path, {"manager": self}) + if self._view is None: + Logger.log("e", "Not creating PostProcessing button near save button because the QML component failed to be created.") + return Logger.log("d", "Post processing view created.") # Create the save button component @@ -269,6 +273,9 @@ class PostProcessingPlugin(QObject, Extension): def showPopup(self): if self._view is None: self._createView() + if self._view is None: + Logger.log("e", "Not creating PostProcessing window since the QML component failed to be created.") + return self._view.show() ## Property changed: trigger re-slice diff --git a/plugins/PostProcessingPlugin/plugin.json b/plugins/PostProcessingPlugin/plugin.json index ebfef8145a..fea061e93b 100644 --- a/plugins/PostProcessingPlugin/plugin.json +++ b/plugins/PostProcessingPlugin/plugin.json @@ -2,7 +2,7 @@ "name": "Post Processing", "author": "Ultimaker", "version": "2.2", - "api": 4, + "api": 5, "description": "Extension that allows for user created scripts for post processing", "catalog": "cura" } \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/scripts/FilamentChange.py b/plugins/PostProcessingPlugin/scripts/FilamentChange.py index 1246bc8b43..0fa52de4f1 100644 --- a/plugins/PostProcessingPlugin/scripts/FilamentChange.py +++ b/plugins/PostProcessingPlugin/scripts/FilamentChange.py @@ -58,10 +58,10 @@ class FilamentChange(Script): color_change = "M600" if initial_retract is not None and initial_retract > 0.: - color_change = color_change + (" E%.2f" % initial_retract) + color_change = color_change + (" E-%.2f" % initial_retract) if later_retract is not None and later_retract > 0.: - color_change = color_change + (" L%.2f" % later_retract) + color_change = color_change + (" L-%.2f" % later_retract) color_change = color_change + " ; Generated by FilamentChange plugin" diff --git a/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py b/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py index 6354dd4f04..8b50a88b7f 100644 --- a/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py +++ b/plugins/PostProcessingPlugin/scripts/PauseAtHeight.py @@ -28,7 +28,7 @@ class PauseAtHeight(Script): "pause_height": { "label": "Pause Height", - "description": "At what height should the pause occur", + "description": "At what height should the pause occur?", "unit": "mm", "type": "float", "default_value": 5.0, @@ -39,7 +39,7 @@ class PauseAtHeight(Script): "pause_layer": { "label": "Pause Layer", - "description": "At what layer should the pause occur", + "description": "At what layer should the pause occur?", "type": "int", "value": "math.floor((pause_height - 0.27) / 0.1) + 1", "minimum_value": "0", @@ -142,13 +142,14 @@ class PauseAtHeight(Script): standby_temperature = self.getSettingValueByKey("standby_temperature") firmware_retract = Application.getInstance().getGlobalContainerStack().getProperty("machine_firmware_retract", "value") control_temperatures = Application.getInstance().getGlobalContainerStack().getProperty("machine_nozzle_temp_enabled", "value") + initial_layer_height = Application.getInstance().getGlobalContainerStack().getProperty("layer_height_0", "value") is_griffin = False # T = ExtruderManager.getInstance().getActiveExtruderStack().getProperty("material_print_temperature", "value") # use offset to calculate the current height: = - - layer_0_z = 0. + layer_0_z = 0 current_z = 0 got_first_g_cmd_on_layer_0 = False current_t = 0 #Tracks the current extruder for tracking the target temperature. @@ -195,11 +196,10 @@ class PauseAtHeight(Script): # This block is executed once, the first time there is a G # command, to get the z offset (z for first positive layer) if not got_first_g_cmd_on_layer_0: - layer_0_z = current_z + layer_0_z = current_z - initial_layer_height got_first_g_cmd_on_layer_0 = True current_height = current_z - layer_0_z - if current_height < pause_height: break # Try the next layer. diff --git a/plugins/PostProcessingPlugin/scripts/Stretch.py b/plugins/PostProcessingPlugin/scripts/Stretch.py index c7a36ab7d6..9757296041 100644 --- a/plugins/PostProcessingPlugin/scripts/Stretch.py +++ b/plugins/PostProcessingPlugin/scripts/Stretch.py @@ -35,25 +35,39 @@ class GCodeStep(): Class to store the current value of each G_Code parameter for any G-Code step """ - def __init__(self, step): + def __init__(self, step, in_relative_movement: bool = False): self.step = step self.step_x = 0 self.step_y = 0 self.step_z = 0 self.step_e = 0 self.step_f = 0 + + self.in_relative_movement = in_relative_movement + self.comment = "" def readStep(self, line): """ Reads gcode from line into self """ - self.step_x = _getValue(line, "X", self.step_x) - self.step_y = _getValue(line, "Y", self.step_y) - self.step_z = _getValue(line, "Z", self.step_z) - self.step_e = _getValue(line, "E", self.step_e) - self.step_f = _getValue(line, "F", self.step_f) - return + if not self.in_relative_movement: + self.step_x = _getValue(line, "X", self.step_x) + self.step_y = _getValue(line, "Y", self.step_y) + self.step_z = _getValue(line, "Z", self.step_z) + self.step_e = _getValue(line, "E", self.step_e) + self.step_f = _getValue(line, "F", self.step_f) + else: + delta_step_x = _getValue(line, "X", 0) + delta_step_y = _getValue(line, "Y", 0) + delta_step_z = _getValue(line, "Z", 0) + delta_step_e = _getValue(line, "E", 0) + + self.step_x += delta_step_x + self.step_y += delta_step_y + self.step_z += delta_step_z + self.step_e += delta_step_e + self.step_f = _getValue(line, "F", self.step_f) # the feedrate is not relative def copyPosFrom(self, step): """ @@ -65,7 +79,9 @@ class GCodeStep(): self.step_e = step.step_e self.step_f = step.step_f self.comment = step.comment - return + + def setInRelativeMovement(self, value: bool) -> None: + self.in_relative_movement = value # Execution part of the stretch plugin @@ -86,6 +102,7 @@ class Stretcher(): # of already deposited material for current layer self.layer_z = 0 # Z position of the extrusion moves of the current layer self.layergcode = "" + self._in_relative_movement = False def execute(self, data): """ @@ -96,7 +113,8 @@ class Stretcher(): + " and push wall stretch " + str(self.pw_stretch) + "mm") retdata = [] layer_steps = [] - current = GCodeStep(0) + in_relative_movement = False + current = GCodeStep(0, in_relative_movement) self.layer_z = 0. current_e = 0. for layer in data: @@ -107,20 +125,31 @@ class Stretcher(): current.comment = line[line.find(";"):] if _getValue(line, "G") == 0: current.readStep(line) - onestep = GCodeStep(0) + onestep = GCodeStep(0, in_relative_movement) onestep.copyPosFrom(current) elif _getValue(line, "G") == 1: current.readStep(line) - onestep = GCodeStep(1) + onestep = GCodeStep(1, in_relative_movement) onestep.copyPosFrom(current) + + # end of relative movement + elif _getValue(line, "G") == 90: + in_relative_movement = False + current.setInRelativeMovement(in_relative_movement) + # start of relative movement + elif _getValue(line, "G") == 91: + in_relative_movement = True + current.setInRelativeMovement(in_relative_movement) + elif _getValue(line, "G") == 92: current.readStep(line) - onestep = GCodeStep(-1) + onestep = GCodeStep(-1, in_relative_movement) onestep.copyPosFrom(current) else: - onestep = GCodeStep(-1) + onestep = GCodeStep(-1, in_relative_movement) onestep.copyPosFrom(current) onestep.comment = line + if line.find(";LAYER:") >= 0 and len(layer_steps): # Previous plugin "forgot" to separate two layers... Logger.log("d", "Layer Z " + "{:.3f}".format(self.layer_z) diff --git a/plugins/PrepareStage/plugin.json b/plugins/PrepareStage/plugin.json index 4fd55e955e..f0464313c7 100644 --- a/plugins/PrepareStage/plugin.json +++ b/plugins/PrepareStage/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides a prepare stage in Cura.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/RemovableDriveOutputDevice/plugin.json b/plugins/RemovableDriveOutputDevice/plugin.json index df11644256..36bb9ae186 100644 --- a/plugins/RemovableDriveOutputDevice/plugin.json +++ b/plugins/RemovableDriveOutputDevice/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "description": "Provides removable drive hotplugging and writing support.", "version": "1.0.0", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/SimulationView/LayerSlider.qml b/plugins/SimulationView/LayerSlider.qml index 22f9d91340..6dcaa3f475 100644 --- a/plugins/SimulationView/LayerSlider.qml +++ b/plugins/SimulationView/LayerSlider.qml @@ -40,33 +40,37 @@ Item { property bool layersVisible: true - function getUpperValueFromSliderHandle () { + function getUpperValueFromSliderHandle() { return upperHandle.getValue() } - function setUpperValue (value) { + function setUpperValue(value) { upperHandle.setValue(value) updateRangeHandle() } - function getLowerValueFromSliderHandle () { + function getLowerValueFromSliderHandle() { return lowerHandle.getValue() } - function setLowerValue (value) { + function setLowerValue(value) { lowerHandle.setValue(value) updateRangeHandle() } - function updateRangeHandle () { + function updateRangeHandle() { rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height) } // set the active handle to show only one label at a time - function setActiveHandle (handle) { + function setActiveHandle(handle) { activeHandle = handle } + function normalizeValue(value) { + return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue) + } + // slider track Rectangle { id: track @@ -188,6 +192,8 @@ Item { // set the slider position based on the upper value function setValue (value) { + // Normalize values between range, since using arrow keys will create out-of-the-range values + value = sliderRoot.normalizeValue(value) UM.SimulationView.setCurrentLayer(value) @@ -274,6 +280,8 @@ Item { // set the slider position based on the lower value function setValue (value) { + // Normalize values between range, since using arrow keys will create out-of-the-range values + value = sliderRoot.normalizeValue(value) UM.SimulationView.setMinimumLayer(value) diff --git a/plugins/SimulationView/PathSlider.qml b/plugins/SimulationView/PathSlider.qml index 0a4af904aa..999912e3ba 100644 --- a/plugins/SimulationView/PathSlider.qml +++ b/plugins/SimulationView/PathSlider.qml @@ -29,6 +29,7 @@ Item { // value properties property real maximumValue: 100 + property real minimumValue: 0 property bool roundValues: true property real handleValue: maximumValue @@ -47,6 +48,10 @@ Item { rangeHandle.width = handle.x - sliderRoot.handleSize } + function normalizeValue(value) { + return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue) + } + // slider track Rectangle { id: track @@ -110,6 +115,8 @@ Item { // set the slider position based on the value function setValue (value) { + // Normalize values between range, since using arrow keys will create out-of-the-range values + value = sliderRoot.normalizeValue(value) UM.SimulationView.setCurrentPath(value) diff --git a/plugins/SimulationView/SimulationSliderLabel.qml b/plugins/SimulationView/SimulationSliderLabel.qml index cdefd75f2b..559bffadc4 100644 --- a/plugins/SimulationView/SimulationSliderLabel.qml +++ b/plugins/SimulationView/SimulationSliderLabel.qml @@ -25,10 +25,6 @@ UM.PointingRectangle { width: valueLabel.width + UM.Theme.getSize("default_margin").width visible: false - // make sure the text field is focussed when pressing the parent handle - // needed to connect the key bindings when switching active handle - onVisibleChanged: if (visible) valueLabel.forceActiveFocus() - color: UM.Theme.getColor("tool_panel_background") borderColor: UM.Theme.getColor("lining") borderWidth: UM.Theme.getSize("default_lining").width diff --git a/plugins/SimulationView/SimulationView.qml b/plugins/SimulationView/SimulationView.qml index a3a8ced4cf..be767e93ab 100644 --- a/plugins/SimulationView/SimulationView.qml +++ b/plugins/SimulationView/SimulationView.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.4 @@ -12,30 +12,43 @@ import Cura 1.0 as Cura Item { id: base - width: { - if (UM.SimulationView.compatibilityMode) { + width: + { + if (UM.SimulationView.compatibilityMode) + { return UM.Theme.getSize("layerview_menu_size_compatibility").width; - } else { + } + else + { return UM.Theme.getSize("layerview_menu_size").width; } } height: { - if (viewSettings.collapsed) { - if (UM.SimulationView.compatibilityMode) { + if (viewSettings.collapsed) + { + if (UM.SimulationView.compatibilityMode) + { return UM.Theme.getSize("layerview_menu_size_compatibility_collapsed").height; } return UM.Theme.getSize("layerview_menu_size_collapsed").height; - } else if (UM.SimulationView.compatibilityMode) { + } + else if (UM.SimulationView.compatibilityMode) + { return UM.Theme.getSize("layerview_menu_size_compatibility").height; - } else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) { + } + else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) + { return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) - } else { + } + else + { return UM.Theme.getSize("layerview_menu_size").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) } } Behavior on height { NumberAnimation { duration: 100 } } - property var buttonTarget: { + property var buttonTarget: + { if(parent != null) { var force_binding = parent.y; // ensure this gets reevaluated when the panel moves @@ -44,7 +57,8 @@ Item return Qt.point(0,0) } - Rectangle { + Rectangle + { id: layerViewMenu anchors.right: parent.right anchors.top: parent.top @@ -83,7 +97,8 @@ Item } } - ColumnLayout { + ColumnLayout + { id: viewSettings property bool collapsed: false @@ -195,7 +210,8 @@ Item width: width } - Connections { + Connections + { target: UM.Preferences onPreferenceChanged: { @@ -212,18 +228,22 @@ Item } } - Repeater { + Repeater + { model: Cura.ExtrudersModel{} - CheckBox { + CheckBox + { id: extrudersModelCheckBox checked: viewSettings.extruder_opacities[index] > 0.5 || viewSettings.extruder_opacities[index] == undefined || viewSettings.extruder_opacities[index] == "" - onClicked: { + onClicked: + { viewSettings.extruder_opacities[index] = checked ? 1.0 : 0.0 UM.Preferences.setValue("layerview/extruder_opacities", viewSettings.extruder_opacities.join("|")); } visible: !UM.SimulationView.compatibilityMode enabled: index + 1 <= 4 - Rectangle { + Rectangle + { anchors.verticalCenter: parent.verticalCenter anchors.right: extrudersModelCheckBox.right width: UM.Theme.getSize("layerview_legend_size").width @@ -253,8 +273,10 @@ Item } } - Repeater { - model: ListModel { + Repeater + { + model: ListModel + { id: typesLegendModel Component.onCompleted: { @@ -285,13 +307,16 @@ Item } } - CheckBox { + CheckBox + { id: legendModelCheckBox checked: model.initialValue - onClicked: { + onClicked: + { UM.Preferences.setValue(model.preference, checked); } - Rectangle { + Rectangle + { anchors.verticalCenter: parent.verticalCenter anchors.right: legendModelCheckBox.right width: UM.Theme.getSize("layerview_legend_size").width @@ -320,18 +345,22 @@ Item } } - CheckBox { + CheckBox + { checked: viewSettings.only_show_top_layers - onClicked: { + onClicked: + { UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0); } text: catalog.i18nc("@label", "Only Show Top Layers") visible: UM.SimulationView.compatibilityMode style: UM.Theme.styles.checkbox } - CheckBox { + CheckBox + { checked: viewSettings.top_layer_count == 5 - onClicked: { + onClicked: + { UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1); } text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top") @@ -339,8 +368,10 @@ Item style: UM.Theme.styles.checkbox } - Repeater { - model: ListModel { + Repeater + { + model: ListModel + { id: typesLegendModelNoCheck Component.onCompleted: { @@ -355,11 +386,13 @@ Item } } - Label { + Label + { text: label visible: viewSettings.show_legend id: typesLegendModelLabel - Rectangle { + Rectangle + { anchors.verticalCenter: parent.verticalCenter anchors.right: typesLegendModelLabel.right width: UM.Theme.getSize("layerview_legend_size").width @@ -378,30 +411,37 @@ Item } // Text for the minimum, maximum and units for the feedrates and layer thickness - Item { + Item + { id: gradientLegend visible: viewSettings.show_gradient width: parent.width height: UM.Theme.getSize("layerview_row").height - anchors { + anchors + { topMargin: UM.Theme.getSize("slider_layerview_margin").height horizontalCenter: parent.horizontalCenter } - Label { + Label + { text: minText() anchors.left: parent.left color: UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") - function minText() { - if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) { + function minText() + { + if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) + { // Feedrate selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 2) { + if (UM.Preferences.getValue("layerview/layer_view_type") == 2) + { return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2) } // Layer thickness selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 3) { + if (UM.Preferences.getValue("layerview/layer_view_type") == 3) + { return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2) } } @@ -409,20 +449,25 @@ Item } } - Label { + Label + { text: unitsText() anchors.horizontalCenter: parent.horizontalCenter color: UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") - function unitsText() { - if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) { + function unitsText() + { + if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) + { // Feedrate selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 2) { + if (UM.Preferences.getValue("layerview/layer_view_type") == 2) + { return "mm/s" } // Layer thickness selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 3) { + if (UM.Preferences.getValue("layerview/layer_view_type") == 3) + { return "mm" } } @@ -430,20 +475,25 @@ Item } } - Label { + Label + { text: maxText() anchors.right: parent.right color: UM.Theme.getColor("setting_control_text") font: UM.Theme.getFont("default") - function maxText() { - if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) { + function maxText() + { + if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) + { // Feedrate selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 2) { + if (UM.Preferences.getValue("layerview/layer_view_type") == 2) + { return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2) } // Layer thickness selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 3) { + if (UM.Preferences.getValue("layerview/layer_view_type") == 3) + { return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2) } } @@ -453,7 +503,8 @@ Item } // Gradient colors for feedrate - Rectangle { // In QML 5.9 can be changed by LinearGradient + Rectangle + { // In QML 5.9 can be changed by LinearGradient // Invert values because then the bar is rotated 90 degrees id: feedrateGradient visible: viewSettings.show_feedrate_gradient @@ -463,20 +514,25 @@ Item border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") transform: Rotation {origin.x: 0; origin.y: 0; angle: 90} - gradient: Gradient { - GradientStop { + gradient: Gradient + { + GradientStop + { position: 0.000 color: Qt.rgba(1, 0.5, 0, 1) } - GradientStop { + GradientStop + { position: 0.625 color: Qt.rgba(0.375, 0.5, 0, 1) } - GradientStop { + GradientStop + { position: 0.75 color: Qt.rgba(0.25, 1, 0, 1) } - GradientStop { + GradientStop + { position: 1.0 color: Qt.rgba(0, 0, 1, 1) } @@ -484,7 +540,8 @@ Item } // Gradient colors for layer thickness (similar to parula colormap) - Rectangle { // In QML 5.9 can be changed by LinearGradient + Rectangle // In QML 5.9 can be changed by LinearGradient + { // Invert values because then the bar is rotated 90 degrees id: thicknessGradient visible: viewSettings.show_thickness_gradient @@ -494,24 +551,30 @@ Item border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") transform: Rotation {origin.x: 0; origin.y: 0; angle: 90} - gradient: Gradient { - GradientStop { + gradient: Gradient + { + GradientStop + { position: 0.000 color: Qt.rgba(1, 1, 0, 1) } - GradientStop { + GradientStop + { position: 0.25 color: Qt.rgba(1, 0.75, 0.25, 1) } - GradientStop { + GradientStop + { position: 0.5 color: Qt.rgba(0, 0.75, 0.5, 1) } - GradientStop { + GradientStop + { position: 0.75 color: Qt.rgba(0, 0.375, 0.75, 1) } - GradientStop { + GradientStop + { position: 1.0 color: Qt.rgba(0, 0, 0.5, 1) } @@ -520,19 +583,22 @@ Item } } - Item { + Item + { id: slidersBox width: parent.width visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity - anchors { + anchors + { top: parent.bottom topMargin: UM.Theme.getSize("slider_layerview_margin").height left: parent.left } - PathSlider { + PathSlider + { id: pathSlider height: UM.Theme.getSize("slider_handle").width @@ -553,25 +619,29 @@ Item rangeColor: UM.Theme.getColor("slider_groove_fill") // update values when layer data changes - Connections { + Connections + { target: UM.SimulationView onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath) onCurrentPathChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath) } // make sure the slider handlers show the correct value after switching views - Component.onCompleted: { + Component.onCompleted: + { pathSlider.setHandleValue(UM.SimulationView.currentPath) } } - LayerSlider { + LayerSlider + { id: layerSlider width: UM.Theme.getSize("slider_handle").width height: UM.Theme.getSize("layerview_menu_size").height - anchors { + anchors + { top: !UM.SimulationView.compatibilityMode ? pathSlider.bottom : parent.top topMargin: !UM.SimulationView.compatibilityMode ? UM.Theme.getSize("default_margin").height : 0 right: parent.right @@ -593,7 +663,8 @@ Item handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width // update values when layer data changes - Connections { + Connections + { target: UM.SimulationView onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer) onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer) @@ -601,45 +672,54 @@ Item } // make sure the slider handlers show the correct value after switching views - Component.onCompleted: { + Component.onCompleted: + { layerSlider.setLowerValue(UM.SimulationView.minimumLayer) layerSlider.setUpperValue(UM.SimulationView.currentLayer) } } // Play simulation button - Button { + Button + { id: playButton iconSource: "./resources/simulation_resume.svg" style: UM.Theme.styles.small_tool_button visible: !UM.SimulationView.compatibilityMode - anchors { + anchors + { verticalCenter: pathSlider.verticalCenter } property var status: 0 // indicates if it's stopped (0) or playing (1) - onClicked: { - switch(status) { - case 0: { + onClicked: + { + switch(status) + { + case 0: + { resumeSimulation() break } - case 1: { + case 1: + { pauseSimulation() break } } } - function pauseSimulation() { + function pauseSimulation() + { UM.SimulationView.setSimulationRunning(false) iconSource = "./resources/simulation_resume.svg" simulationTimer.stop() status = 0 } - function resumeSimulation() { + function resumeSimulation() + { UM.SimulationView.setSimulationRunning(true) iconSource = "./resources/simulation_pause.svg" simulationTimer.start() @@ -652,7 +732,8 @@ Item interval: 100 running: false repeat: true - onTriggered: { + onTriggered: + { var currentPath = UM.SimulationView.currentPath var numPaths = UM.SimulationView.numPaths var currentLayer = UM.SimulationView.currentLayer @@ -697,7 +778,8 @@ Item } } - FontMetrics { + FontMetrics + { id: fontMetrics font: UM.Theme.getFont("default") } diff --git a/plugins/SimulationView/plugin.json b/plugins/SimulationView/plugin.json index 0e7bec0626..93df98068f 100644 --- a/plugins/SimulationView/plugin.json +++ b/plugins/SimulationView/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides the Simulation view.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/SliceInfoPlugin/plugin.json b/plugins/SliceInfoPlugin/plugin.json index d1c643266b..939e5ff235 100644 --- a/plugins/SliceInfoPlugin/plugin.json +++ b/plugins/SliceInfoPlugin/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Submits anonymous slice info. Can be disabled through preferences.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/SolidView/plugin.json b/plugins/SolidView/plugin.json index 6d6bda96f0..e70ec224dd 100644 --- a/plugins/SolidView/plugin.json +++ b/plugins/SolidView/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides a normal solid mesh view.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/SupportEraser/SupportEraser.py b/plugins/SupportEraser/SupportEraser.py index 44d4831c04..0683c48635 100644 --- a/plugins/SupportEraser/SupportEraser.py +++ b/plugins/SupportEraser/SupportEraser.py @@ -25,10 +25,12 @@ from cura.Scene.BuildPlateDecorator import BuildPlateDecorator from UM.Settings.SettingInstance import SettingInstance +import numpy + class SupportEraser(Tool): def __init__(self): super().__init__() - self._shortcut_key = Qt.Key_G + self._shortcut_key = Qt.Key_E self._controller = self.getController() self._selection_pass = None @@ -96,8 +98,7 @@ class SupportEraser(Tool): node.setName("Eraser") node.setSelectable(True) - mesh = MeshBuilder() - mesh.addCube(10,10,10) + mesh = self._createCube(10) node.setMeshData(mesh.build()) active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate @@ -160,3 +161,28 @@ class SupportEraser(Tool): self._skip_press = False self._had_selection = has_selection + + def _createCube(self, size): + mesh = MeshBuilder() + + # Can't use MeshBuilder.addCube() because that does not get per-vertex normals + # Per-vertex normals require duplication of vertices + s = size / 2 + verts = [ # 6 faces with 4 corners each + [-s, -s, s], [-s, s, s], [ s, s, s], [ s, -s, s], + [-s, s, -s], [-s, -s, -s], [ s, -s, -s], [ s, s, -s], + [ s, -s, -s], [-s, -s, -s], [-s, -s, s], [ s, -s, s], + [-s, s, -s], [ s, s, -s], [ s, s, s], [-s, s, s], + [-s, -s, s], [-s, -s, -s], [-s, s, -s], [-s, s, s], + [ s, -s, -s], [ s, -s, s], [ s, s, s], [ s, s, -s] + ] + mesh.setVertices(numpy.asarray(verts, dtype=numpy.float32)) + + indices = [] + for i in range(0, 24, 4): # All 6 quads (12 triangles) + indices.append([i, i+2, i+1]) + indices.append([i, i+3, i+2]) + mesh.setIndices(numpy.asarray(indices, dtype=numpy.int32)) + + mesh.calculateNormals() + return mesh diff --git a/plugins/SupportEraser/plugin.json b/plugins/SupportEraser/plugin.json index 5ccb639913..7af35e0fb5 100644 --- a/plugins/SupportEraser/plugin.json +++ b/plugins/SupportEraser/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Creates an eraser mesh to block the printing of support in certain places", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/Toolbox/plugin.json b/plugins/Toolbox/plugin.json index 12d4042b6b..2557185524 100644 --- a/plugins/Toolbox/plugin.json +++ b/plugins/Toolbox/plugin.json @@ -2,6 +2,6 @@ "name": "Toolbox", "author": "Ultimaker B.V.", "version": "1.0.0", - "api": 4, + "api": 5, "description": "Find, manage and install new Cura packages." } diff --git a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml index 4978af6168..1efcde2110 100644 --- a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml +++ b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml @@ -29,6 +29,16 @@ Item anchors.topMargin: UM.Theme.getSize("default_margin").height width: parent.width frameVisible: false + + // Workaround for scroll issues (QTBUG-49652) + flickableItem.interactive: false + Component.onCompleted: + { + for (var i = 0; i < flickableItem.children.length; ++i) + { + flickableItem.children[i].enabled = false + } + } selectionMode: 0 model: packageData.supported_configs headerDelegate: Rectangle diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml index 392b867071..ebd4c006f8 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml @@ -114,7 +114,10 @@ Item else { toolbox.viewPage = "author" - toolbox.filterModelByProp("packages", "author_id", model.id) + toolbox.setFilters("packages", { + "author_id": model.id, + "type": "material" + }) } break default: diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml index 2ca0b522fe..15d1ae302c 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml @@ -105,8 +105,21 @@ Rectangle switch(toolbox.viewCategory) { case "material": - toolbox.viewPage = "author" - toolbox.filterModelByProp("packages", "author_name", model.name) + + // If model has a type, it must be a package + if (model.type !== undefined) + { + toolbox.viewPage = "detail" + toolbox.filterModelByProp("packages", "id", model.id) + } + else + { + toolbox.viewPage = "author" + toolbox.setFilters("packages", { + "author_id": model.id, + "type": "material" + }) + } break default: toolbox.viewPage = "detail" diff --git a/plugins/Toolbox/src/PackagesModel.py b/plugins/Toolbox/src/PackagesModel.py index 23aa639bde..8b9199b127 100644 --- a/plugins/Toolbox/src/PackagesModel.py +++ b/plugins/Toolbox/src/PackagesModel.py @@ -28,7 +28,7 @@ class PackagesModel(ListModel): self.addRoleName(Qt.UserRole + 11, "download_url") self.addRoleName(Qt.UserRole + 12, "last_updated") self.addRoleName(Qt.UserRole + 13, "is_bundled") - self.addRoleName(Qt.UserRole + 14, "is_enabled") + self.addRoleName(Qt.UserRole + 14, "is_active") self.addRoleName(Qt.UserRole + 15, "is_installed") # Scheduled pkgs are included in the model but should not be marked as actually installed self.addRoleName(Qt.UserRole + 16, "has_configs") self.addRoleName(Qt.UserRole + 17, "supported_configs") @@ -75,7 +75,7 @@ class PackagesModel(ListModel): "download_url": package["download_url"] if "download_url" in package else None, "last_updated": package["last_updated"] if "last_updated" in package else None, "is_bundled": package["is_bundled"] if "is_bundled" in package else False, - "is_enabled": package["is_enabled"] if "is_enabled" in package else False, + "is_active": package["is_active"] if "is_active" in package else False, "is_installed": package["is_installed"] if "is_installed" in package else False, "has_configs": has_configs, "supported_configs": configs_model, diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index a9d0bb03d1..c4205b8ed5 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -776,17 +776,25 @@ class Toolbox(QObject, Extension): # Filter Models: # -------------------------------------------------------------------------- @pyqtSlot(str, str, str) - def filterModelByProp(self, modelType: str, filterType: str, parameter: str): - if not self._models[modelType]: - Logger.log("w", "Toolbox: Couldn't filter %s model because it doesn't exist.", modelType) + def filterModelByProp(self, model_type: str, filter_type: str, parameter: str) -> None: + if not self._models[model_type]: + Logger.log("w", "Toolbox: Couldn't filter %s model because it doesn't exist.", model_type) return - self._models[modelType].setFilter({ filterType: parameter }) + self._models[model_type].setFilter({filter_type: parameter}) self.filterChanged.emit() - @pyqtSlot() - def removeFilters(self, modelType: str): - if not self._models[modelType]: - Logger.log("w", "Toolbox: Couldn't remove filters on %s model because it doesn't exist.", modelType) + @pyqtSlot(str, "QVariantMap") + def setFilters(self, model_type: str, filter_dict: dict) -> None: + if not self._models[model_type]: + Logger.log("w", "Toolbox: Couldn't filter %s model because it doesn't exist.", model_type) return - self._models[modelType].setFilter({}) + self._models[model_type].setFilter(filter_dict) + self.filterChanged.emit() + + @pyqtSlot(str) + def removeFilters(self, model_type: str) -> None: + if not self._models[model_type]: + Logger.log("w", "Toolbox: Couldn't remove filters on %s model because it doesn't exist.", model_type) + return + self._models[model_type].setFilter({}) self.filterChanged.emit() diff --git a/plugins/UFPWriter/UFPWriter.py b/plugins/UFPWriter/UFPWriter.py index aca293e25a..a85ee489cb 100644 --- a/plugins/UFPWriter/UFPWriter.py +++ b/plugins/UFPWriter/UFPWriter.py @@ -1,5 +1,6 @@ #Copyright (c) 2018 Ultimaker B.V. #Cura is released under the terms of the LGPLv3 or higher. +from typing import cast from Charon.VirtualFile import VirtualFile #To open UFP files. from Charon.OpenMode import OpenMode #To indicate that we want to write to UFP files. @@ -12,11 +13,15 @@ from UM.PluginRegistry import PluginRegistry #To get the g-code writer. from PyQt5.QtCore import QBuffer from cura.Snapshot import Snapshot +from cura.Utils.Threading import call_on_qt_thread + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") class UFPWriter(MeshWriter): def __init__(self): - super().__init__() + super().__init__(add_to_recent_files = False) self._snapshot = None Application.getInstance().getOutputDeviceManager().writeStarted.connect(self._createSnapshot) @@ -25,6 +30,11 @@ class UFPWriter(MeshWriter): Logger.log("d", "Creating thumbnail image...") self._snapshot = Snapshot.snapshot(width = 300, height = 300) + # This needs to be called on the main thread (Qt thread) because the serialization of material containers can + # trigger loading other containers. Because those loaded containers are QtObjects, they must be created on the + # Qt thread. The File read/write operations right now are executed on separated threads because they are scheduled + # by the Job class. + @call_on_qt_thread def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode): archive = VirtualFile() archive.openStream(stream, "application/x-ufp", OpenMode.WriteOnly) @@ -32,7 +42,11 @@ class UFPWriter(MeshWriter): #Store the g-code from the scene. archive.addContentType(extension = "gcode", mime_type = "text/x-gcode") gcode_textio = StringIO() #We have to convert the g-code into bytes. - PluginRegistry.getInstance().getPluginObject("GCodeWriter").write(gcode_textio, None) + gcode_writer = cast(MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter")) + success = gcode_writer.write(gcode_textio, None) + if not success: #Writing the g-code failed. Then I can also not write the gzipped g-code. + self.setInformation(gcode_writer.getInformation()) + return False gcode = archive.getStream("/3D/model.gcode") gcode.write(gcode_textio.getvalue().encode("UTF-8")) archive.addRelation(virtual_path = "/3D/model.gcode", relation_type = "http://schemas.ultimaker.org/package/2018/relationships/gcode") @@ -52,5 +66,50 @@ class UFPWriter(MeshWriter): else: Logger.log("d", "Thumbnail not created, cannot save it") + # Store the material. + application = Application.getInstance() + machine_manager = application.getMachineManager() + material_manager = application.getMaterialManager() + global_stack = machine_manager.activeMachine + + material_extension = "xml.fdm_material" + material_mime_type = "application/x-ultimaker-material-profile" + + try: + archive.addContentType(extension = material_extension, mime_type = material_mime_type) + except: + Logger.log("w", "The material extension: %s was already added", material_extension) + + added_materials = [] + for extruder_stack in global_stack.extruders.values(): + material = extruder_stack.material + material_file_name = material.getMetaData()["base_file"] + ".xml.fdm_material" + material_file_name = "/Materials/" + material_file_name + + #Same material cannot be added + if material_file_name in added_materials: + continue + + material_root_id = material.getMetaDataEntry("base_file") + material_group = material_manager.getMaterialGroup(material_root_id) + if material_group is None: + Logger.log("e", "Cannot find material container with root id [%s]", material_root_id) + return False + + material_container = material_group.root_material_node.getContainer() + try: + serialized_material = material_container.serialize() + except NotImplementedError: + Logger.log("e", "Unable serialize material container with root id: %s", material_root_id) + return False + + material_file = archive.getStream(material_file_name) + material_file.write(serialized_material.encode("UTF-8")) + archive.addRelation(virtual_path = material_file_name, + relation_type = "http://schemas.ultimaker.org/package/2018/relationships/material", + origin = "/3D/model.gcode") + + added_materials.append(material_file_name) + archive.close() return True diff --git a/plugins/UFPWriter/plugin.json b/plugins/UFPWriter/plugin.json index 7d10b89ad4..ab590353e0 100644 --- a/plugins/UFPWriter/plugin.json +++ b/plugins/UFPWriter/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides support for writing Ultimaker Format Packages.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/ClusterControlItem.qml b/plugins/UM3NetworkPrinting/ClusterControlItem.qml index b42515de51..5cf550955c 100644 --- a/plugins/UM3NetworkPrinting/ClusterControlItem.qml +++ b/plugins/UM3NetworkPrinting/ClusterControlItem.qml @@ -30,7 +30,12 @@ Component anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.right:parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width text: Cura.MachineManager.printerOutputDevices[0].name + elide: Text.ElideRight } Rectangle diff --git a/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml b/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml index 86bdaae0a5..0e86d55de8 100644 --- a/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml +++ b/plugins/UM3NetworkPrinting/ClusterMonitorItem.qml @@ -9,6 +9,7 @@ Component { Rectangle { + id: monitorFrame width: maximumWidth height: maximumHeight color: UM.Theme.getColor("viewport_background") @@ -103,5 +104,15 @@ Component visible: OutputDevice.activePrinter != null anchors.fill:parent } + + onVisibleChanged: + { + if (!monitorFrame.visible) + { + // After switching the Tab ensure that active printer is Null, the video stream image + // might be active + OutputDevice.setActivePrinter(null) + } + } } } diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 84e0a66170..e85961f619 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -113,7 +113,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): machine_file_formats = global_stack.getMetaDataEntry("file_formats").split(";") machine_file_formats = [file_type.strip() for file_type in machine_file_formats] #Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format. - if "application/x-ufp" not in machine_file_formats and self.printerType == "ultimaker3" and Version(self.firmwareVersion) >= Version("4.4"): + if "application/x-ufp" not in machine_file_formats and Version(self.firmwareVersion) >= Version("4.4"): machine_file_formats = ["application/x-ufp"] + machine_file_formats # Take the intersection between file_formats and machine_file_formats. @@ -590,4 +590,4 @@ def findByKey(list: List[Union[PrintJobOutputModel, PrinterOutputModel]], key: s for item in list: if item.key == key: return item - return None \ No newline at end of file + return None diff --git a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py index 707443b9ea..4a0319cafc 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py @@ -19,5 +19,5 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def setJobState(self, job: "PrintJobOutputModel", state: str): data = "{\"action\": \"%s\"}" % state - self._output_device.put("print_jobs/%s/action" % job.key, data, onFinished=None) + self._output_device.put("print_jobs/%s/action" % job.key, data, on_finished=None) diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index 8ecbe016f1..b5b80a3010 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -299,11 +299,11 @@ Cura.MachineAction } else if (base.selectedDevice.clusterSize === 0) { - return catalog.i18nc("@label", "This printer is not set up to host a group of Ultimaker 3 printers."); + return catalog.i18nc("@label", "This printer is not set up to host a group of printers."); } else { - return catalog.i18nc("@label", "This printer is the host for a group of %1 Ultimaker 3 printers.".arg(base.selectedDevice.clusterSize)); + return catalog.i18nc("@label", "This printer is the host for a group of %1 printers.".arg(base.selectedDevice.clusterSize)); } } @@ -349,11 +349,6 @@ Cura.MachineAction addressField.focus = true; } - onAccepted: - { - manager.setManualDevice(printerKey, addressText) - } - Column { anchors.fill: parent spacing: UM.Theme.getSize("default_margin").height @@ -369,7 +364,6 @@ Cura.MachineAction { id: addressField width: parent.width - maximumLength: 40 validator: RegExpValidator { regExp: /[a-zA-Z0-9\.\-\_]*/ @@ -393,7 +387,7 @@ Cura.MachineAction text: catalog.i18nc("@action:button", "OK") onClicked: { - manualPrinterDialog.accept() + manager.setManualDevice(manualPrinterDialog.printerKey, manualPrinterDialog.addressText) manualPrinterDialog.hide() } enabled: manualPrinterDialog.addressText.trim() != "" diff --git a/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py b/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py index f38c1a1c7a..8617b5b2ff 100644 --- a/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py @@ -165,7 +165,7 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): file_name = "none.xml" - self.postForm("materials", "form-data; name=\"file\";filename=\"%s\"" % file_name, xml_data.encode(), onFinished=None) + self.postForm("materials", "form-data; name=\"file\";filename=\"%s\"" % file_name, xml_data.encode(), on_finished=None) except NotImplementedError: # If the material container is not the most "generic" one it can't be serialized an will raise a @@ -270,7 +270,7 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): file_name = "%s.gcode.gz" % CuraApplication.getInstance().getPrintInformation().jobName self.postForm("print_job", "form-data; name=\"file\";filename=\"%s\"" % file_name, compressed_gcode, - onFinished=self._onPostPrintJobFinished) + on_finished=self._onPostPrintJobFinished) return @@ -381,8 +381,8 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): self._checkAuthentication() # We don't need authentication for requesting info, so we can go right ahead with requesting this. - self.get("printer", onFinished=self._onGetPrinterDataFinished) - self.get("print_job", onFinished=self._onGetPrintJobFinished) + self.get("printer", on_finished=self._onGetPrinterDataFinished) + self.get("print_job", on_finished=self._onGetPrintJobFinished) def _resetAuthenticationRequestedMessage(self): if self._authentication_requested_message: @@ -404,7 +404,7 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): def _verifyAuthentication(self): Logger.log("d", "Attempting to verify authentication") # This will ensure that the "_onAuthenticationRequired" is triggered, which will setup the authenticator. - self.get("auth/verify", onFinished=self._onVerifyAuthenticationCompleted) + self.get("auth/verify", on_finished=self._onVerifyAuthenticationCompleted) def _onVerifyAuthenticationCompleted(self, reply): status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) @@ -426,7 +426,7 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): def _checkAuthentication(self): Logger.log("d", "Checking if authentication is correct for id %s and key %s", self._authentication_id, self._getSafeAuthKey()) - self.get("auth/check/" + str(self._authentication_id), onFinished=self._onCheckAuthenticationFinished) + self.get("auth/check/" + str(self._authentication_id), on_finished=self._onCheckAuthenticationFinished) def _onCheckAuthenticationFinished(self, reply): if str(self._authentication_id) not in reply.url().toString(): @@ -502,7 +502,7 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): self.post("auth/request", json.dumps({"application": "Cura-" + CuraApplication.getInstance().getVersion(), "user": self._getUserName()}).encode(), - onFinished=self._onRequestAuthenticationFinished) + on_finished=self._onRequestAuthenticationFinished) self.setAuthenticationState(AuthState.AuthenticationRequested) diff --git a/plugins/UM3NetworkPrinting/LegacyUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/LegacyUM3PrinterOutputController.py index b12a31b6cf..702b48ce15 100644 --- a/plugins/UM3NetworkPrinting/LegacyUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/LegacyUM3PrinterOutputController.py @@ -31,11 +31,11 @@ class LegacyUM3PrinterOutputController(PrinterOutputController): def setJobState(self, job: "PrintJobOutputModel", state: str): data = "{\"target\": \"%s\"}" % state - self._output_device.put("print_job/state", data, onFinished=None) + self._output_device.put("print_job/state", data, on_finished=None) def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): data = str(temperature) - self._output_device.put("printer/bed/temperature/target", data, onFinished=self._onPutBedTemperatureCompleted) + self._output_device.put("printer/bed/temperature/target", data, on_finished=self._onPutBedTemperatureCompleted) def _onPutBedTemperatureCompleted(self, reply): if Version(self._preheat_printer.firmwareVersion) < Version("3.5.92"): @@ -51,10 +51,10 @@ class LegacyUM3PrinterOutputController(PrinterOutputController): new_y = head_pos.y + y new_z = head_pos.z + z data = "{\n\"x\":%s,\n\"y\":%s,\n\"z\":%s\n}" %(new_x, new_y, new_z) - self._output_device.put("printer/heads/0/position", data, onFinished=None) + self._output_device.put("printer/heads/0/position", data, on_finished=None) def homeBed(self, printer): - self._output_device.put("printer/heads/0/position/z", "0", onFinished=None) + self._output_device.put("printer/heads/0/position/z", "0", on_finished=None) def _onPreheatBedTimerFinished(self): self.setTargetBedTemperature(self._preheat_printer, 0) @@ -89,7 +89,7 @@ class LegacyUM3PrinterOutputController(PrinterOutputController): printer.updateIsPreheating(True) return - self._output_device.put("printer/bed/pre_heat", data, onFinished = self._onPutPreheatBedCompleted) + self._output_device.put("printer/bed/pre_heat", data, on_finished = self._onPutPreheatBedCompleted) printer.updateIsPreheating(True) self._preheat_request_in_progress = True diff --git a/plugins/UM3NetworkPrinting/PrintWindow.qml b/plugins/UM3NetworkPrinting/PrintWindow.qml index 0553db0eb2..9793b218fc 100644 --- a/plugins/UM3NetworkPrinting/PrintWindow.qml +++ b/plugins/UM3NetworkPrinting/PrintWindow.qml @@ -26,6 +26,10 @@ UM.Dialog { resetPrintersModel() } + else + { + OutputDevice.cancelPrintSelection() + } } title: catalog.i18nc("@title:window", "Print over network") diff --git a/plugins/UM3NetworkPrinting/PrinterVideoStream.qml b/plugins/UM3NetworkPrinting/PrinterVideoStream.qml index 7f7b2ad546..68758e095e 100644 --- a/plugins/UM3NetworkPrinting/PrinterVideoStream.qml +++ b/plugins/UM3NetworkPrinting/PrinterVideoStream.qml @@ -16,9 +16,9 @@ Item MouseArea { - anchors.fill: parent - onClicked: OutputDevice.setActivePrinter(null) - z: 0 + anchors.fill: parent + onClicked: OutputDevice.setActivePrinter(null) + z: 0 } Button @@ -28,7 +28,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").width anchors.right: cameraImage.right - // TODO: Harcoded sizes + // TODO: Hardcoded sizes width: 20 * screenScaleFactor height: 20 * screenScaleFactor @@ -89,9 +89,11 @@ Item MouseArea { - anchors.fill: cameraImage - onClicked: { /* no-op */ } - z: 1 + anchors.fill: cameraImage + onClicked: + { + OutputDevice.setActivePrinter(null) + } + z: 1 } - } diff --git a/plugins/UM3NetworkPrinting/SendMaterialJob.py b/plugins/UM3NetworkPrinting/SendMaterialJob.py index 0ac38843a1..8491e79c29 100644 --- a/plugins/UM3NetworkPrinting/SendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/SendMaterialJob.py @@ -39,12 +39,12 @@ class SendMaterialJob(Job): try: remote_materials_list = json.loads(remote_materials_list) except json.JSONDecodeError: - Logger.log("e", "Current material storage on printer was a corrupted reply.") + Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.") return try: remote_materials_by_guid = {material["guid"]: material for material in remote_materials_list} #Index by GUID. except KeyError: - Logger.log("e", "Current material storage on printer was an invalid reply (missing GUIDs).") + Logger.log("e", "Request material storage on printer: Printer's answer was missing GUIDs.") return container_registry = ContainerRegistry.getInstance() diff --git a/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py index 3644bbf056..f4749a6747 100644 --- a/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/UM3OutputDevicePlugin.py @@ -198,7 +198,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): has_cluster_capable_firmware = Version(system_info["firmware"]) > self._min_cluster_version instance_name = "manual:%s" % address properties = { - b"name": system_info["name"].encode("utf-8"), + b"name": (system_info["name"] + " (manual)").encode("utf-8"), b"address": address.encode("utf-8"), b"firmware_version": system_info["firmware"].encode("utf-8"), b"manual": b"true", diff --git a/plugins/UM3NetworkPrinting/plugin.json b/plugins/UM3NetworkPrinting/plugin.json index e7b59fadd6..d415338374 100644 --- a/plugins/UM3NetworkPrinting/plugin.json +++ b/plugins/UM3NetworkPrinting/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "description": "Manages network connections to Ultimaker 3 printers.", "version": "1.0.0", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/USBPrinting/AutoDetectBaudJob.py b/plugins/USBPrinting/AutoDetectBaudJob.py index 4635946928..f8af61c567 100644 --- a/plugins/USBPrinting/AutoDetectBaudJob.py +++ b/plugins/USBPrinting/AutoDetectBaudJob.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Job import Job @@ -21,7 +21,6 @@ class AutoDetectBaudJob(Job): def run(self): Logger.log("d", "Auto detect baud rate started.") - timeout = 3 wait_response_timeouts = [3, 15, 30] wait_bootloader_times = [1.5, 5, 15] write_timeout = 3 @@ -52,7 +51,7 @@ class AutoDetectBaudJob(Job): if serial is None: try: serial = Serial(str(self._serial_port), baud_rate, timeout = read_timeout, writeTimeout = write_timeout) - except SerialException as e: + except SerialException: Logger.logException("w", "Unable to create serial") continue else: @@ -72,7 +71,7 @@ class AutoDetectBaudJob(Job): while timeout_time > time(): line = serial.readline() - if b"ok T:" in line: + if b"ok " in line and b"T:" in line: successful_responses += 1 if successful_responses >= 3: self.setResult(baud_rate) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 109888a15d..45b566fcab 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -15,7 +15,7 @@ from cura.PrinterOutput.GenericOutputController import GenericOutputController from .AutoDetectBaudJob import AutoDetectBaudJob from .avr_isp import stk500v2, intelHex -from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty +from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty, QUrl from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event @@ -146,8 +146,11 @@ class USBPrinterOutputDevice(PrinterOutputDevice): @pyqtSlot(str) def updateFirmware(self, file): - # the file path is qurl encoded. - self._firmware_location = file.replace("file://", "") + # the file path could be url-encoded. + if file.startswith("file://"): + self._firmware_location = QUrl(file).toLocalFile() + else: + self._firmware_location = file self.showFirmwareInterface() self.setFirmwareUpdateState(FirmwareUpdateState.updating) self._update_firmware_thread.start() @@ -323,7 +326,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): if self._firmware_name is None: self.sendCommand("M115") - if b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed + if (b"ok " in line and b"T:" in line) or b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line) # Update all temperature values matched_extruder_nrs = [] diff --git a/plugins/USBPrinting/plugin.json b/plugins/USBPrinting/plugin.json index 27e07c45b2..3484c8a48a 100644 --- a/plugins/USBPrinting/plugin.json +++ b/plugins/USBPrinting/plugin.json @@ -2,7 +2,7 @@ "name": "USB printing", "author": "Ultimaker B.V.", "version": "1.0.0", - "api": 4, + "api": 5, "description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.", "i18n-catalog": "cura" } diff --git a/plugins/UltimakerMachineActions/plugin.json b/plugins/UltimakerMachineActions/plugin.json index 57b3e6bc8f..b60c7df88e 100644 --- a/plugins/UltimakerMachineActions/plugin.json +++ b/plugins/UltimakerMachineActions/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.).", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/UserAgreement/plugin.json b/plugins/UserAgreement/plugin.json index b10abc5640..50a2aa0441 100644 --- a/plugins/UserAgreement/plugin.json +++ b/plugins/UserAgreement/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Ask the user once if he/she agrees with our license.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json b/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json index 79115f931e..463fcdc941 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 2.1 to Cura 2.2.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json b/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json index d213042ad2..e7a0b1c559 100644 --- a/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 2.2 to Cura 2.4.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json b/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json index 759b6368fd..3029539887 100644 --- a/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 2.5 to Cura 2.6.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json b/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json index 3c3d7fff8c..225da67235 100644 --- a/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 2.6 to Cura 2.7.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json b/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json index 3df84ff7e6..9a139851ec 100644 --- a/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 2.7 to Cura 3.0.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json b/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json index d80b820976..cf42b3f6cd 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 3.0 to Cura 3.1.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json index fbce09c807..f9cc968dae 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 3.2 to Cura 3.3.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json b/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json index 164b79d504..f5ba7235d1 100644 --- a/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 3.3 to Cura 3.4.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade34to40/VersionUpgrade34to40.py b/plugins/VersionUpgrade/VersionUpgrade34to40/VersionUpgrade34to40.py index 83609206ef..a61aae06bb 100644 --- a/plugins/VersionUpgrade/VersionUpgrade34to40/VersionUpgrade34to40.py +++ b/plugins/VersionUpgrade/VersionUpgrade34to40/VersionUpgrade34to40.py @@ -8,6 +8,9 @@ from UM.VersionUpgrade import VersionUpgrade deleted_settings = {"prime_tower_wall_thickness", "dual_pre_wipe", "prime_tower_purge_volume"} +changed_settings = {'retraction_combing': 'noskin'} +updated_settings = {'retraction_combing': 'infill'} + _RENAMED_MATERIAL_PROFILES = { "dsm_arnitel2045_175_cartesio_0.25_mm": "dsm_arnitel2045_175_cartesio_0.25mm_thermoplastic_extruder", "dsm_arnitel2045_175_cartesio_0.4_mm": "dsm_arnitel2045_175_cartesio_0.4mm_thermoplastic_extruder", @@ -127,6 +130,13 @@ class VersionUpgrade34to40(VersionUpgrade): continue del parser["values"][deleted_setting] + for setting_key in changed_settings: + if setting_key not in parser["values"]: + continue + + if parser["values"][setting_key] == changed_settings[setting_key]: + parser["values"][setting_key] = updated_settings[setting_key] + result = io.StringIO() parser.write(result) return [filename], [result.getvalue()] diff --git a/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json b/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json index 1059ca3e57..c07ae31c0a 100644 --- a/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Upgrades configurations from Cura 3.4 to Cura 4.0.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/X3DReader/plugin.json b/plugins/X3DReader/plugin.json index f18c7f033d..9ee09e43df 100644 --- a/plugins/X3DReader/plugin.json +++ b/plugins/X3DReader/plugin.json @@ -3,6 +3,6 @@ "author": "Seva Alekseyev", "version": "0.5.0", "description": "Provides support for reading X3D files.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/XRayView/plugin.json b/plugins/XRayView/plugin.json index 4e89690c13..576dec4656 100644 --- a/plugins/XRayView/plugin.json +++ b/plugins/XRayView/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides the X-Ray view.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index eac6646197..7d9b2aacc3 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -6,21 +6,22 @@ import io import json #To parse the product-to-id mapping file. import os.path #To find the product-to-id mapping. import sys -from typing import Any, Dict, List, Optional, cast +from typing import Any, Dict, List, Optional, Tuple, cast import xml.etree.ElementTree as ET -from typing import Dict -from typing import Iterator from UM.Resources import Resources from UM.Logger import Logger -from cura.CuraApplication import CuraApplication import UM.Dictionary from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerRegistry import ContainerRegistry from UM.ConfigurationErrorMessage import ConfigurationErrorMessage +from cura.CuraApplication import CuraApplication +from cura.Machines.VariantType import VariantType + from .XmlMaterialValidator import XmlMaterialValidator + ## Handles serializing and deserializing material containers from an XML file class XmlMaterialProfile(InstanceContainer): CurrentFdmMaterialVersion = "1.3" @@ -269,7 +270,6 @@ class XmlMaterialProfile(InstanceContainer): buildplate_dict = {} # type: Dict[str, Any] for variant_name, variant_dict in machine_variant_map[definition_id].items(): variant_type = variant_dict["variant_node"].metadata["hardware_type"] - from cura.Machines.VariantManager import VariantType variant_type = VariantType(variant_type) if variant_type == VariantType.NOZZLE: # The hotend identifier is not the containers name, but its "name". @@ -693,74 +693,38 @@ class XmlMaterialProfile(InstanceContainer): if buildplate_id is None: continue - from cura.Machines.VariantManager import VariantType variant_manager = CuraApplication.getInstance().getVariantManager() variant_node = variant_manager.getVariantNode(machine_id, buildplate_id, variant_type = VariantType.BUILD_PLATE) if not variant_node: continue - buildplate_compatibility = machine_compatibility - buildplate_recommended = machine_compatibility - settings = buildplate.iterfind("./um:setting", self.__namespaces) - for entry in settings: - key = entry.get("key") - if key in self.__unmapped_settings: - if key == "hardware compatible": - buildplate_compatibility = self._parseCompatibleValue(entry.text) - elif key == "hardware recommended": - buildplate_recommended = self._parseCompatibleValue(entry.text) - else: - Logger.log("d", "Unsupported material setting %s", key) + _, buildplate_unmapped_settings_dict = self._getSettingsDictForNode(buildplate) + + buildplate_compatibility = buildplate_unmapped_settings_dict.get("hardware compatible", + machine_compatibility) + buildplate_recommended = buildplate_unmapped_settings_dict.get("hardware recommended", + machine_compatibility) buildplate_map["buildplate_compatible"][buildplate_id] = buildplate_compatibility buildplate_map["buildplate_recommended"][buildplate_id] = buildplate_recommended hotends = machine.iterfind("./um:hotend", self.__namespaces) for hotend in hotends: - # The "id" field for hotends in material profiles are actually + # The "id" field for hotends in material profiles is actually name hotend_name = hotend.get("id") if hotend_name is None: continue variant_manager = CuraApplication.getInstance().getVariantManager() - variant_node = variant_manager.getVariantNode(machine_id, hotend_name) + variant_node = variant_manager.getVariantNode(machine_id, hotend_name, VariantType.NOZZLE) if not variant_node: continue - hotend_compatibility = machine_compatibility - hotend_setting_values = {} - settings = hotend.iterfind("./um:setting", self.__namespaces) - for entry in settings: - key = entry.get("key") - if key in self.__material_settings_setting_map: - if key == "processing temperature graph": #This setting has no setting text but subtags. - graph_nodes = entry.iterfind("./um:point", self.__namespaces) - graph_points = [] - for graph_node in graph_nodes: - flow = float(graph_node.get("flow")) - temperature = float(graph_node.get("temperature")) - graph_points.append([flow, temperature]) - hotend_setting_values[self.__material_settings_setting_map[key]] = str(graph_points) - else: - hotend_setting_values[self.__material_settings_setting_map[key]] = entry.text - elif key in self.__unmapped_settings: - if key == "hardware compatible": - hotend_compatibility = self._parseCompatibleValue(entry.text) - else: - Logger.log("d", "Unsupported material setting %s", key) - - # Add namespaced Cura-specific settings - settings = hotend.iterfind("./cura:setting", self.__namespaces) - for entry in settings: - value = entry.text - if value.lower() == "yes": - value = True - elif value.lower() == "no": - value = False - key = entry.get("key") - hotend_setting_values[key] = value + hotend_mapped_settings, hotend_unmapped_settings = self._getSettingsDictForNode(hotend) + hotend_compatibility = hotend_unmapped_settings.get("hardware compatible", machine_compatibility) + # Generate container ID for the hotend-specific material container new_hotend_specific_material_id = self.getId() + "_" + machine_id + "_" + hotend_name.replace(" ", "_") # Same as machine compatibility, keep the derived material containers consistent with the parent material @@ -785,7 +749,7 @@ class XmlMaterialProfile(InstanceContainer): new_hotend_material.getMetaData()["buildplate_recommended"] = buildplate_map["buildplate_recommended"] cached_hotend_setting_properties = cached_machine_setting_properties.copy() - cached_hotend_setting_properties.update(hotend_setting_values) + cached_hotend_setting_properties.update(hotend_mapped_settings) new_hotend_material.setCachedValues(cached_hotend_setting_properties) @@ -794,6 +758,61 @@ class XmlMaterialProfile(InstanceContainer): if is_new_material: containers_to_add.append(new_hotend_material) + # + # Build plates in hotend + # + buildplates = hotend.iterfind("./um:buildplate", self.__namespaces) + for buildplate in buildplates: + # The "id" field for buildplate in material profiles is actually name + buildplate_name = buildplate.get("id") + if buildplate_name is None: + continue + + variant_manager = CuraApplication.getInstance().getVariantManager() + variant_node = variant_manager.getVariantNode(machine_id, buildplate_name, VariantType.BUILD_PLATE) + if not variant_node: + continue + + buildplate_mapped_settings, buildplate_unmapped_settings = self._getSettingsDictForNode(buildplate) + buildplate_compatibility = buildplate_unmapped_settings.get("hardware compatible", + buildplate_map["buildplate_compatible"]) + buildplate_recommended = buildplate_unmapped_settings.get("hardware recommended", + buildplate_map["buildplate_recommended"]) + + # Generate container ID for the hotend-and-buildplate-specific material container + new_hotend_and_buildplate_specific_material_id = new_hotend_specific_material_id + "_" + buildplate_name.replace(" ", "_") + + # Same as machine compatibility, keep the derived material containers consistent with the parent material + if ContainerRegistry.getInstance().isLoaded(new_hotend_and_buildplate_specific_material_id): + new_hotend_and_buildplate_material = ContainerRegistry.getInstance().findContainers(id = new_hotend_and_buildplate_specific_material_id)[0] + is_new_material = False + else: + new_hotend_and_buildplate_material = XmlMaterialProfile(new_hotend_and_buildplate_specific_material_id) + is_new_material = True + + new_hotend_and_buildplate_material.setMetaData(copy.deepcopy(new_hotend_material.getMetaData())) + new_hotend_and_buildplate_material.getMetaData()["id"] = new_hotend_and_buildplate_specific_material_id + new_hotend_and_buildplate_material.getMetaData()["name"] = self.getName() + new_hotend_and_buildplate_material.getMetaData()["variant_name"] = hotend_name + new_hotend_and_buildplate_material.getMetaData()["buildplate_name"] = buildplate_name + new_hotend_and_buildplate_material.setDefinition(machine_id) + # Don't use setMetadata, as that overrides it for all materials with same base file + new_hotend_and_buildplate_material.getMetaData()["compatible"] = buildplate_compatibility + new_hotend_and_buildplate_material.getMetaData()["machine_manufacturer"] = machine_manufacturer + new_hotend_and_buildplate_material.getMetaData()["definition"] = machine_id + new_hotend_and_buildplate_material.getMetaData()["buildplate_compatible"] = buildplate_compatibility + new_hotend_and_buildplate_material.getMetaData()["buildplate_recommended"] = buildplate_recommended + + cached_hotend_and_buildplate_setting_properties = cached_hotend_setting_properties.copy() + cached_hotend_and_buildplate_setting_properties.update(buildplate_mapped_settings) + + new_hotend_and_buildplate_material.setCachedValues(cached_hotend_and_buildplate_setting_properties) + + new_hotend_and_buildplate_material._dirty = False + + if is_new_material: + containers_to_add.append(new_hotend_and_buildplate_material) + # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue break @@ -801,6 +820,54 @@ class XmlMaterialProfile(InstanceContainer): for container_to_add in containers_to_add: ContainerRegistry.getInstance().addContainer(container_to_add) + @classmethod + def _getSettingsDictForNode(cls, node) -> Tuple[dict, dict]: + node_mapped_settings_dict = dict() + node_unmapped_settings_dict = dict() + + # Fetch settings in the "um" namespace + um_settings = node.iterfind("./um:setting", cls.__namespaces) + for um_setting_entry in um_settings: + setting_key = um_setting_entry.get("key") + + # Mapped settings + if setting_key in cls.__material_settings_setting_map: + if setting_key == "processing temperature graph": # This setting has no setting text but subtags. + graph_nodes = um_setting_entry.iterfind("./um:point", cls.__namespaces) + graph_points = [] + for graph_node in graph_nodes: + flow = float(graph_node.get("flow")) + temperature = float(graph_node.get("temperature")) + graph_points.append([flow, temperature]) + node_mapped_settings_dict[cls.__material_settings_setting_map[setting_key]] = str( + graph_points) + else: + node_mapped_settings_dict[cls.__material_settings_setting_map[setting_key]] = um_setting_entry.text + + # Unmapped settings + elif setting_key in cls.__unmapped_settings: + if setting_key in ("hardware compatible", "hardware recommended"): + node_unmapped_settings_dict[setting_key] = cls._parseCompatibleValue(um_setting_entry.text) + + # Unknown settings + else: + Logger.log("w", "Unsupported material setting %s", setting_key) + + # Fetch settings in the "cura" namespace + cura_settings = node.iterfind("./cura:setting", cls.__namespaces) + for cura_setting_entry in cura_settings: + value = cura_setting_entry.text + if value.lower() == "yes": + value = True + elif value.lower() == "no": + value = False + key = cura_setting_entry.get("key") + + # Cura settings are all mapped + node_mapped_settings_dict[key] = value + + return node_mapped_settings_dict, node_unmapped_settings_dict + @classmethod def deserializeMetadata(cls, serialized: str, container_id: str) -> List[Dict[str, Any]]: result_metadata = [] #All the metadata that we found except the base (because the base is returned). @@ -983,6 +1050,36 @@ class XmlMaterialProfile(InstanceContainer): result_metadata.append(new_hotend_material_metadata) + # + # Buildplates in Hotends + # + buildplates = hotend.iterfind("./um:buildplate", cls.__namespaces) + for buildplate in buildplates: + # The "id" field for buildplate in material profiles is actually name + buildplate_name = buildplate.get("id") + if buildplate_name is None: + continue + + buildplate_mapped_settings, buildplate_unmapped_settings = cls._getSettingsDictForNode(buildplate) + buildplate_compatibility = buildplate_unmapped_settings.get("hardware compatible", + buildplate_map["buildplate_compatible"]) + buildplate_recommended = buildplate_unmapped_settings.get("hardware recommended", + buildplate_map["buildplate_recommended"]) + + # Generate container ID for the hotend-and-buildplate-specific material container + new_hotend_and_buildplate_specific_material_id = new_hotend_specific_material_id + "_" + buildplate_name.replace( + " ", "_") + + new_hotend_and_buildplate_material_metadata = {} + new_hotend_and_buildplate_material_metadata.update(new_hotend_material_metadata) + new_hotend_and_buildplate_material_metadata["id"] = new_hotend_and_buildplate_specific_material_id + new_hotend_and_buildplate_material_metadata["buildplate_name"] = buildplate_name + new_hotend_and_buildplate_material_metadata["compatible"] = buildplate_compatibility + new_hotend_and_buildplate_material_metadata["buildplate_compatible"] = buildplate_compatibility + new_hotend_and_buildplate_material_metadata["buildplate_recommended"] = buildplate_recommended + + result_metadata.append(new_hotend_and_buildplate_material_metadata) + # there is only one ID for a machine. Once we have reached here, it means we have already found # a workable ID for that machine, so there is no need to continue break diff --git a/plugins/XmlMaterialProfile/plugin.json b/plugins/XmlMaterialProfile/plugin.json index 17056dcb3e..4b2901c375 100644 --- a/plugins/XmlMaterialProfile/plugin.json +++ b/plugins/XmlMaterialProfile/plugin.json @@ -3,6 +3,6 @@ "author": "Ultimaker B.V.", "version": "1.0.0", "description": "Provides capabilities to read and write XML-based material profiles.", - "api": 4, + "api": 5, "i18n-catalog": "cura" } diff --git a/resources/bundled_packages.json b/resources/bundled_packages.json index 6d9b9d1a95..d216415921 100644 --- a/resources/bundled_packages.json +++ b/resources/bundled_packages.json @@ -662,6 +662,23 @@ } } }, + "VersionUpgrade34to40": { + "package_info": { + "package_id": "VersionUpgrade34to40", + "package_type": "plugin", + "display_name": "Version Upgrade 3.4 to 4.0", + "description": "Upgrades configurations from Cura 3.4 to Cura 4.0.", + "package_version": "1.0.0", + "sdk_version": 4, + "website": "https://ultimaker.com", + "author": { + "author_id": "Ultimaker", + "display_name": "Ultimaker B.V.", + "email": "plugins@ultimaker.com", + "website": "https://ultimaker.com" + } + } + }, "X3DReader": { "package_info": { "package_id": "X3DReader", @@ -1366,277 +1383,5 @@ "website": "https://www.vellemanprojects.eu" } } - }, - "ConsoleLogger": { - "package_info": { - "package_id": "ConsoleLogger", - "package_type": "plugin", - "display_name": "Console Logger", - "description": "Outputs log information to the console.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "OBJReader": { - "package_info": { - "package_id": "OBJReader", - "package_type": "plugin", - "display_name": "Wavefront OBJ Reader", - "description": "Makes it possible to read Wavefront OBJ files.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "OBJWriter": { - "package_info": { - "package_id": "OBJWriter", - "package_type": "plugin", - "display_name": "Wavefront OBJ Writer", - "description": "Makes it possible to write Wavefront OBJ files.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "STLReader": { - "package_info": { - "package_id": "STLReader", - "package_type": "plugin", - "display_name": "STL Reader", - "description": "Provides support for reading STL files.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "STLWriter": { - "package_info": { - "package_id": "STLWriter", - "package_type": "plugin", - "display_name": "STL Writer", - "description": "Provides support for writing STL files.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "FileLogger": { - "package_info": { - "package_id": "FileLogger", - "package_type": "plugin", - "display_name": "File Logger", - "description": "Outputs log information to a file in your settings folder.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "LocalContainerProvider": { - "package_info": { - "package_id": "LocalContainerProvider", - "package_type": "plugin", - "display_name": "Local Container Provider", - "description": "Provides built-in setting containers that come with the installation of the application.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "LocalFileOutputDevice": { - "package_info": { - "package_id": "LocalFileOutputDevice", - "package_type": "plugin", - "display_name": "Local File Output Device", - "description": "Enables saving to local files.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "CameraTool": { - "package_info": { - "package_id": "CameraTool", - "package_type": "plugin", - "display_name": "Camera Tool", - "description": "Provides the tool to manipulate the camera.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "MirrorTool": { - "package_info": { - "package_id": "MirrorTool", - "package_type": "plugin", - "display_name": "Mirror Tool", - "description": "Provides the Mirror tool.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "RotateTool": { - "package_info": { - "package_id": "RotateTool", - "package_type": "plugin", - "display_name": "Rotate Tool", - "description": "Provides the Rotate tool.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "ScaleTool": { - "package_info": { - "package_id": "ScaleTool", - "package_type": "plugin", - "display_name": "Scale Tool", - "description": "Provides the Scale tool.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "SelectionTool": { - "package_info": { - "package_id": "SelectionTool", - "package_type": "plugin", - "display_name": "Selection Tool", - "description": "Provides the Selection tool.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "TranslateTool": { - "package_info": { - "package_id": "TranslateTool", - "package_type": "plugin", - "display_name": "Move Tool", - "description": "Provides the Move tool.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "UpdateChecker": { - "package_info": { - "package_id": "UpdateChecker", - "package_type": "plugin", - "display_name": "Update Checker", - "description": "Checks for updates of the software.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, - "SimpleView": { - "package_info": { - "package_id": "SimpleView", - "package_type": "plugin", - "display_name": "Simple View", - "description": "Provides a simple solid mesh view.", - "package_version": "1.0.0", - "sdk_version": 4, - "website": "https://ultimaker.com", - "author": { - "author_id": "Ultimaker", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } } } diff --git a/resources/definitions/dagoma_discoeasy200.def.json b/resources/definitions/dagoma_discoeasy200.def.json index bf1e43ccea..89d94ff6b7 100644 --- a/resources/definitions/dagoma_discoeasy200.def.json +++ b/resources/definitions/dagoma_discoeasy200.def.json @@ -9,6 +9,8 @@ "file_formats": "text/x-gcode", "platform": "discoeasy200.stl", "platform_offset": [ 105, -59, 280], + "has_machine_quality": true, + "has_materials": true, "machine_extruder_trains": { "0": "dagoma_discoeasy200_extruder_0" @@ -29,32 +31,44 @@ }, "machine_head_with_fans_polygon": { "default_value": [ - [17, 70], - [17, -40], - [-17, -40], - [17, 70] + [-17, -70], + [-17, 40], + [17, 40], + [17, -70] ] }, "gantry_height": { "default_value": 10 }, "machine_start_gcode": { - "default_value": ";Gcode by Cura\nG90\nM106 S250\nG28 X Y\nG1 X50\nM109 S180\nG28\nM104 S{material_print_temperature_layer_0}\nG29\nM107\nG1 X100 Y20 F3000\nG1 Z0.5\nM109 S{material_print_temperature_layer_0}\nM82\nG92 E0\nG1 F200 E10\nG92 E0\nG1 Z3\nG1 F6000\n" + "default_value": ";Gcode by Cura\nG90\nM106 S255\nG28 X Y\nG1 X50\nM109 R90\nG28\nM104 S{material_print_temperature_layer_0}\nG29\nM107\nG1 X100 Y20 F3000\nG1 Z0.5\nM109 S{material_print_temperature_layer_0}\nM82\nG92 E0\nG1 F200 E10\nG92 E0\nG1 Z3\nG1 F6000\n" }, "machine_end_gcode": { "default_value": "\nM104 S0\nM106 S255\nM140 S0\nG91\nG1 E-1 F300\nG1 Z+3 F3000\nG90\nG28 X Y\nM107\nM84\n" }, + "default_material_print_temperature": { + "default_value": 205 + }, "speed_print": { "default_value": 60 }, "speed_travel": { - "value": "100" + "default_value": 100 }, "retraction_amount": { "default_value": 3.5 }, "retraction_speed": { "default_value": 50 + }, + "adhesion_type": { + "default_value": "skirt" + }, + "skirt_line_count": { + "default_value": 2 + }, + "layer_height_0": { + "default_value": 0.26 } } } diff --git a/resources/definitions/dagoma_neva.def.json b/resources/definitions/dagoma_neva.def.json index fd747dce1c..cdd5725765 100644 --- a/resources/definitions/dagoma_neva.def.json +++ b/resources/definitions/dagoma_neva.def.json @@ -1,5 +1,4 @@ { - "id": "Dagoma_neva", "name": "Dagoma NEVA", "version": 2, "inherits": "fdmprinter", @@ -10,6 +9,8 @@ "file_formats": "text/x-gcode", "platform": "neva.stl", "platform_offset": [ 0, 0, 0], + "has_machine_quality": true, + "has_materials": true, "machine_extruder_trains": { "0": "dagoma_neva_extruder_0" @@ -30,10 +31,10 @@ }, "machine_head_with_fans_polygon": { "default_value": [ - [17, 40], - [17, -70], - [-17, -70], - [17, 40] + [-36, -42], + [-36, 42], + [36, 42], + [36, -42] ] }, "gantry_height": { @@ -43,14 +44,17 @@ "default_value": "elliptic" }, "machine_gcode_flavor": { - "default_value": "RepRap (RepRap)" + "default_value": "RepRap" }, "machine_start_gcode": { - "default_value": ";Gcode by Cura\nG90\nG28\nM109 S100\nG29\nM104 S{material_print_temperature_layer_0}\nG0 X0 Y-85\nG0 Z0.26\nM109 S{material_print_temperature_layer_0}\nM82\nG92 E0\nG1 F200 E6\nG92 E0\nG1 F200 E-3.5\nG0 Z0.15\nG0 X10\nG0 Z3\nG1 F6000\n" + "default_value": ";Gcode by Cura\nG90\nG28\nM107\nM109 R100\nG29\nM109 S{material_print_temperature_layer_0} U-55 X55 V-85 Y-85 W0.26 Z0.26\nM82\nG92 E0\nG1 F200 E6\nG92 E0\nG1 F200 E-3.5\nG0 Z0.15\nG0 X10\nG0 Z3\nG1 F6000\n" }, "machine_end_gcode": { "default_value": "\nM104 S0\nM106 S255\nM140 S0\nG91\nG1 E-1 F300\nG1 Z+3 E-2 F9000\nG90\nG28\n" }, + "default_material_print_temperature": { + "default_value": 205 + }, "speed_print": { "default_value": 40 }, @@ -62,6 +66,15 @@ }, "retraction_speed": { "default_value": 60 + }, + "adhesion_type": { + "default_value": "skirt" + }, + "skirt_line_count": { + "default_value": 2 + }, + "layer_height_0": { + "default_value": 0.26 } } } diff --git a/resources/definitions/dagoma_neva_magis.def.json b/resources/definitions/dagoma_neva_magis.def.json new file mode 100644 index 0000000000..0b7b50cb5f --- /dev/null +++ b/resources/definitions/dagoma_neva_magis.def.json @@ -0,0 +1,80 @@ +{ + "name": "Dagoma NEVA Magis", + "version": 2, + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Dagoma", + "manufacturer": "Dagoma", + "file_formats": "text/x-gcode", + "platform": "neva.stl", + "platform_offset": [ 0, 0, 0], + "has_machine_quality": true, + "has_materials": true, + "machine_extruder_trains": + { + "0": "dagoma_neva_magis_extruder_0" + } + }, + "overrides": { + "machine_width": { + "default_value": 195.55 + }, + "machine_height": { + "default_value": 205 + }, + "machine_depth": { + "default_value": 195.55 + }, + "machine_center_is_zero": { + "default_value": true + }, + "machine_head_with_fans_polygon": { + "default_value": [ + [-36, -42], + [-36, 42], + [36, 42], + [36, -42] + ] + }, + "gantry_height": { + "default_value": 0 + }, + "machine_shape": { + "default_value": "elliptic" + }, + "machine_gcode_flavor": { + "default_value": "RepRap" + }, + "machine_start_gcode": { + "default_value": ";Gcode by Cura\nG90\nG28\nM107\nM109 R100\nG29\nM109 S{material_print_temperature_layer_0} U-55 X55 V-85 Y-85 W0.26 Z0.26\nM82\nG92 E0\nG1 F200 E6\nG92 E0\nG1 F200 E-3.5\nG0 Z0.15\nG0 X10\nG0 Z3\nG1 F6000\n" + }, + "machine_end_gcode": { + "default_value": "\nM104 S0\nM106 S255\nM140 S0\nG91\nG1 E-1 F300\nG1 Z+3 E-2 F9000\nG90\nG28\n" + }, + "default_material_print_temperature": { + "default_value": 205 + }, + "speed_print": { + "default_value": 40 + }, + "speed_travel": { + "default_value": 120 + }, + "retraction_amount": { + "default_value": 3.8 + }, + "retraction_speed": { + "default_value": 60 + }, + "adhesion_type": { + "default_value": "skirt" + }, + "skirt_line_count": { + "default_value": 2 + }, + "layer_height_0": { + "default_value": 0.26 + } + } +} diff --git a/resources/definitions/deltacomb.def.json b/resources/definitions/deltacomb.def.json index f1114583c0..a4b2d47a7b 100644 --- a/resources/definitions/deltacomb.def.json +++ b/resources/definitions/deltacomb.def.json @@ -34,7 +34,7 @@ "material_initial_print_temperature": { "value": "material_print_temperature" }, "material_print_temperature_layer_0": { "value": "material_print_temperature + 5" }, "travel_avoid_distance": { "default_value": 1, "value": "1" }, - "speed_print" : { "default_value": 60 }, + "speed_print" : { "default_value": 70 }, "speed_travel": { "value": "150.0" }, "speed_infill": { "value": "round(speed_print * 1.05, 0)" }, "speed_topbottom": { "value": "round(speed_print * 0.95, 0)" }, @@ -52,6 +52,9 @@ "top_bottom_thickness": { "default_value": 0.6 }, "support_z_distance": { "value": "layer_height * 2" }, "support_bottom_distance": { "value": "layer_height" }, - "support_use_towers" : { "default_value": false } + "support_use_towers" : { "default_value": false }, + "jerk_wall_0" : { "value": "30" }, + "jerk_travel" : { "default_value": 20 }, + "acceleration_travel" : { "value": 10000 } } } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index e376d8a9c2..610ee1473e 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1196,6 +1196,16 @@ "limit_to_extruder": "top_bottom_extruder_nr", "settable_per_mesh": true }, + "connect_skin_polygons": + { + "label": "Connect Top/Bottom Polygons", + "description": "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happend midway over infill this feature can reduce the top surface quality.", + "type": "bool", + "default_value": false, + "enabled": "top_bottom_pattern == 'concentric'", + "limit_to_extruder": "infill_extruder_nr", + "settable_per_mesh": true + }, "skin_angles": { "label": "Top/Bottom Line Directions", @@ -1644,7 +1654,18 @@ "type": "bool", "default_value": false, "value": "infill_pattern == 'cross' or infill_pattern == 'cross_3d'", - "enabled": "infill_pattern == 'grid' or infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' or infill_pattern == 'cross' or infill_pattern == 'cross_3d'", + "enabled": "infill_pattern == 'lines' or infill_pattern == 'grid' or infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' or infill_pattern == 'cross' or infill_pattern == 'cross_3d'", + "limit_to_extruder": "infill_extruder_nr", + "settable_per_mesh": true + }, + "connect_infill_polygons": + { + "label": "Connect Infill Polygons", + "description": "Connect infill paths where they run next to each other. For infill patterns which consist of several closed polygons, enabling this setting greatly reduces the travel time.", + "type": "bool", + "default_value": true, + "value": "infill_pattern == 'cross' or infill_pattern == 'cross_3d' or infill_multiplier % 2 == 0", + "enabled": "infill_pattern == 'cross' or infill_pattern == 'cross_3d' or infill_multiplier % 2 == 0", "limit_to_extruder": "infill_extruder_nr", "settable_per_mesh": true }, @@ -1680,6 +1701,29 @@ "limit_to_extruder": "infill_extruder_nr", "settable_per_mesh": true }, + "infill_multiplier": + { + "label": "Infill Line Multiplier", + "description": "Convert each infill line to this many lines. The extra lines do not cross over each other, but avoid each other. This makes the infill stiffer, but increases print time and material usage.", + "default_value": 1, + "type": "int", + "minimum_value": "1", + "maximum_value_warning": "infill_line_distance / infill_line_width", + "enabled": "infill_sparse_density > 0 and not spaghetti_infill_enabled and infill_pattern != 'zigzag'", + "limit_to_extruder": "infill_extruder_nr", + "settable_per_mesh": true + }, + "infill_wall_line_count": + { + "label": "Extra Infill Wall Count", + "description": "Add extra wals around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\nThis feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right.", + "default_value": 0, + "type": "int", + "minimum_value": "0", + "enabled": "infill_sparse_density > 0 and not spaghetti_infill_enabled", + "limit_to_extruder": "infill_extruder_nr", + "settable_per_mesh": true + }, "sub_div_rad_add": { "label": "Cubic Subdivision Shell", @@ -1775,9 +1819,9 @@ "unit": "mm", "type": "float", "default_value": 0.1, - "minimum_value": "resolveOrValue('layer_height')", + "minimum_value": "resolveOrValue('layer_height') if infill_line_distance > 0 else -999999", "maximum_value_warning": "0.75 * machine_nozzle_size", - "maximum_value": "resolveOrValue('layer_height') * (1.45 if spaghetti_infill_enabled else 8)", + "maximum_value": "resolveOrValue('layer_height') * (1.45 if spaghetti_infill_enabled else 8) if infill_line_distance > 0 else 999999", "value": "resolveOrValue('layer_height')", "enabled": "infill_sparse_density > 0 and not spaghetti_infill_enabled", "limit_to_extruder": "infill_extruder_nr", @@ -2083,6 +2127,7 @@ "type": "float", "default_value": 60, "value": "default_material_bed_temperature", + "resolve": "max(extruderValues('material_bed_temperature'))", "minimum_value": "-273.15", "minimum_value_warning": "0", "maximum_value_warning": "130", @@ -2981,7 +3026,7 @@ { "label": "Initial Layer Print Acceleration", "description": "The acceleration during the printing of the initial layer.", - "unit": "mm/s", + "unit": "mm/s²", "type": "float", "default_value": 3000, "value": "acceleration_layer_0", @@ -2995,7 +3040,7 @@ { "label": "Initial Layer Travel Acceleration", "description": "The acceleration for travel moves in the initial layer.", - "unit": "mm/s", + "unit": "mm/s²", "type": "float", "default_value": 3000, "value": "acceleration_layer_0 * acceleration_travel / acceleration_print", @@ -3311,13 +3356,14 @@ "retraction_combing": { "label": "Combing Mode", - "description": "Combing keeps the nozzle within already printed areas when traveling. This results in slightly longer travel moves but reduces the need for retractions. If combing is off, the material will retract and the nozzle moves in a straight line to the next point. It is also possible to avoid combing over top/bottom skin areas by combing within the infill only.", + "description": "Combing keeps the nozzle within already printed areas when traveling. This results in slightly longer travel moves but reduces the need for retractions. If combing is off, the material will retract and the nozzle moves in a straight line to the next point. It is also possible to avoid combing over top/bottom skin areas and also to only comb within the infill. Note that the 'Within Infill' option behaves exactly like the 'Not in Skin' option in earlier Cura releases.", "type": "enum", "options": { "off": "Off", "all": "All", - "noskin": "Not in Skin" + "noskin": "Not in Skin", + "infill": "Within Infill" }, "default_value": "all", "resolve": "'noskin' if 'noskin' in extruderValues('retraction_combing') else ('all' if 'all' in extruderValues('retraction_combing') else 'off')", @@ -4690,7 +4736,7 @@ }, "raft_base_line_spacing": { - "label": "Raft Line Spacing", + "label": "Raft Base Line Spacing", "description": "The distance between the raft lines for the base raft layer. Wide spacing makes for easy removal of the raft from the build plate.", "unit": "mm", "type": "float", @@ -5013,7 +5059,7 @@ "description": "The minimum volume for each layer of the prime tower in order to purge enough material.", "unit": "mm³", "type": "float", - "default_value": 5, + "default_value": 6, "minimum_value": "0", "maximum_value_warning": "((resolveOrValue('prime_tower_size') * 0.5) ** 2 * 3.14159 * resolveOrValue('layer_height') if prime_tower_circular else resolveOrValue('prime_tower_size') ** 2 * resolveOrValue('layer_height')) - sum(extruderValues('prime_tower_min_volume')) + prime_tower_min_volume", "enabled": "resolveOrValue('prime_tower_enable')", @@ -5028,7 +5074,7 @@ "unit": "mm", "enabled": "resolveOrValue('prime_tower_enable')", "default_value": 200, - "value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - 1", + "value": "machine_width - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - 1", "maximum_value": "machine_width / 2 if machine_center_is_zero else machine_width", "minimum_value": "resolveOrValue('prime_tower_size') - machine_width / 2 if machine_center_is_zero else resolveOrValue('prime_tower_size')", "settable_per_mesh": false, @@ -5042,7 +5088,7 @@ "unit": "mm", "enabled": "resolveOrValue('prime_tower_enable')", "default_value": 200, - "value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - 1", + "value": "machine_depth - prime_tower_size - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 - (resolveOrValue('draft_shield_dist') if resolveOrValue('draft_shield_enabled') else 0) - 1", "maximum_value": "machine_depth / 2 - resolveOrValue('prime_tower_size') if machine_center_is_zero else machine_depth - resolveOrValue('prime_tower_size')", "minimum_value": "machine_depth / -2 if machine_center_is_zero else 0", "settable_per_mesh": false, @@ -5173,6 +5219,7 @@ "type": "bool", "default_value": true, "value": "extruders_enabled_count > 1", + "enabled": "all(p != 'surface' for p in extruderValues('magic_mesh_surface_mode'))", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": true @@ -5183,7 +5230,7 @@ "description": "Switch to which mesh intersecting volumes will belong with every layer, so that the overlapping meshes become interwoven. Turning this setting off will cause one of the meshes to obtain all of the volume in the overlap, while it is removed from the other meshes.", "type": "bool", "default_value": true, - "enabled": "carve_multiple_volumes", + "enabled": "carve_multiple_volumes and all(p != 'surface' for p in extruderValues('magic_mesh_surface_mode'))", "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": true @@ -5580,6 +5627,19 @@ "settable_per_mesh": false, "settable_per_extruder": true }, + "minimum_polygon_circumference": + { + "label": "Minimum Polygon Circumference", + "description": "Polygons in sliced layers that have a circumference smaller than this amount will be filtered out. Lower values lead to higher resolution mesh at the cost of slicing time. It is meant mostly for high resolution SLA printers and very tiny 3D models with a lot of details.", + "unit": "mm", + "type": "float", + "default_value": 1.0, + "minimum_value": "0.001", + "minimum_value_warning": "0.05", + "maximum_value_warning": "1.0", + "settable_per_mesh": true, + "settable_per_extruder": false + }, "meshfix_maximum_resolution": { "label": "Maximum Resolution", diff --git a/resources/definitions/malyan_m200.def.json b/resources/definitions/malyan_m200.def.json index b3b0651e1a..f2c01b3831 100644 --- a/resources/definitions/malyan_m200.def.json +++ b/resources/definitions/malyan_m200.def.json @@ -9,6 +9,7 @@ "category": "Other", "file_formats": "text/x-gcode", "platform": "malyan_m200_platform.stl", + "platform_offset": [0, -0.25, 0], "has_machine_quality": true, "has_materials": true, "preferred_quality_type": "normal", diff --git a/resources/definitions/monoprice_select_mini_v2.def.json b/resources/definitions/monoprice_select_mini_v2.def.json index 4e3d63044e..bed4fb1adb 100644 --- a/resources/definitions/monoprice_select_mini_v2.def.json +++ b/resources/definitions/monoprice_select_mini_v2.def.json @@ -20,6 +20,10 @@ "overrides": { "machine_name": { "default_value": "Monoprice Select Mini V2" }, + "machine_end_gcode": + { + "default_value": "G0 X0 Y120;(Stick out the part)\nM190 S0;(Turn off heat bed, don't wait.)\nG92 E10;(Set extruder to 10)\nG1 E7 F200;(retract 3mm)\nM104 S0;(Turn off nozzle, don't wait)\nG4 S300;(Delay 5 minutes)\nM107;(Turn off part fan)\nM84;(Turn off stepper motors.)" + }, "adhesion_type": { "default_value": "brim" }, "retraction_combing": { "default_value": "noskin" }, "retraction_amount" : { "default_value": 2.5}, diff --git a/resources/definitions/peopoly_moai.def.json b/resources/definitions/peopoly_moai.def.json index 5c03444d49..a578cc4240 100644 --- a/resources/definitions/peopoly_moai.def.json +++ b/resources/definitions/peopoly_moai.def.json @@ -4,13 +4,14 @@ "inherits": "fdmprinter", "metadata": { "visible": true, - "author": "fieldOfView", + "author": "Peopoly", "manufacturer": "Peopoly", "file_formats": "text/x-gcode", "has_machine_quality": true, "has_materials": false, - "machine_extruder_trains": - { + "platform": "moai.obj", + "platform_texture": "moai.jpg", + "machine_extruder_trains": { "0": "peopoly_moai_extruder_0" } }, @@ -46,7 +47,6 @@ "machine_end_gcode": { "default_value": "M104 S0\nM140 S0\nG28 X0 Y0\nM84" }, - "line_width": { "minimum_value_warning": "machine_nozzle_size" }, @@ -75,7 +75,14 @@ "value": "0.1" }, "top_bottom_thickness": { - "minimum_value_warning": "0.1" + "minimum_value_warning": "0.1", + "value": "0.1" + }, + "top_thickness": { + "minimum_value_warning": "resolveOrValue('layer_height')" + }, + "bottom_thickness": { + "minimum_value_warning": "resolveOrValue('layer_height')" }, "infill_sparse_thickness": { "maximum_value_warning": "0.5" @@ -102,24 +109,23 @@ "value": "speed_print" }, "speed_travel": { - "value": "300" + "value": 150 }, "speed_travel_layer_0": { - "value": "300" + "value": 150 }, "speed_layer_0": { - "value": "5" + "value": 5 }, "speed_slowdown_layers": { - "value": "2" + "value": 3 }, "infill_overlap": { - "value": "15" + "value": 15 }, "adhesion_type": { - "value": "\"none\"" + "value": "'none'" }, - "acceleration_enabled": { "value": "False" }, @@ -139,6 +145,10 @@ "enabled": false, "value": "False" }, + "cool_fan_speed_min": { + "enabled": false, + "value": 0 + }, "retraction_enable": { "enabled": false, "value": "False" @@ -148,7 +158,8 @@ "value": "'off'" }, "retract_at_layer_change": { - "enabled": false + "enabled": false, + "value": false }, "cool_min_layer_time_fan_speed_max": { "enabled": false @@ -158,6 +169,117 @@ }, "cool_fan_full_layer": { "enabled": false + }, + "minimum_polygon_circumference": { + "value": "0.1" + }, + "meshfix_maximum_resolution": { + "value": "0.005" + }, + "skin_outline_count": { + "value": 0 + }, + "travel_compensate_overlapping_walls_enabled": { + "value": "False" + }, + "travel_compensate_overlapping_walls_0_enabled": { + "value": "False" + }, + "travel_compensate_overlapping_walls_x_enabled": { + "value": "False" + }, + "wall_0_wipe_dist": { + "value": "machine_nozzle_size / 3" + }, + "wall_thickness": { + "value": 0.5 + }, + "infill_sparse_density": { + "value": 70 + }, + "infill_pattern": { + "value": "'lines'" + }, + "infill_angles": { + "value": "[0,90]" + }, + "cool_min_layer_time": { + "enabled": false, + "value": 0 + }, + "cool_min_speed": { + "enabled": false, + "value": 0 + }, + "cool_lift_head": { + "enabled": false, + "value": "False" + }, + "material_flow": { + "enabled": false + }, + "material_flow_layer_0": { + "enabled": false + }, + "speed_equalize_flow_enabled": { + "enabled": false, + "value": "False" + }, + "draft_shield_enabled": { + "enabled": false, + "value": "False" + }, + "z_seam_corner": { + "value": "'z_seam_corner_none'" + }, + "z_seam_type": { + "value": "'shortest'" + }, + "skin_no_small_gaps_heuristic": { + "value": "False" + }, + "ironing_enabled": { + "enabled": false, + "value": "False" + }, + "skin_overlap": { + "value": 5 + }, + "infill_wipe_dist": { + "value": 0 + }, + "expand_skins_expand_distance": { + "value": "( wall_line_width_0 + (wall_line_count - 1) * wall_line_width_x ) / 2" + }, + "max_feedrate_z_override": { + "value": 0, + "enabled": false + }, + "flow_rate_max_extrusion_offset": { + "enabled": false + }, + "flow_rate_extrusion_offset_factor": { + "enabled": false + }, + "adaptive_layer_height_enabled": { + "value": "False", + "enabled": false + }, + "bridge_settings_enabled": { + "value": "False", + "enabled": false + }, + "acceleration_enabled": { + "value": "False", + "enabled": false + }, + "relative_extrusion": { + "value": "False", + "enabled": false + }, + "coasting_enable": { + "value": "False", + "enabled": false } } } diff --git a/resources/definitions/tizyx_k25.def.json b/resources/definitions/tizyx_k25.def.json new file mode 100644 index 0000000000..94a20b371e --- /dev/null +++ b/resources/definitions/tizyx_k25.def.json @@ -0,0 +1,50 @@ +{ + "version": 2, + "name": "TiZYX K25", + "inherits": "fdmprinter", + "metadata": + { + "visible": true, + "author": "TiZYX", + "manufacturer": "TiZYX", + "file_formats": "text/x-gcode", + "platform": "tizyx_k25_platform.stl", + "platform_offset": [0, -4, 0], + "exclude_materials": ["chromatik_pla", "dsm_arnitel2045_175", "dsm_novamid1070_175", "fabtotum_abs", "fabtotum_nylon", "fabtotum_pla", "fabtotum_tpu", "fiberlogy_hd_pla", "filo3d_pla", "filo3d_pla_green", "filo3d_pla_red", "generic_abs", "generic_abs_175", "generic_bam", "generic_cpe", "generic_cpe_175", "generic_cpe_plus", "generic_hips", "generic_hips_175", "generic_nylon", "generic_nylon_175", "generic_pc", "generic_pc_175", "generic_petg", "generic_petg_175", "generic_pla", "generic_pla_175", "generic_pp", "generic_pva", "generic_pva_175", "generic_tough_pla", "generic_tpu", "imade3d_petg_green", "imade3d_petg_pink", "imade3d_pla_green", "imade3d_pla_pink", "innofill_innoflex60_175", "octofiber_pla", "polyflex_pla", "polymax_pla", "polyplus_pla", "polywood_pla", "ultimaker_abs_black", "ultimaker_abs_blue", "ultimaker_abs_green", "ultimaker_abs_grey", "ultimaker_abs_orange", "ultimaker_abs_pearl-gold", "ultimaker_abs_red", "ultimaker_abs_silver-metallic", "ultimaker_abs_white", "ultimaker_abs_yellow", "ultimaker_bam", "ultimaker_cpe_black", "ultimaker_cpe_blue", "ultimaker_cpe_dark-grey", "ultimaker_cpe_green", "ultimaker_cpe_light-grey", "ultimaker_cpe_plus_black", "ultimaker_cpe_plus_transparent", "ultimaker_cpe_plus_white", "ultimaker_cpe_red", "ultimaker_cpe_transparent", "ultimaker_cpe_white", "ultimaker_cpe_yellow", "ultimaker_nylon_black", "ultimaker_nylon_transparent", "ultimaker_pc_black", "ultimaker_pc_transparent", "ultimaker_pc_white", "ultimaker_pla_black", "ultimaker_pla_blue", "ultimaker_pla_green", "ultimaker_pla_magenta", "ultimaker_pla_orange", "ultimaker_pla_pearl-white", "ultimaker_pla_red", "ultimaker_pla_silver-metallic", "ultimaker_pla_transparent", "ultimaker_pla_white", "ultimaker_pla_yellow", "ultimaker_pp_transparent", "ultimaker_pva", "ultimaker_tough_pla_black", "ultimaker_tough_pla_green", "ultimaker_tough_pla_red", "ultimaker_tough_pla_white", "ultimaker_tpu_black", "ultimaker_tpu_blue", "ultimaker_tpu_red", "ultimaker_tpu_white", "verbatim_bvoh_175", "Vertex_Delta_ABS", "Vertex_Delta_PET", "Vertex_Delta_PLA", "Vertex_Delta_TPU", "zyyx_pro_flex", "zyyx_pro_pla" ], + "preferred_material": "tizyx_pla", + "has_machine_quality": true, + "has_materials": true, + "machine_extruder_trains": + { + "0": "tizyx_k25_extruder_0" + } + }, + + "overrides": + { + "machine_name": { "default_value": "TiZYX K25" }, + "machine_heated_bed": { "default_value": true }, + "machine_width": { "default_value": 255 }, + "machine_height": { "default_value": 255 }, + "machine_depth": { "default_value": 255 }, + "machine_center_is_zero": { "default_value": false }, + "gantry_height": { "default_value": 500 }, + "machine_head_with_fans_polygon": { + "default_value": [ + [25, 49], + [25, -49], + [-25, -49], + [25, 49] + ] + }, + "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, + "machine_start_gcode": + { + "default_value": "M82\nG90\nG28 X\nG28 Y\nG28 Z\nG29\nG91\nG1 Z0\nG90\nM82\nG92 E0\nG1 X125 Y245 F3000\nG1 Z0" + }, + "machine_end_gcode": + { + "default_value": "M104 S0\nM140 S0\nG91\nG1 E-5 F300\nG1 Z+3 F3000\nG1 Y245 F3000\nM84" + } + } +} diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index 08fe01a76b..b75d12ce44 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -90,7 +90,7 @@ "infill_overlap": { "value": "0" }, "infill_pattern": { "value": "'triangles'" }, "infill_wipe_dist": { "value": "0" }, - "initial_layer_line_width_factor": { "value": "120" }, + "initial_layer_line_width_factor": { "value": "120" }, "jerk_enabled": { "value": "True" }, "jerk_layer_0": { "value": "jerk_topbottom" }, "jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" }, diff --git a/resources/definitions/winbo_dragonl4.def.json b/resources/definitions/winbo_dragonl4.def.json new file mode 100644 index 0000000000..0ca68cdcee --- /dev/null +++ b/resources/definitions/winbo_dragonl4.def.json @@ -0,0 +1,137 @@ +{ + "version": 2, + "name": "Winbo Dragon(L)4", + "inherits": "fdmprinter", + "metadata": { + "author": "Winbo", + "manufacturer": "Winbo Smart Tech Co., Ltd.", + "category": "Other", + "visible": true, + "file_formats": "text/x-gcode", + "supports_usb_connection": false, + "machine_extruder_trains": + { + "0": "winbo_dragonl4_extruder" + } + }, + + "overrides": { + "machine_name": { "default_value": "Winbo Dragon(L)4" }, + "machine_width": { "default_value": 615 }, + "machine_depth": { "default_value": 463 }, + "machine_height": { "default_value": 615 }, + "machine_heated_bed": { "default_value": true }, + "material_bed_temp_wait": { "default_value": false }, + "machine_filament_park_distance": { "value": "machine_heat_zone_length" }, + "machine_nozzle_heat_up_speed": { "default_value": 1.4 }, + "machine_nozzle_cool_down_speed": { "default_value": 0.8 }, + "machine_head_with_fans_polygon": + { + "default_value": + [ + [ -50, 90 ],[ -50, -60 ],[ 50, -60 ],[ 50, 90 ] + ] + }, + "machine_gcode_flavor": { "default_value": "Marlin" }, + "machine_max_feedrate_x": { "default_value": 300 }, + "machine_max_feedrate_y": { "default_value": 300 }, + "machine_max_feedrate_z": { "default_value": 40 }, + "machine_acceleration": { "default_value": 2000 }, + "gantry_height": { "default_value": 80 }, + "machine_extruder_count": { "default_value": 1 }, + "machine_start_gcode": { "default_value": "G21\nG90\nM82\nM107\nM9998\nG28 X0 Y0\nG28 Z0\nG1 F6000 Z0.3\nG92 E0\nG1 F800 X585 E12\nG92 E0" }, + "machine_end_gcode": { "default_value": "M104 S0\nM140 S0\nG92 E2\nG1 E0 F200\nG28 X0 Y0\nM84 X Y E" }, + "prime_blob_enable": { "enabled": true }, + "acceleration_enabled": { "value": "True" }, + "acceleration_layer_0": { "value": "acceleration_topbottom" }, + "acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" }, + "acceleration_print": { "value": "1800" }, + "acceleration_travel": { "value": "2000" }, + "acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" }, + "acceleration_support_interface": { "value": "acceleration_topbottom" }, + "acceleration_topbottom": { "value": "math.ceil(acceleration_print * 500 / 4000)" }, + "acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 4000)" }, + "acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 500 / 1000)" }, + "brim_width": { "value": "4" }, + "cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" }, + "cool_fan_speed": { "value": "100" }, + "cool_fan_speed_max": { "value": "100" }, + "cool_min_speed": { "value": "5" }, + "fill_outline_gaps": { "value": "True" }, + "infill_overlap": { "value": "0" }, + "min_infill_area": { "value": "1" }, + "min_skin_width_for_expansion": { "value": "2" }, + "jerk_enabled": { "value": "True" }, + "jerk_layer_0": { "value": "jerk_topbottom" }, + "jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" }, + "jerk_print": { "value": "25" }, + "jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" }, + "jerk_support_interface": { "value": "jerk_topbottom" }, + "jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" }, + "jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" }, + "jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" }, + "wall_thickness": { "value": "2.4"}, + "line_width": { "value": "extruderValue(-1,'machine_nozzle_size')" }, + "wall_0_inset": { "value": "0.05" }, + "wall_line_width_x": { "value": "line_width" }, + "wall_line_width_0": { "value": "line_width-0.05" }, + "support_line_width": { "value": "max(min(line_width,0.4),line_width/2)" }, + "support_interface_line_width": { "value": "support_line_width" }, + "machine_min_cool_heat_time_window": { "value": "15" }, + "default_material_print_temperature": { "value": "200" }, + "material_print_temperature_layer_0": { "value": "material_print_temperature - 5" }, + "material_bed_temperature": { "maximum_value": "100" }, + "material_bed_temperature_layer_0": { "maximum_value": "100" }, + "raft_airgap": { "value": "0" }, + "raft_base_thickness": { "value": "0.3" }, + "raft_interface_line_spacing": { "value": "0.5" }, + "raft_interface_line_width": { "value": "0.5" }, + "raft_interface_thickness": { "value": "0.2" }, + "raft_jerk": { "value": "jerk_layer_0" }, + "raft_margin": { "value": "5" }, + "raft_surface_layers": { "value": "2" }, + "retraction_amount": { "value": "4" }, + "retraction_count_max": { "value": "10" }, + "retraction_extrusion_window": { "value": "1" }, + "retraction_hop": { "value": "0.5" }, + "retraction_hop_enabled": { "value": "True" }, + "retraction_hop_only_when_collides": { "value": "True" }, + "retraction_min_travel": { "value": "5" }, + "retraction_prime_speed": { "value": "25" }, + "skin_overlap": { "value": "10" }, + "speed_layer_0": { "value": "25" }, + "speed_print": { "value": "70" }, + "speed_support": { "value": "speed_print*line_width/support_line_width" }, + "speed_support_interface": { "value": "speed_print*line_width/support_interface_line_width" }, + "speed_topbottom": { "value": "speed_print*line_width/skin_line_width" }, + "speed_travel": { "value": "100" }, + "speed_infill": { "value": "speed_print*line_width/infill_line_width" }, + "speed_wall": { "value": "speed_print*wall_line_width_0/line_width" }, + "speed_wall_0": { "value": "math.ceil(speed_wall * 0.6)" }, + "speed_wall_x": { "value": "speed_wall" }, + "speed_equalize_flow_enabled": { "value": "False" }, + "support_angle": { "value": "50" }, + "support_xy_distance": { "value": "1" }, + "support_z_distance": { "value": "max((0.2 if(0.2%layer_height==0) else layer_height*int((0.2+layer_height)/layer_height)),layer_height)" }, + "support_bottom_distance": { "value": "max(support_z_distance,layer_height*int(0.45/layer_height))" }, + "top_bottom_thickness": { "value": "max(1.2,layer_height*6)" }, + "travel_avoid_distance": { "value": "3" }, + "gradual_support_infill_step_height": { "value": "0.2" }, + "gradual_support_infill_steps": { "value": "1" }, + "infill_sparse_density": { "value": "20" }, + "gradual_infill_step_height": { "value": "1" }, + "initial_layer_line_width_factor": { "value": "120" }, + "jerk_travel": { "value": "25" }, + "support_bottom_enable": { "value": "True" }, + "support_bottom_height": { "value": "max((0.15 if(0.15%layer_height==0) else layer_height*int((0.15+layer_height)/layer_height)),layer_height)" }, + "support_bottom_pattern": { "value": "'zigzag'" }, + "support_connect_zigzags": { "value": "False" }, + "support_infill_rate": { "value": "8" }, + "support_interface_density": { "value": "80" }, + "support_interface_enable": { "value": "True" }, + "support_interface_height": { "value": "0.5" }, + "support_roof_pattern": { "value": "'concentric'" }, + "z_seam_type": { "value": "'shortest'" }, + "speed_equalize_flow_max": { "value": "65" } + } +} diff --git a/resources/definitions/winbo_mini2.def.json b/resources/definitions/winbo_mini2.def.json new file mode 100644 index 0000000000..7393fdf910 --- /dev/null +++ b/resources/definitions/winbo_mini2.def.json @@ -0,0 +1,137 @@ +{ + "version": 2, + "name": "Winbo Mini2", + "inherits": "fdmprinter", + "metadata": { + "author": "Winbo", + "manufacturer": "Winbo Smart Tech Co., Ltd.", + "category": "Other", + "visible": true, + "file_formats": "text/x-gcode", + "supports_usb_connection": true, + "machine_extruder_trains": + { + "0": "winbo_mini2_extruder" + } + }, + + "overrides": { + "machine_name": { "default_value": "Winbo Mini2" }, + "machine_width": { "default_value": 205 }, + "machine_depth": { "default_value": 155 }, + "machine_height": { "default_value": 205 }, + "machine_heated_bed": { "default_value": false }, + "material_bed_temp_wait": { "default_value": false }, + "machine_filament_park_distance": { "value": "machine_heat_zone_length" }, + "machine_nozzle_heat_up_speed": { "default_value": 1.4 }, + "machine_nozzle_cool_down_speed": { "default_value": 0.8 }, + "machine_head_with_fans_polygon": + { + "default_value": + [ + [ -52, 30 ],[ -52, -40 ],[ 13, -40 ],[ 13, 30 ] + ] + }, + "machine_gcode_flavor": { "default_value": "Marlin" }, + "machine_max_feedrate_x": { "default_value": 250 }, + "machine_max_feedrate_y": { "default_value": 200 }, + "machine_max_feedrate_z": { "default_value": 40 }, + "machine_acceleration": { "default_value": 3000 }, + "gantry_height": { "default_value": 75 }, + "machine_extruder_count": { "default_value": 1 }, + "machine_start_gcode": { "default_value": "G21\nG90\nM82\nM107\nG28 X0 Y0\nG28 Z0\nG1 F1000 Z3\nG1 F4000 X0\nG1 F4000 Y0\nG1 F1000 Z0.2\nG92 E0\nG1 F1000 X30 E8\nG92 E0\nM117 Printing." }, + "machine_end_gcode": { "default_value": "M104 S0\nM140 S0\nG92 E2\nG1 E0 F200\nG28 X0 Y0\nM84 X Y E" }, + "prime_blob_enable": { "enabled": true }, + "acceleration_enabled": { "value": "True" }, + "acceleration_layer_0": { "value": "acceleration_topbottom" }, + "acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" }, + "acceleration_print": { "value": "2000" }, + "acceleration_travel": { "value": "2500" }, + "acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" }, + "acceleration_support_interface": { "value": "acceleration_topbottom" }, + "acceleration_topbottom": { "value": "math.ceil(acceleration_print * 500 / 4000)" }, + "acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 4000)" }, + "acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 500 / 1000)" }, + "brim_width": { "value": "3" }, + "cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" }, + "cool_fan_speed": { "value": "100" }, + "cool_fan_speed_max": { "value": "100" }, + "cool_min_speed": { "value": "5" }, + "fill_outline_gaps": { "value": "True" }, + "infill_overlap": { "value": "0" }, + "min_infill_area": { "value": "1" }, + "min_skin_width_for_expansion": { "value": "2" }, + "jerk_enabled": { "value": "True" }, + "jerk_layer_0": { "value": "jerk_topbottom" }, + "jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" }, + "jerk_print": { "value": "25" }, + "jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" }, + "jerk_support_interface": { "value": "jerk_topbottom" }, + "jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" }, + "jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" }, + "jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" }, + "wall_thickness": { "value": "1.2"}, + "line_width": { "value": "extruderValue(-1,'machine_nozzle_size')" }, + "wall_0_inset": { "value": "0.05" }, + "wall_line_width_x": { "value": "line_width" }, + "wall_line_width_0": { "value": "line_width-0.05" }, + "support_line_width": { "value": "max(min(line_width,0.4),line_width/2)" }, + "support_interface_line_width": { "value": "support_line_width" }, + "machine_min_cool_heat_time_window": { "value": "15" }, + "default_material_print_temperature": { "value": "200" }, + "material_print_temperature_layer_0": { "value": "material_print_temperature - 5" }, + "material_bed_temperature": { "maximum_value": "115" }, + "material_bed_temperature_layer_0": { "maximum_value": "115" }, + "raft_airgap": { "value": "0" }, + "raft_base_thickness": { "value": "0.3" }, + "raft_interface_line_spacing": { "value": "0.5" }, + "raft_interface_line_width": { "value": "0.5" }, + "raft_interface_thickness": { "value": "0.2" }, + "raft_jerk": { "value": "jerk_layer_0" }, + "raft_margin": { "value": "10" }, + "raft_surface_layers": { "value": "1" }, + "retraction_amount": { "value": "4" }, + "retraction_count_max": { "value": "10" }, + "retraction_extrusion_window": { "value": "1" }, + "retraction_hop": { "value": "0.5" }, + "retraction_hop_enabled": { "value": "True" }, + "retraction_hop_only_when_collides": { "value": "True" }, + "retraction_min_travel": { "value": "5" }, + "retraction_prime_speed": { "value": "25" }, + "skin_overlap": { "value": "10" }, + "speed_layer_0": { "value": "20" }, + "speed_print": { "value": "50" }, + "speed_support": { "value": "speed_print*line_width/support_line_width" }, + "speed_support_interface": { "value": "speed_print*line_width/support_interface_line_width" }, + "speed_topbottom": { "value": "speed_print*line_width/skin_line_width" }, + "speed_travel": { "value": "90" }, + "speed_infill": { "value": "speed_print*line_width/infill_line_width" }, + "speed_wall": { "value": "speed_print*wall_line_width_0/line_width" }, + "speed_wall_0": { "value": "math.ceil(speed_wall * 0.6)" }, + "speed_wall_x": { "value": "speed_wall" }, + "speed_equalize_flow_enabled": { "value": "False" }, + "support_angle": { "value": "50" }, + "support_xy_distance": { "value": "1" }, + "support_z_distance": { "value": "max((0.2 if(0.2%layer_height==0) else layer_height*int((0.2+layer_height)/layer_height)),layer_height)" }, + "support_bottom_distance": { "value": "max(support_z_distance,layer_height*int(0.45/layer_height))" }, + "top_bottom_thickness": { "value": "max(1.2,layer_height*6)" }, + "travel_avoid_distance": { "value": "3" }, + "gradual_support_infill_step_height": { "value": "0.2" }, + "gradual_support_infill_steps": { "value": "1" }, + "infill_sparse_density": { "value": "20" }, + "gradual_infill_step_height": { "value": "1" }, + "initial_layer_line_width_factor": { "value": "120" }, + "jerk_travel": { "value": "25" }, + "support_bottom_enable": { "value": "True" }, + "support_bottom_height": { "value": "max((0.15 if(0.15%layer_height==0) else layer_height*int((0.15+layer_height)/layer_height)),layer_height)" }, + "support_bottom_pattern": { "value": "'zigzag'" }, + "support_connect_zigzags": { "value": "False" }, + "support_infill_rate": { "value": "8" }, + "support_interface_density": { "value": "80" }, + "support_interface_enable": { "value": "True" }, + "support_interface_height": { "value": "0.5" }, + "support_roof_pattern": { "value": "'concentric'" }, + "z_seam_type": { "value": "'shortest'" }, + "speed_equalize_flow_max": { "value": "65" } + } +} diff --git a/resources/definitions/winbo_superhelper105.def.json b/resources/definitions/winbo_superhelper105.def.json new file mode 100644 index 0000000000..59e71fb446 --- /dev/null +++ b/resources/definitions/winbo_superhelper105.def.json @@ -0,0 +1,126 @@ +{ + "version": 2, + "name": "Winbo Super Helper 105", + "inherits": "fdmprinter", + "metadata": { + "author": "Winbo", + "manufacturer": "Winbo Smart Tech Co., Ltd.", + "category": "Other", + "visible": true, + "file_formats": "text/x-gcode", + "supports_usb_connection": true, + "machine_extruder_trains": + { + "0": "winbo_superhelper105_extruder" + } + }, + + "overrides": { + "machine_name": { "default_value": "Winbo Super Helper 105" }, + "machine_width": { "default_value": 108 }, + "machine_depth": { "default_value": 108 }, + "machine_height": { "default_value": 158 }, + "machine_heated_bed": { "default_value": false }, + "material_bed_temp_wait": { "default_value": false }, + "machine_filament_park_distance": { "value": "machine_heat_zone_length" }, + "machine_nozzle_heat_up_speed": { "default_value": 1.4 }, + "machine_nozzle_cool_down_speed": { "default_value": 0.8 }, + "machine_head_with_fans_polygon": + { + "default_value": + [ + [ -110, 50 ],[ -110, -30 ],[ 110, -30 ],[ 110, 50 ] + ] + }, + "machine_gcode_flavor": { "default_value": "Marlin" }, + "machine_max_feedrate_x": { "default_value": 250 }, + "machine_max_feedrate_y": { "default_value": 200 }, + "machine_max_feedrate_z": { "default_value": 40 }, + "machine_acceleration": { "default_value": 2000 }, + "gantry_height": { "default_value": 200 }, + "machine_extruder_count": { "default_value": 1 }, + "machine_start_gcode": { "default_value": "G21\nG90\nM82\nM107\nG28 X0 Y0\nG28 Z0\nG1 F6000 Z0.3\nG92 E0\nG1 F1000 X30 E8\nG92 E0\nM117 Printing." }, + "machine_end_gcode": { "default_value": "M104 S0\nM140 S0\nG92 E2\nG1 E0 F200\nG28 X0 Y0\nM84 X Y E" }, + "prime_blob_enable": { "enabled": true }, + "acceleration_enabled": { "value": "True" }, + "acceleration_layer_0": { "value": "acceleration_topbottom" }, + "acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" }, + "acceleration_print": { "value": "2000" }, + "acceleration_travel": { "value": "1500" }, + "acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" }, + "acceleration_support_interface": { "value": "acceleration_topbottom" }, + "acceleration_topbottom": { "value": "math.ceil(acceleration_print * 500 / 4000)" }, + "acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 4000)" }, + "acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 500 / 1000)" }, + "brim_width": { "value": "3" }, + "cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" }, + "cool_fan_speed": { "value": "100" }, + "cool_fan_speed_max": { "value": "100" }, + "cool_min_speed": { "value": "5" }, + "fill_outline_gaps": { "value": "True" }, + "infill_overlap": { "value": "0" }, + "min_infill_area": { "value": "1" }, + "min_skin_width_for_expansion": { "value": "2" }, + "jerk_enabled": { "value": "True" }, + "jerk_layer_0": { "value": "jerk_topbottom" }, + "jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" }, + "jerk_print": { "value": "25" }, + "jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" }, + "jerk_support_interface": { "value": "jerk_topbottom" }, + "jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" }, + "jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" }, + "jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" }, + "wall_thickness": { "value": "0.8"}, + "line_width": { "value": "extruderValue(-1,'machine_nozzle_size')" }, + "raft_base_thickness": { "value": "0.3" }, + "raft_interface_line_spacing": { "value": "0.5" }, + "raft_interface_line_width": { "value": "0.5" }, + "raft_interface_thickness": { "value": "0.2" }, + "raft_jerk": { "value": "jerk_layer_0" }, + "raft_margin": { "value": "10" }, + "raft_surface_layers": { "value": "1" }, + "retraction_amount": { "value": "4" }, + "retraction_count_max": { "value": "10" }, + "retraction_extrusion_window": { "value": "1" }, + "retraction_hop": { "value": "0.5" }, + "retraction_hop_enabled": { "value": "True" }, + "retraction_hop_only_when_collides": { "value": "True" }, + "retraction_min_travel": { "value": "5" }, + "retraction_prime_speed": { "value": "25" }, + "skin_overlap": { "value": "10" }, + "speed_layer_0": { "value": "20" }, + "speed_print": { "value": "52" }, + "speed_support": { "value": "speed_print*line_width/support_line_width" }, + "speed_support_interface": { "value": "speed_print*line_width/support_interface_line_width" }, + "speed_topbottom": { "value": "speed_print*line_width/skin_line_width" }, + "speed_travel": { "value": "80" }, + "speed_infill": { "value": "speed_print*line_width/infill_line_width" }, + "speed_wall": { "value": "speed_print*wall_line_width_0/line_width" }, + "speed_wall_0": { "value": "math.ceil(speed_wall * 0.6)" }, + "speed_wall_x": { "value": "speed_wall" }, + "speed_equalize_flow_enabled": { "value": "False" }, + "support_angle": { "value": "50" }, + "support_xy_distance": { "value": "1" }, + "support_z_distance": { "value": "max((0.2 if(0.2%layer_height==0) else layer_height*int((0.2+layer_height)/layer_height)),layer_height)" }, + "support_bottom_distance": { "value": "max(support_z_distance,layer_height*int(0.45/layer_height))" }, + "top_bottom_thickness": { "value": "max(1.2,layer_height*6)" }, + "travel_avoid_distance": { "value": "3" }, + "gradual_support_infill_step_height": { "value": "0.2" }, + "gradual_support_infill_steps": { "value": "1" }, + "infill_sparse_density": { "value": "20" }, + "gradual_infill_step_height": { "value": "1" }, + "initial_layer_line_width_factor": { "value": "120" }, + "jerk_travel": { "value": "25" }, + "support_bottom_enable": { "value": "True" }, + "support_bottom_height": { "value": "max((0.15 if(0.15%layer_height==0) else layer_height*int((0.15+layer_height)/layer_height)),layer_height)" }, + "support_bottom_pattern": { "value": "'zigzag'" }, + "support_connect_zigzags": { "value": "False" }, + "support_infill_rate": { "value": "8" }, + "support_interface_density": { "value": "80" }, + "support_interface_enable": { "value": "True" }, + "support_interface_height": { "value": "0.5" }, + "support_roof_pattern": { "value": "'concentric'" }, + "z_seam_type": { "value": "'shortest'" }, + "speed_equalize_flow_max": { "value": "65" } + } +} diff --git a/resources/definitions/winbo_superhelper155.def.json b/resources/definitions/winbo_superhelper155.def.json new file mode 100644 index 0000000000..65bb4e7b73 --- /dev/null +++ b/resources/definitions/winbo_superhelper155.def.json @@ -0,0 +1,30 @@ +{ + "version": 2, + "name": "Winbo Super Helper 155", + "inherits": "winbo_superhelper105", + "metadata": { + "author": "Winbo", + "manufacturer": "Winbo Smart Tech Co., Ltd.", + "category": "Other", + "visible": true, + "file_formats": "text/x-gcode", + "supports_usb_connection": true, + "machine_extruder_trains": + { + "0": "winbo_superhelper155_extruder" + } + }, + "overrides": { + "machine_name": { "default_value": "Winbo Super Helper 155" }, + "machine_width": { "default_value": 158 }, + "machine_depth": { "default_value": 158 }, + "machine_height": { "default_value": 208 }, + "machine_head_with_fans_polygon": + { + "default_value": + [ + [ -160, 50 ],[ -160, -30 ],[ 160, -30 ],[ 160, 50 ] + ] + } + } +} diff --git a/resources/extruders/builder_premium_large_front.def.json b/resources/extruders/builder_premium_large_front.def.json index 059f7ef8a7..4834bc8fd9 100644 --- a/resources/extruders/builder_premium_large_front.def.json +++ b/resources/extruders/builder_premium_large_front.def.json @@ -16,13 +16,13 @@ "machine_nozzle_offset_x": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 }, "material_diameter": { "default_value": 1.75 }, - - "machine_extruder_start_pos_abs": { "default_value": true }, + + "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_start_pos_y": { "value": "prime_tower_position_y" }, "machine_extruder_end_pos_abs": { "default_value": true }, "machine_extruder_end_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }, - "extruder_prime_pos_abs": { "default_value": true } + "extruder_prime_pos_abs": { "default_value": true } } } diff --git a/resources/extruders/builder_premium_large_rear.def.json b/resources/extruders/builder_premium_large_rear.def.json index 769178a8b4..f257749ea4 100644 --- a/resources/extruders/builder_premium_large_rear.def.json +++ b/resources/extruders/builder_premium_large_rear.def.json @@ -20,9 +20,9 @@ "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_start_pos_y": { "value": "prime_tower_position_y" }, - "machine_extruder_end_pos_abs": { "default_value": true }, + "machine_extruder_end_pos_abs": { "default_value": true }, "machine_extruder_end_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }, - "extruder_prime_pos_abs": { "default_value": true } + "extruder_prime_pos_abs": { "default_value": true } } } diff --git a/resources/extruders/builder_premium_medium_front.def.json b/resources/extruders/builder_premium_medium_front.def.json index bd735fbe25..05dcb3d49f 100644 --- a/resources/extruders/builder_premium_medium_front.def.json +++ b/resources/extruders/builder_premium_medium_front.def.json @@ -16,13 +16,13 @@ "machine_nozzle_offset_x": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 }, "material_diameter": { "default_value": 1.75 }, - - "machine_extruder_start_pos_abs": { "default_value": true }, + + "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_start_pos_y": { "value": "prime_tower_position_y" }, "machine_extruder_end_pos_abs": { "default_value": true }, "machine_extruder_end_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }, - "extruder_prime_pos_abs": { "default_value": true } + "extruder_prime_pos_abs": { "default_value": true } } } diff --git a/resources/extruders/builder_premium_medium_rear.def.json b/resources/extruders/builder_premium_medium_rear.def.json index 59e688ff71..3461e07f09 100644 --- a/resources/extruders/builder_premium_medium_rear.def.json +++ b/resources/extruders/builder_premium_medium_rear.def.json @@ -20,9 +20,9 @@ "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_start_pos_y": { "value": "prime_tower_position_y" }, - "machine_extruder_end_pos_abs": { "default_value": true }, + "machine_extruder_end_pos_abs": { "default_value": true }, "machine_extruder_end_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }, - "extruder_prime_pos_abs": { "default_value": true } + "extruder_prime_pos_abs": { "default_value": true } } } diff --git a/resources/extruders/builder_premium_small_front.def.json b/resources/extruders/builder_premium_small_front.def.json index 17fb914a42..7a1c352c73 100644 --- a/resources/extruders/builder_premium_small_front.def.json +++ b/resources/extruders/builder_premium_small_front.def.json @@ -16,13 +16,13 @@ "machine_nozzle_offset_x": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 }, "material_diameter": { "default_value": 1.75 }, - - "machine_extruder_start_pos_abs": { "default_value": true }, + + "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_start_pos_y": { "value": "prime_tower_position_y" }, "machine_extruder_end_pos_abs": { "default_value": true }, "machine_extruder_end_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }, - "extruder_prime_pos_abs": { "default_value": true } + "extruder_prime_pos_abs": { "default_value": true } } } diff --git a/resources/extruders/builder_premium_small_rear.def.json b/resources/extruders/builder_premium_small_rear.def.json index 70a2dbf1aa..7085236a5c 100644 --- a/resources/extruders/builder_premium_small_rear.def.json +++ b/resources/extruders/builder_premium_small_rear.def.json @@ -20,9 +20,9 @@ "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_start_pos_y": { "value": "prime_tower_position_y" }, - "machine_extruder_end_pos_abs": { "default_value": true }, + "machine_extruder_end_pos_abs": { "default_value": true }, "machine_extruder_end_pos_x": { "value": "prime_tower_position_x" }, "machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }, - "extruder_prime_pos_abs": { "default_value": true } + "extruder_prime_pos_abs": { "default_value": true } } } diff --git a/resources/extruders/dagoma_discoeasy200_extruder_0.def.json b/resources/extruders/dagoma_discoeasy200_extruder_0.def.json index eb2b8ef1f7..c885ac971e 100644 --- a/resources/extruders/dagoma_discoeasy200_extruder_0.def.json +++ b/resources/extruders/dagoma_discoeasy200_extruder_0.def.json @@ -1,5 +1,4 @@ { - "id": "dagoma_discoeasy200_extruder_0", "version": 2, "name": "Extruder 1", "inherits": "fdmextruder", @@ -9,8 +8,14 @@ }, "overrides": { - "extruder_nr": { "default_value": 0 }, - "machine_nozzle_size": { "default_value": 0.4 }, - "material_diameter": { "default_value": 1.75 } + "extruder_nr": { + "default_value": 0 + }, + "machine_nozzle_size": { + "default_value": 0.4 + }, + "material_diameter": { + "default_value": 1.75 + } } } diff --git a/resources/extruders/dagoma_neva_extruder_0.def.json b/resources/extruders/dagoma_neva_extruder_0.def.json index dcb8311be4..95035f63f2 100644 --- a/resources/extruders/dagoma_neva_extruder_0.def.json +++ b/resources/extruders/dagoma_neva_extruder_0.def.json @@ -1,5 +1,4 @@ { - "id": "dagoma_neva_extruder_0", "version": 2, "name": "Extruder 1", "inherits": "fdmextruder", @@ -9,8 +8,14 @@ }, "overrides": { - "extruder_nr": { "default_value": 0 }, - "machine_nozzle_size": { "default_value": 0.4 }, - "material_diameter": { "default_value": 1.75 } + "extruder_nr": { + "default_value": 0 + }, + "machine_nozzle_size": { + "default_value": 0.4 + }, + "material_diameter": { + "default_value": 1.75 + } } } diff --git a/resources/extruders/dagoma_neva_magis_extruder_0.def.json b/resources/extruders/dagoma_neva_magis_extruder_0.def.json new file mode 100644 index 0000000000..0d5fd3c9b4 --- /dev/null +++ b/resources/extruders/dagoma_neva_magis_extruder_0.def.json @@ -0,0 +1,21 @@ +{ + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "dagoma_neva_magis", + "position": "0" + }, + + "overrides": { + "extruder_nr": { + "default_value": 0 + }, + "machine_nozzle_size": { + "default_value": 0.4 + }, + "material_diameter": { + "default_value": 1.75 + } + } +} diff --git a/resources/extruders/peopoly_moai_extruder_0.def.json b/resources/extruders/peopoly_moai_extruder_0.def.json index 7940002926..bbffd4ac4d 100644 --- a/resources/extruders/peopoly_moai_extruder_0.def.json +++ b/resources/extruders/peopoly_moai_extruder_0.def.json @@ -11,6 +11,9 @@ "overrides": { "extruder_nr": { "default_value": 0 }, "machine_nozzle_size": { "default_value": 0.067 }, - "material_diameter": { "default_value": 1.75 } + "material_diameter": { + "enabled": false, + "default_value": 1.75 + } } } diff --git a/resources/extruders/tizyx_k25_extruder_0.def.json b/resources/extruders/tizyx_k25_extruder_0.def.json new file mode 100644 index 0000000000..409198d77c --- /dev/null +++ b/resources/extruders/tizyx_k25_extruder_0.def.json @@ -0,0 +1,16 @@ +{ + "id": "tizyx_k25_extruder_0", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "tizyx_k25", + "position": "0" + }, + + "overrides": { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} \ No newline at end of file diff --git a/resources/extruders/winbo_dragonl4_extruder.def.json b/resources/extruders/winbo_dragonl4_extruder.def.json new file mode 100644 index 0000000000..37a08c8d08 --- /dev/null +++ b/resources/extruders/winbo_dragonl4_extruder.def.json @@ -0,0 +1,20 @@ +{ + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "winbo_dragonl4", + "position": "0" + }, + + "overrides": { + "extruder_nr": { + "default_value": 0, + "maximum_value": "2" + }, + "material_diameter": { "default_value": 3.0 }, + "machine_nozzle_size": { "default_value": 0.8 }, + "machine_nozzle_offset_x": { "default_value": 0.0 }, + "machine_nozzle_offset_y": { "default_value": 0.0 } + } +} diff --git a/resources/extruders/winbo_mini2_extruder.def.json b/resources/extruders/winbo_mini2_extruder.def.json new file mode 100644 index 0000000000..a57ec28109 --- /dev/null +++ b/resources/extruders/winbo_mini2_extruder.def.json @@ -0,0 +1,20 @@ +{ + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "winbo_mini2", + "position": "0" + }, + + "overrides": { + "extruder_nr": { + "default_value": 0, + "maximum_value": "2" + }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "machine_nozzle_offset_x": { "default_value": 0.0 }, + "machine_nozzle_offset_y": { "default_value": 0.0 } + } +} diff --git a/resources/extruders/winbo_superhelper105_extruder.def.json b/resources/extruders/winbo_superhelper105_extruder.def.json new file mode 100644 index 0000000000..a974317937 --- /dev/null +++ b/resources/extruders/winbo_superhelper105_extruder.def.json @@ -0,0 +1,20 @@ +{ + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "winbo_superhelper105", + "position": "0" + }, + + "overrides": { + "extruder_nr": { + "default_value": 0, + "maximum_value": "2" + }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "machine_nozzle_offset_x": { "default_value": 0.0 }, + "machine_nozzle_offset_y": { "default_value": 0.0 } + } +} diff --git a/resources/extruders/winbo_superhelper155_extruder.def.json b/resources/extruders/winbo_superhelper155_extruder.def.json new file mode 100644 index 0000000000..6d83689bf4 --- /dev/null +++ b/resources/extruders/winbo_superhelper155_extruder.def.json @@ -0,0 +1,20 @@ +{ + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "winbo_superhelper155", + "position": "0" + }, + + "overrides": { + "extruder_nr": { + "default_value": 0, + "maximum_value": "2" + }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "machine_nozzle_offset_x": { "default_value": 0.0 }, + "machine_nozzle_offset_y": { "default_value": 0.0 } + } +} diff --git a/resources/i18n/de_DE/cura.po b/resources/i18n/de_DE/cura.po index 37b8840468..31ce980615 100644 --- a/resources/i18n/de_DE/cura.po +++ b/resources/i18n/de_DE/cura.po @@ -4036,7 +4036,7 @@ msgstr "&Ansicht" #: /home/ruben/Projects/Cura/resources/qml/Cura.qml:184 msgctxt "@title:menu" msgid "&Settings" -msgstr "&Einstellungen" +msgstr "&Konfiguration" #: /home/ruben/Projects/Cura/resources/qml/Cura.qml:186 msgctxt "@title:menu menubar:toplevel" diff --git a/resources/images/moai.jpg b/resources/images/moai.jpg new file mode 100644 index 0000000000..54c6c7561e Binary files /dev/null and b/resources/images/moai.jpg differ diff --git a/resources/meshes/moai.obj b/resources/meshes/moai.obj new file mode 100644 index 0000000000..f13f30d6f4 --- /dev/null +++ b/resources/meshes/moai.obj @@ -0,0 +1,32 @@ +# OBJ written from C:\Users\Flo\Desktop\Cura_FILES\moai.obj +mtllib moai.mtl +# Units millimeters + +g Mesh +v 65 -65 0 +v -65 -65 0 +v -65 65 0 +v 65 65 0 +v 65 -65 0 +v -65 -65 0 +v -65 65 0 +v 65 65 0 +v -65 65 18.8383 +v 65 65 18.8383 +vn 0 0 1 +vn 1 0 0 +vn -1 0 0 +vt 0.0975501 1 +vt 1 1 +vt 1 0.0977239 +vt 0.0975501 0.0977239 +vt 0.0186426 0.870052 +vt 0.0736426 0.870052 +vt 0.0186426 0.815052 +vt 0.0214764 0.912057 +vt 0.0764764 0.967057 +vt 0.0214764 0.967057 +usemtl red +f 1/1/1 4/2/1 3/3/1 2/4/1 +f 7/5/2 9/6/2 6/7/2 +f 5/8/3 10/9/3 8/10/3 diff --git a/resources/meshes/tizyx_k25_platform.stl b/resources/meshes/tizyx_k25_platform.stl new file mode 100644 index 0000000000..5417aaed5f Binary files /dev/null and b/resources/meshes/tizyx_k25_platform.stl differ diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 21e6eebf58..d5572298f7 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -110,35 +110,35 @@ Item Action { id: view3DCameraAction; - text: catalog.i18nc("@action:inmenu menubar:view","&3D View"); + text: catalog.i18nc("@action:inmenu menubar:view","3D View"); onTriggered: UM.Controller.rotateView("3d", 0); } Action { id: viewFrontCameraAction; - text: catalog.i18nc("@action:inmenu menubar:view","&Front View"); + text: catalog.i18nc("@action:inmenu menubar:view","Front View"); onTriggered: UM.Controller.rotateView("home", 0); } Action { id: viewTopCameraAction; - text: catalog.i18nc("@action:inmenu menubar:view","&Top View"); + text: catalog.i18nc("@action:inmenu menubar:view","Top View"); onTriggered: UM.Controller.rotateView("y", 90); } Action { id: viewLeftSideCameraAction; - text: catalog.i18nc("@action:inmenu menubar:view","&Left Side View"); + text: catalog.i18nc("@action:inmenu menubar:view","Left Side View"); onTriggered: UM.Controller.rotateView("x", 90); } Action { id: viewRightSideCameraAction; - text: catalog.i18nc("@action:inmenu menubar:view","&Right Side View"); + text: catalog.i18nc("@action:inmenu menubar:view","Right Side View"); onTriggered: UM.Controller.rotateView("x", -90); } @@ -229,7 +229,7 @@ Item Action { id: deleteSelectionAction; - text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete &Selected Model", "Delete &Selected Models", UM.Selection.selectionCount); + text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete Selected Model", "Delete Selected Models", UM.Selection.selectionCount); enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection; iconName: "edit-delete"; shortcut: StandardKey.Delete; @@ -239,7 +239,7 @@ Item Action //Also add backspace as the same function as delete because on Macintosh keyboards the button called "delete" is actually a backspace, and the user expects it to function as a delete. { id: backspaceSelectionAction - text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete &Selected Model", "Delete &Selected Models", UM.Selection.selectionCount) + text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete Selected Model", "Delete Selected Models", UM.Selection.selectionCount) enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection iconName: "edit-delete" shortcut: StandardKey.Backspace @@ -328,7 +328,7 @@ Item Action { id: selectAllAction; - text: catalog.i18nc("@action:inmenu menubar:edit","&Select All Models"); + text: catalog.i18nc("@action:inmenu menubar:edit","Select All Models"); enabled: UM.Controller.toolsEnabled; iconName: "edit-select-all"; shortcut: "Ctrl+A"; @@ -386,7 +386,7 @@ Item Action { id: resetAllAction; - text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model &Transformations"); + text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model Transformations"); onTriggered: CuraApplication.resetAll(); } diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 09c66f98f9..616523fc45 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -117,10 +117,10 @@ UM.MainWindow MenuItem { id: saveWorkspaceMenu - text: catalog.i18nc("@title:menu menubar:file","&Save...") + text: catalog.i18nc("@title:menu menubar:file","Save...") onTriggered: { - var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetype": "application/x-curaproject+xml" }; + var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" }; if(UM.Preferences.getValue("cura/dialog_on_project_save")) { saveWorkspaceDialog.args = args; @@ -142,7 +142,7 @@ UM.MainWindow onTriggered: { var localDeviceId = "local_file"; - UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}); + UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}); } } @@ -151,7 +151,7 @@ UM.MainWindow text: catalog.i18nc("@action:inmenu menubar:file", "Export Selection..."); enabled: UM.Selection.hasSelection; iconName: "document-save-as"; - onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetype": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}); + onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}); } MenuSeparator { } @@ -231,8 +231,8 @@ UM.MainWindow onObjectRemoved: settingsMenu.removeItem(object) } - // TODO Temporary hidden, add back again when feature ready -// BuildplateMenu { title: catalog.i18nc("@title:menu", "&Build plate"); visible: Cura.MachineManager.hasVariantBuildplates } + // TODO Only show in dev mode. Remove check when feature ready + BuildplateMenu { title: catalog.i18nc("@title:menu", "&Build plate"); visible: CuraSDKVersion == "dev" ? Cura.MachineManager.hasVariantBuildplates : false } ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); } MenuSeparator { } @@ -541,7 +541,7 @@ UM.MainWindow insertPage(2, catalog.i18nc("@title:tab", "Printers"), Qt.resolvedUrl("Preferences/MachinesPage.qml")); - insertPage(3, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/MaterialsPage.qml")); + insertPage(3, catalog.i18nc("@title:tab", "Materials"), Qt.resolvedUrl("Preferences/Materials/MaterialsPage.qml")); insertPage(4, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml")); diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index 20ec8ce289..31ca84d66e 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -81,7 +81,7 @@ Item { text: PrintInformation.jobName horizontalAlignment: TextInput.AlignRight onEditingFinished: { - var new_name = text == "" ? catalog.i18nc("@text Print job name", "unnamed") : text; + var new_name = text == "" ? catalog.i18nc("@text Print job name", "Untitled") : text; PrintInformation.setJobName(new_name, true); printJobTextfield.focus = false; } diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 6f0130d5ca..942dd81d9c 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -103,9 +103,24 @@ Rectangle id: mouse anchors.fill: parent onClicked: activateConfiguration() + cursorShape: Qt.PointingHandCursor hoverEnabled: true - onEntered: parent.border.color = UM.Theme.getColor("configuration_item_border_hover") - onExited: updateBorderColor() + onEntered: + { + parent.border.color = UM.Theme.getColor("configuration_item_border_hover") + if (configurationItem.selected == false) + { + configurationItem.color = UM.Theme.getColor("sidebar_lining") + } + } + onExited: + { + updateBorderColor() + if (configurationItem.selected == false) + { + configurationItem.color = UM.Theme.getColor("configuration_item") + } + } } Connections @@ -122,4 +137,13 @@ Rectangle configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) updateBorderColor() } + + onVisibleChanged: + { + if(visible) + { + // I cannot trigger function updateBorderColor() after visibility change + color = selected ? UM.Theme.getColor("configuration_item_active") : UM.Theme.getColor("configuration_item") + } + } } \ No newline at end of file diff --git a/resources/qml/Menus/MaterialMenu.qml b/resources/qml/Menus/MaterialMenu.qml index 64b3130724..f9e343d2dd 100644 --- a/resources/qml/Menus/MaterialMenu.qml +++ b/resources/qml/Menus/MaterialMenu.qml @@ -10,28 +10,74 @@ import Cura 1.0 as Cura Menu { id: menu - title: "Material" + title: catalog.i18nc("@label:category menu label", "Material") property int extruderIndex: 0 + Cura.FavoriteMaterialsModel + { + id: favoriteMaterialsModel + extruderPosition: menu.extruderIndex + } + + Cura.GenericMaterialsModel + { + id: genericMaterialsModel + extruderPosition: menu.extruderIndex + } + + Cura.MaterialBrandsModel + { + id: brandModel + extruderPosition: menu.extruderIndex + } + + MenuItem + { + text: catalog.i18nc("@label:category menu label", "Favorites") + enabled: false + visible: favoriteMaterialsModel.items.length > 0 + } Instantiator { - model: genericMaterialsModel - MenuItem + model: favoriteMaterialsModel + delegate: MenuItem { - text: model.name + text: model.brand + " " + model.name checkable: true checked: model.root_material_id == Cura.MachineManager.currentRootMaterialId[extruderIndex] + onTriggered: Cura.MachineManager.setMaterial(extruderIndex, model.container_node) exclusiveGroup: group - onTriggered: - { - Cura.MachineManager.setMaterial(extruderIndex, model.container_node); - } } onObjectAdded: menu.insertItem(index, object) - onObjectRemoved: menu.removeItem(object) + onObjectRemoved: menu.removeItem(object) // TODO: This ain't gonna work, removeItem() takes an index, not object } - MenuSeparator { } + + MenuSeparator {} + + Menu + { + id: genericMenu + title: catalog.i18nc("@label:category menu label", "Generic") + + Instantiator + { + model: genericMaterialsModel + delegate: MenuItem + { + text: model.name + checkable: true + checked: model.root_material_id == Cura.MachineManager.currentRootMaterialId[extruderIndex] + exclusiveGroup: group + onTriggered: Cura.MachineManager.setMaterial(extruderIndex, model.container_node) + } + onObjectAdded: genericMenu.insertItem(index, object) + onObjectRemoved: genericMenu.removeItem(object) // TODO: This ain't gonna work, removeItem() takes an index, not object + } + } + + MenuSeparator {} + Instantiator { model: brandModel @@ -40,12 +86,12 @@ Menu id: brandMenu title: brandName property string brandName: model.name - property var brandMaterials: model.materials + property var brandMaterials: model.material_types Instantiator { model: brandMaterials - Menu + delegate: Menu { id: brandMaterialsMenu title: materialName @@ -55,16 +101,13 @@ Menu Instantiator { model: brandMaterialColors - MenuItem + delegate: MenuItem { text: model.name checkable: true checked: model.id == Cura.MachineManager.allActiveMaterialIds[Cura.ExtruderManager.extruderIds[extruderIndex]] exclusiveGroup: group - onTriggered: - { - Cura.MachineManager.setMaterial(extruderIndex, model.container_node); - } + onTriggered: Cura.MachineManager.setMaterial(extruderIndex, model.container_node) } onObjectAdded: brandMaterialsMenu.insertItem(index, object) onObjectRemoved: brandMaterialsMenu.removeItem(object) @@ -78,21 +121,14 @@ Menu onObjectRemoved: menu.removeItem(object) } - Cura.GenericMaterialsModel - { - id: genericMaterialsModel - extruderPosition: menu.extruderIndex + ExclusiveGroup { + id: group } - Cura.BrandMaterialsModel + MenuSeparator {} + + MenuItem { - id: brandModel - extruderPosition: menu.extruderIndex + action: Cura.Actions.manageMaterials } - - ExclusiveGroup { id: group } - - MenuSeparator { } - - MenuItem { action: Cura.Actions.manageMaterials } } diff --git a/resources/qml/Preferences/Materials/MaterialsBrandSection.qml b/resources/qml/Preferences/Materials/MaterialsBrandSection.qml new file mode 100644 index 0000000000..1077cbff6f --- /dev/null +++ b/resources/qml/Preferences/Materials/MaterialsBrandSection.qml @@ -0,0 +1,100 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Uranium is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Rectangle +{ + id: brand_section + property var expanded: base.collapsed_brands.indexOf(model.name) > -1 + property var types_model: model.material_types + height: childrenRect.height + width: parent.width + Rectangle + { + id: brand_header_background + color: UM.Theme.getColor("favorites_header_bar") + anchors.fill: brand_header + } + Row + { + id: brand_header + width: parent.width + Label + { + id: brand_name + text: model.name + height: UM.Theme.getSize("favorites_row").height + width: parent.width - UM.Theme.getSize("favorites_button").width + verticalAlignment: Text.AlignVCenter + leftPadding: 4 + } + Button + { + text: "" + implicitWidth: UM.Theme.getSize("favorites_button").width + implicitHeight: UM.Theme.getSize("favorites_button").height + UM.RecolorImage { + anchors + { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: height + color: "black" + source: brand_section.expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") + } + style: ButtonStyle + { + background: Rectangle + { + anchors.fill: parent + color: "transparent" + } + } + } + } + MouseArea + { + anchors.fill: brand_header + onPressed: + { + const i = base.collapsed_brands.indexOf(model.name) + if (i > -1) + { + // Remove it + base.collapsed_brands.splice(i, 1) + brand_section.expanded = false + } + else + { + // Add it + base.collapsed_brands.push(model.name) + brand_section.expanded = true + } + } + } + Column + { + anchors.top: brand_header.bottom + width: parent.width + anchors.left: parent.left + height: brand_section.expanded ? childrenRect.height : 0 + visible: brand_section.expanded + Repeater + { + model: types_model + delegate: MaterialsTypeSection {} + } + } +} \ No newline at end of file diff --git a/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml b/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml new file mode 100644 index 0000000000..ad9f0e3766 --- /dev/null +++ b/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml @@ -0,0 +1,102 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Uranium is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Item +{ + id: detailsPanel + + property var currentItem: base.currentItem + + onCurrentItemChanged: { updateMaterialPropertiesObject(currentItem) } + + function updateMaterialPropertiesObject( currentItem ) + { + materialProperties.name = currentItem.name || "Unknown" + materialProperties.guid = currentItem.GUID; + materialProperties.container_id = currentItem.id + materialProperties.brand = currentItem.brand || "Unknown" + materialProperties.material = currentItem.material || "Unknown" + materialProperties.color_name = currentItem.color_name || "Yellow" + materialProperties.color_code = currentItem.color_code || "yellow" + materialProperties.description = currentItem.description || "" + materialProperties.adhesion_info = currentItem.adhesion_info || ""; + materialProperties.density = currentItem.density || 0.0 + materialProperties.diameter = currentItem.diameter || 0.0 + materialProperties.approximate_diameter = currentItem.approximate_diameter || "0" + } + + Item + { + anchors.fill: parent + + Item // Material title Label + { + id: profileName + + width: parent.width + height: childrenRect.height + + Label { + text: materialProperties.name + font: UM.Theme.getFont("large") + } + } + + MaterialsView // Material detailed information view below the title Label + { + id: materialDetailsView + anchors + { + left: parent.left + right: parent.right + top: profileName.bottom + topMargin: UM.Theme.getSize("default_margin").height + bottom: parent.bottom + } + + editingEnabled: base.currentItem != null && !base.currentItem.is_read_only + + properties: materialProperties + containerId: base.currentItem != null ? base.currentItem.id : "" + currentMaterialNode: base.currentItem.container_node + + + } + + QtObject + { + id: materialProperties + + property string guid: "00000000-0000-0000-0000-000000000000" + property string container_id: "Unknown"; + property string name: "Unknown"; + property string profile_type: "Unknown"; + property string brand: "Unknown"; + property string material: "Unknown"; // This needs to be named as "material" to be consistent with + // the material container's metadata entry + + property string color_name: "Yellow"; + property color color_code: "yellow"; + + property real density: 0.0; + property real diameter: 0.0; + property string approximate_diameter: "0"; + + property real spool_cost: 0.0; + property real spool_weight: 0.0; + property real spool_length: 0.0; + property real cost_per_meter: 0.0; + + property string description: ""; + property string adhesion_info: ""; + } + } +} \ No newline at end of file diff --git a/resources/qml/Preferences/Materials/MaterialsList.qml b/resources/qml/Preferences/Materials/MaterialsList.qml new file mode 100644 index 0000000000..4a1a330ed6 --- /dev/null +++ b/resources/qml/Preferences/Materials/MaterialsList.qml @@ -0,0 +1,199 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Uranium is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Item +{ + id: materialList + width: materialScrollView.width - 17 + height: childrenRect.height + + // Children + UM.I18nCatalog { id: catalog; name: "cura"; } + Cura.MaterialBrandsModel { id: materialsModel } + Cura.FavoriteMaterialsModel { id: favoriteMaterialsModel } + Cura.GenericMaterialsModel { id: genericMaterialsModel } + Column + { + Rectangle + { + property var expanded: true + + id: favorites_section + height: childrenRect.height + width: materialList.width + Rectangle + { + id: favorites_header_background + color: UM.Theme.getColor("favorites_header_bar") + anchors.fill: favorites_header + } + Row + { + id: favorites_header + Label + { + id: favorites_name + text: "Favorites" + height: UM.Theme.getSize("favorites_row").height + width: materialList.width - UM.Theme.getSize("favorites_button").width + verticalAlignment: Text.AlignVCenter + leftPadding: 4 + } + Button + { + text: "" + implicitWidth: UM.Theme.getSize("favorites_button").width + implicitHeight: UM.Theme.getSize("favorites_button").height + UM.RecolorImage { + anchors + { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: height + color: "black" + source: favorites_section.expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") + } + style: ButtonStyle + { + background: Rectangle + { + anchors.fill: parent + color: "transparent" + } + } + } + } + MouseArea + { + anchors.fill: favorites_header + onPressed: + { + favorites_section.expanded = !favorites_section.expanded + } + } + Column + { + anchors.top: favorites_header.bottom + anchors.left: parent.left + width: materialList.width + height: favorites_section.expanded ? childrenRect.height : 0 + visible: favorites_section.expanded + Repeater + { + model: favoriteMaterialsModel + delegate: MaterialsSlot { + material: model + } + } + } + } + Rectangle + { + property var expanded: base.collapsed_brands.indexOf("Generic") > -1 + + id: generic_section + height: childrenRect.height + width: materialList.width + Rectangle + { + id: generic_header_background + color: UM.Theme.getColor("favorites_header_bar") + anchors.fill: generic_header + } + Row + { + id: generic_header + Label + { + id: generic_name + text: "Generic" + height: UM.Theme.getSize("favorites_row").height + width: materialList.width - UM.Theme.getSize("favorites_button").width + verticalAlignment: Text.AlignVCenter + leftPadding: 4 + } + Button + { + text: "" + implicitWidth: UM.Theme.getSize("favorites_button").width + implicitHeight: UM.Theme.getSize("favorites_button").height + UM.RecolorImage { + anchors + { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: height + color: "black" + source: generic_section.expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") + } + style: ButtonStyle + { + background: Rectangle + { + anchors.fill: parent + color: "transparent" + } + } + } + } + MouseArea + { + anchors.fill: generic_header + onPressed: + { + const i = base.collapsed_brands.indexOf("Generic") + if (i > -1) + { + // Remove it + base.collapsed_brands.splice(i, 1) + generic_section.expanded = false + } + else + { + // Add it + base.collapsed_brands.push("Generic") + generic_section.expanded = true + } + } + } + Column + { + anchors.top: generic_header.bottom + width: materialList.width + anchors.left: parent.left + height: generic_section.expanded ? childrenRect.height : 0 + visible: generic_section.expanded + Repeater + { + model: genericMaterialsModel + delegate: MaterialsSlot { + material: model + } + } + } + } + Repeater + { + id: brand_list + model: materialsModel + delegate: MaterialsBrandSection {} + } + } +} \ No newline at end of file diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/Materials/MaterialsPage.qml similarity index 56% rename from resources/qml/Preferences/MaterialsPage.qml rename to resources/qml/Preferences/Materials/MaterialsPage.qml index e2e3edec2f..0b81df5fa1 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/Materials/MaterialsPage.qml @@ -9,25 +9,110 @@ import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura - Item { id: base property QtObject materialManager: CuraApplication.getMaterialManager() - property var resetEnabled: false // Keep PreferencesDialog happy - - UM.I18nCatalog { id: catalog; name: "cura"; } - - Cura.MaterialManagementModel + // Keep PreferencesDialog happy + property var resetEnabled: false + property var currentItem: null + property var isCurrentItemActivated: { - id: materialsModel + const extruder_position = Cura.ExtruderManager.activeExtruderIndex; + const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; + return base.currentItem.root_material_id == root_material_id; + } + property string newRootMaterialIdToSwitchTo: "" + property bool toActivateNewMaterial: false + + // TODO: Save these to preferences + property var collapsed_brands: [] + property var collapsed_types: [] + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + Cura.MaterialBrandsModel { id: materialsModel } + + function findModelByRootId( search_root_id ) + { + for (var i = 0; i < materialsModel.rowCount(); i++) + { + var types_model = materialsModel.getItem(i).material_types; + for (var j = 0; j < types_model.rowCount(); j++) + { + var colors_model = types_model.getItem(j).colors; + for (var k = 0; k < colors_model.rowCount(); k++) + { + var material = colors_model.getItem(k); + if (material.root_material_id == search_root_id) + { + return material + } + } + } + } + } + Component.onCompleted: + { + // Select the activated material when this page shows up + const extruder_position = Cura.ExtruderManager.activeExtruderIndex; + const active_root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; + console.log("goign to search for", active_root_material_id) + base.currentItem = findModelByRootId(active_root_material_id) } + onCurrentItemChanged: { MaterialsDetailsPanel.currentItem = currentItem } + Connections + { + target: materialsModel + onItemsChanged: + { + var currentItemId = base.currentItem == null ? "" : base.currentItem.root_material_id; + var position = Cura.ExtruderManager.activeExtruderIndex; + + // try to pick the currently selected item; it may have been moved + if (base.newRootMaterialIdToSwitchTo == "") + { + base.newRootMaterialIdToSwitchTo = currentItemId; + } + + for (var idx = 0; idx < materialsModel.rowCount(); ++idx) + { + var item = materialsModel.getItem(idx); + if (item.root_material_id == base.newRootMaterialIdToSwitchTo) + { + // Switch to the newly created profile if needed + materialListView.currentIndex = idx; + materialListView.activateDetailsWithIndex(materialListView.currentIndex); + if (base.toActivateNewMaterial) + { + Cura.MachineManager.setMaterial(position, item.container_node); + } + base.newRootMaterialIdToSwitchTo = ""; + base.toActivateNewMaterial = false; + return + } + } + + materialListView.currentIndex = 0; + materialListView.activateDetailsWithIndex(materialListView.currentIndex); + if (base.toActivateNewMaterial) + { + Cura.MachineManager.setMaterial(position, materialsModel.getItem(0).container_node); + } + base.newRootMaterialIdToSwitchTo = ""; + base.toActivateNewMaterial = false; + } + } + + // Main layout Label { id: titleLabel - anchors { top: parent.top @@ -35,45 +120,12 @@ Item right: parent.right margins: 5 * screenScaleFactor } - font.pointSize: 18 text: catalog.i18nc("@title:tab", "Materials") } - property var hasCurrentItem: materialListView.currentItem != null - - property var currentItem: - { // is soon to be overwritten - var current_index = materialListView.currentIndex; - return materialsModel.getItem(current_index); - } - - property var isCurrentItemActivated: - { - const extruder_position = Cura.ExtruderManager.activeExtruderIndex; - const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; - return base.currentItem.root_material_id == root_material_id; - } - - Component.onCompleted: - { - // Select the activated material when this page shows up - const extruder_position = Cura.ExtruderManager.activeExtruderIndex; - const active_root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; - var itemIndex = -1; - for (var i = 0; i < materialsModel.rowCount(); ++i) - { - var item = materialsModel.getItem(i); - if (item.root_material_id == active_root_material_id) - { - itemIndex = i; - break; - } - } - materialListView.currentIndex = itemIndex; - } - - Row // Button Row + // Button Row + Row { id: buttonRow anchors @@ -166,63 +218,102 @@ Item } } - property string newRootMaterialIdToSwitchTo: "" - property bool toActivateNewMaterial: false - - // This connection makes sure that we will switch to the new - Connections - { - target: materialsModel - onItemsChanged: + Item { + id: contentsItem + anchors { - var currentItemId = base.currentItem == null ? "" : base.currentItem.root_material_id; - var position = Cura.ExtruderManager.activeExtruderIndex; + top: titleLabel.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + margins: 5 * screenScaleFactor + bottomMargin: 0 + } + clip: true + } - // try to pick the currently selected item; it may have been moved - if (base.newRootMaterialIdToSwitchTo == "") + Item + { + anchors + { + top: buttonRow.bottom + topMargin: UM.Theme.getSize("default_margin").height + left: parent.left + right: parent.right + bottom: parent.bottom + } + + SystemPalette { id: palette } + + Label + { + id: captionLabel + anchors { - base.newRootMaterialIdToSwitchTo = currentItemId; + top: parent.top + left: parent.left } - - for (var idx = 0; idx < materialsModel.rowCount(); ++idx) + visible: text != "" + text: { - var item = materialsModel.getItem(idx); - if (item.root_material_id == base.newRootMaterialIdToSwitchTo) + var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName; + if (Cura.MachineManager.hasVariants) { - // Switch to the newly created profile if needed - materialListView.currentIndex = idx; - materialListView.activateDetailsWithIndex(materialListView.currentIndex); - if (base.toActivateNewMaterial) - { - Cura.MachineManager.setMaterial(position, item.container_node); - } - base.newRootMaterialIdToSwitchTo = ""; - base.toActivateNewMaterial = false; - return + caption += ", " + Cura.MachineManager.activeDefinitionVariantsName + ": " + Cura.MachineManager.activeVariantName; } + return caption; + } + width: materialScrollView.width + elide: Text.ElideRight + } + + ScrollView + { + id: materialScrollView + anchors + { + top: captionLabel.visible ? captionLabel.bottom : parent.top + topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0 + bottom: parent.bottom + left: parent.left } - materialListView.currentIndex = 0; - materialListView.activateDetailsWithIndex(materialListView.currentIndex); - if (base.toActivateNewMaterial) + Rectangle { - Cura.MachineManager.setMaterial(position, materialsModel.getItem(0).container_node); + parent: viewport + anchors.fill: parent + color: palette.light + } + + width: true ? (parent.width * 0.4) | 0 : parent.width + frameVisible: true + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn + + MaterialsList {} + } + + MaterialsDetailsPanel + { + anchors + { + left: materialScrollView.right + leftMargin: UM.Theme.getSize("default_margin").width + top: parent.top + bottom: parent.bottom + right: parent.right } - base.newRootMaterialIdToSwitchTo = ""; - base.toActivateNewMaterial = false; } } + // Dialogs MessageDialog { id: confirmRemoveMaterialDialog - icon: StandardIcon.Question; title: catalog.i18nc("@title:window", "Confirm Remove") text: catalog.i18nc("@label (%1 is object name)", "Are you sure you wish to remove %1? This cannot be undone!").arg(base.currentItem.name) standardButtons: StandardButton.Yes | StandardButton.No modality: Qt.ApplicationModal - onYes: { base.materialManager.removeMaterial(base.currentItem.container_node); @@ -292,281 +383,4 @@ Item { id: messageDialog } - - - Item { - id: contentsItem - - anchors - { - top: titleLabel.bottom - left: parent.left - right: parent.right - bottom: parent.bottom - margins: 5 * screenScaleFactor - bottomMargin: 0 - } - - clip: true - } - - Item - { - anchors - { - top: buttonRow.bottom - topMargin: UM.Theme.getSize("default_margin").height - left: parent.left - right: parent.right - bottom: parent.bottom - } - - SystemPalette { id: palette } - - Label - { - id: captionLabel - anchors - { - top: parent.top - left: parent.left - } - visible: text != "" - text: - { - var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName; - if (Cura.MachineManager.hasVariants) - { - caption += ", " + Cura.MachineManager.activeDefinitionVariantsName + ": " + Cura.MachineManager.activeVariantName; - } - return caption; - } - width: materialScrollView.width - elide: Text.ElideRight - } - - ScrollView - { - id: materialScrollView - anchors - { - top: captionLabel.visible ? captionLabel.bottom : parent.top - topMargin: captionLabel.visible ? UM.Theme.getSize("default_margin").height : 0 - bottom: parent.bottom - left: parent.left - } - - Rectangle - { - parent: viewport - anchors.fill: parent - color: palette.light - } - - width: true ? (parent.width * 0.4) | 0 : parent.width - frameVisible: true - - ListView - { - id: materialListView - - model: materialsModel - - section.property: "brand" - section.criteria: ViewSection.FullString - section.delegate: Rectangle - { - width: materialScrollView.width - height: childrenRect.height - color: palette.light - - Label - { - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_lining").width - text: section - font.bold: true - color: palette.text - } - } - - delegate: Rectangle - { - width: materialScrollView.width - height: childrenRect.height - color: ListView.isCurrentItem ? palette.highlight : (model.index % 2) ? palette.base : palette.alternateBase - - Row - { - id: materialRow - spacing: (UM.Theme.getSize("default_margin").width / 2) | 0 - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: parent.right - - property bool isCurrentItem: parent.ListView.isCurrentItem - - property bool isItemActivated: - { - const extruder_position = Cura.ExtruderManager.activeExtruderIndex; - const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; - return model.root_material_id == root_material_id; - } - - Rectangle - { - width: Math.floor(parent.height * 0.8) - height: Math.floor(parent.height * 0.8) - color: model.color_code - border.color: materialRow.isCurrentItem ? palette.highlightedText : palette.text; - anchors.verticalCenter: parent.verticalCenter - } - Label - { - width: Math.floor((parent.width * 0.3)) - text: model.material - elide: Text.ElideRight - font.italic: materialRow.isItemActivated - color: materialRow.isCurrentItem ? palette.highlightedText : palette.text; - } - Label - { - text: (model.name != model.material) ? model.name : "" - elide: Text.ElideRight - font.italic: materialRow.isItemActivated - color: materialRow.isCurrentItem ? palette.highlightedText : palette.text; - } - } - - MouseArea - { - anchors.fill: parent - onClicked: - { - parent.ListView.view.currentIndex = model.index; - } - } - } - - function activateDetailsWithIndex(index) - { - var model = materialsModel.getItem(index); - base.currentItem = model; - materialDetailsView.containerId = model.container_id; - materialDetailsView.currentMaterialNode = model.container_node; - - detailsPanel.updateMaterialPropertiesObject(); - } - - onCurrentIndexChanged: - { - forceActiveFocus(); // causes the changed fields to be saved - activateDetailsWithIndex(currentIndex); - } - } - } - - - Item - { - id: detailsPanel - - anchors - { - left: materialScrollView.right - leftMargin: UM.Theme.getSize("default_margin").width - top: parent.top - bottom: parent.bottom - right: parent.right - } - - function updateMaterialPropertiesObject() - { - var currentItem = materialsModel.getItem(materialListView.currentIndex); - - materialProperties.name = currentItem.name ? currentItem.name : "Unknown"; - materialProperties.guid = currentItem.guid; - materialProperties.container_id = currentItem.container_id; - - materialProperties.brand = currentItem.brand ? currentItem.brand : "Unknown"; - materialProperties.material = currentItem.material ? currentItem.material : "Unknown"; - materialProperties.color_name = currentItem.color_name ? currentItem.color_name : "Yellow"; - materialProperties.color_code = currentItem.color_code ? currentItem.color_code : "yellow"; - - materialProperties.description = currentItem.description ? currentItem.description : ""; - materialProperties.adhesion_info = currentItem.adhesion_info ? currentItem.adhesion_info : ""; - - materialProperties.density = currentItem.density ? currentItem.density : 0.0; - materialProperties.diameter = currentItem.diameter ? currentItem.diameter : 0.0; - materialProperties.approximate_diameter = currentItem.approximate_diameter ? currentItem.approximate_diameter : "0"; - } - - Item - { - anchors.fill: parent - - Item // Material title Label - { - id: profileName - - width: parent.width - height: childrenRect.height - - Label { - text: materialProperties.name - font: UM.Theme.getFont("large") - } - } - - MaterialView // Material detailed information view below the title Label - { - id: materialDetailsView - anchors - { - left: parent.left - right: parent.right - top: profileName.bottom - topMargin: UM.Theme.getSize("default_margin").height - bottom: parent.bottom - } - - editingEnabled: base.currentItem != null && !base.currentItem.is_read_only - - properties: materialProperties - containerId: base.currentItem != null ? base.currentItem.container_id : "" - currentMaterialNode: base.currentItem.container_node - - property alias pane: base - } - - QtObject - { - id: materialProperties - - property string guid: "00000000-0000-0000-0000-000000000000" - property string container_id: "Unknown"; - property string name: "Unknown"; - property string profile_type: "Unknown"; - property string brand: "Unknown"; - property string material: "Unknown"; // This needs to be named as "material" to be consistent with - // the material container's metadata entry - - property string color_name: "Yellow"; - property color color_code: "yellow"; - - property real density: 0.0; - property real diameter: 0.0; - property string approximate_diameter: "0"; - - property real spool_cost: 0.0; - property real spool_weight: 0.0; - property real spool_length: 0.0; - property real cost_per_meter: 0.0; - - property string description: ""; - property string adhesion_info: ""; - } - } - } - } } diff --git a/resources/qml/Preferences/Materials/MaterialsSlot.qml b/resources/qml/Preferences/Materials/MaterialsSlot.qml new file mode 100644 index 0000000000..ab0dd23750 --- /dev/null +++ b/resources/qml/Preferences/Materials/MaterialsSlot.qml @@ -0,0 +1,120 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Uranium is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Rectangle +{ + id: material_slot + property var material + property var hovered: false + property var is_favorite: material.is_favorite + + height: UM.Theme.getSize("favorites_row").height + width: parent.width + color: base.currentItem == model ? UM.Theme.getColor("favorites_row_selected") : "transparent" + + Item + { + height: parent.height + width: parent.width + Rectangle + { + id: swatch + color: material.color_code + border.width: UM.Theme.getSize("default_lining").width + border.color: "black" + width: UM.Theme.getSize("favorites_button_icon").width + height: UM.Theme.getSize("favorites_button_icon").height + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + } + Label + { + text: material.brand + " " + material.name + verticalAlignment: Text.AlignVCenter + height: parent.height + anchors.left: swatch.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: UM.Theme.getSize("narrow_margin").width + } + MouseArea + { + anchors.fill: parent + onClicked: { base.currentItem = material } + hoverEnabled: true + onEntered: { material_slot.hovered = true } + onExited: { material_slot.hovered = false } + } + Button + { + id: favorite_button + text: "" + implicitWidth: UM.Theme.getSize("favorites_button").width + implicitHeight: UM.Theme.getSize("favorites_button").height + visible: material_slot.hovered || material_slot.is_favorite || favorite_button.hovered + anchors + { + right: parent.right + verticalCenter: parent.verticalCenter + } + onClicked: + { + if (material_slot.is_favorite) { + base.materialManager.removeFavorite(material.root_material_id) + material_slot.is_favorite = false + return + } + base.materialManager.addFavorite(material.root_material_id) + material_slot.is_favorite = true + return + } + style: ButtonStyle + { + background: Rectangle + { + anchors.fill: parent + color: "transparent" + } + } + UM.RecolorImage { + anchors + { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: UM.Theme.getSize("favorites_button_icon").width + height: UM.Theme.getSize("favorites_button_icon").height + sourceSize.width: width + sourceSize.height: height + color: + { + if (favorite_button.hovered) + { + return UM.Theme.getColor("primary_hover") + } + else + { + if (material_slot.is_favorite) + { + return UM.Theme.getColor("primary") + } + else + { + UM.Theme.getColor("text_inactive") + } + } + } + source: material_slot.is_favorite ? UM.Theme.getIcon("favorites_star_full") : UM.Theme.getIcon("favorites_star_empty") + } + } + } +} \ No newline at end of file diff --git a/resources/qml/Preferences/Materials/MaterialsTypeSection.qml b/resources/qml/Preferences/Materials/MaterialsTypeSection.qml new file mode 100644 index 0000000000..11bf2385e1 --- /dev/null +++ b/resources/qml/Preferences/Materials/MaterialsTypeSection.qml @@ -0,0 +1,109 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Uranium is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Rectangle +{ + id: material_type_section + property var expanded: base.collapsed_types.indexOf(model.brand + "_" + model.name) > -1 + property var colors_model: model.colors + height: childrenRect.height + width: parent.width + Rectangle + { + id: material_type_header_background + color: UM.Theme.getColor("lining") + anchors.bottom: material_type_header.bottom + anchors.left: material_type_header.left + height: UM.Theme.getSize("default_lining").height + width: material_type_header.width + } + Row + { + id: material_type_header + width: parent.width - 8 + anchors + { + left: parent.left + leftMargin: 8 + } + Label + { + text: model.name + height: UM.Theme.getSize("favorites_row").height + width: parent.width - UM.Theme.getSize("favorites_button").width + id: material_type_name + verticalAlignment: Text.AlignVCenter + } + Button + { + text: "" + implicitWidth: UM.Theme.getSize("favorites_button").width + implicitHeight: UM.Theme.getSize("favorites_button").height + UM.RecolorImage { + anchors + { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: height + color: "black" + source: material_type_section.expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") + } + style: ButtonStyle + { + background: Rectangle + { + anchors.fill: parent + color: "transparent" + } + } + } + } + MouseArea + { + anchors.fill: material_type_header + onPressed: + { + const i = base.collapsed_types.indexOf(model.brand + "_" + model.name) + if (i > -1) + { + // Remove it + base.collapsed_types.splice(i, 1) + material_type_section.expanded = false + } + else + { + // Add it + base.collapsed_types.push(model.brand + "_" + model.name) + material_type_section.expanded = true + } + } + } + Column + { + height: material_type_section.expanded ? childrenRect.height : 0 + visible: material_type_section.expanded + width: parent.width + anchors.top: material_type_header.bottom + anchors.left: parent.left + Repeater + { + model: colors_model + delegate: MaterialsSlot { + material: model + } + } + } +} \ No newline at end of file diff --git a/resources/qml/Preferences/MaterialView.qml b/resources/qml/Preferences/Materials/MaterialsView.qml similarity index 96% rename from resources/qml/Preferences/MaterialView.qml rename to resources/qml/Preferences/Materials/MaterialsView.qml index 0929f1790a..a03e5c48d7 100644 --- a/resources/qml/Preferences/MaterialView.qml +++ b/resources/qml/Preferences/Materials/MaterialsView.qml @@ -8,6 +8,8 @@ import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura +import ".." // Access to ReadOnlyTextArea.qml + TabView { id: base @@ -30,20 +32,24 @@ TabView property bool reevaluateLinkedMaterials: false property string linkedMaterialNames: { - if (reevaluateLinkedMaterials) { + if (reevaluateLinkedMaterials) + { reevaluateLinkedMaterials = false; } - if (!base.containerId || !base.editingEnabled) { + if (!base.containerId || !base.editingEnabled) + { return "" } - var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.currentMaterialNode, true); - if (linkedMaterials.length == 0) { + var linkedMaterials = Cura.ContainerManager.getLinkedMaterials(base.currentItem.container_node, true); + if (linkedMaterials.length == 0) + { return "" } return linkedMaterials.join(", "); } - function getApproximateDiameter(diameter) { + function getApproximateDiameter(diameter) + { return Math.round(diameter); } @@ -154,13 +160,15 @@ TabView } Label { width: scrollView.columnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Color") } - Row { + Row + { width: scrollView.columnWidth height: parent.rowHeight spacing: Math.round(UM.Theme.getSize("default_margin").width / 2) // color indicator square - Rectangle { + Rectangle + { id: colorSelector color: properties.color_code @@ -171,7 +179,8 @@ TabView anchors.verticalCenter: parent.verticalCenter // open the color selection dialog on click - MouseArea { + MouseArea + { anchors.fill: parent onClicked: colorDialog.open() enabled: base.editingEnabled @@ -179,7 +188,8 @@ TabView } // pretty color name text field - ReadOnlyTextField { + ReadOnlyTextField + { id: colorLabel; text: properties.color_name; readOnly: !base.editingEnabled @@ -188,7 +198,8 @@ TabView // popup dialog to select a new color // if successful it sets the properties.color_code value to the new color - ColorDialog { + ColorDialog + { id: colorDialog color: properties.color_code onAccepted: base.setMetaDataEntry("color_code", properties.color_code, color) @@ -258,7 +269,8 @@ TabView decimals: 2 maximumValue: 100000000 - onValueChanged: { + onValueChanged: + { base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value)) updateCostPerMeter() } @@ -275,7 +287,8 @@ TabView decimals: 0 maximumValue: 10000 - onValueChanged: { + onValueChanged: + { base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value)) updateCostPerMeter() } @@ -401,7 +414,8 @@ TabView { id: spinBox anchors.left: label.right - value: { + value: + { // In case the setting is not in the material... if (!isNaN(parseFloat(materialPropertyProvider.properties.value))) { @@ -493,8 +507,10 @@ TabView } // Tiny convenience function to check if a value really changed before trying to set it. - function setMetaDataEntry(entry_name, old_value, new_value) { - if (old_value != new_value) { + function setMetaDataEntry(entry_name, old_value, new_value) + { + if (old_value != new_value) + { Cura.ContainerManager.setContainerMetaDataEntry(base.currentMaterialNode, entry_name, new_value) // make sure the UI properties are updated as well since we don't re-fetch the entire model here // When the entry_name is something like properties/diameter, we take the last part of the entry_name @@ -546,10 +562,11 @@ TabView } // update the display name of the material - function updateMaterialDisplayName (old_name, new_name) + function updateMaterialDisplayName(old_name, new_name) { // don't change when new name is the same - if (old_name == new_name) { + if (old_name == new_name) + { return; } diff --git a/resources/qml/PrintMonitor.qml b/resources/qml/PrintMonitor.qml index b24bcb6d6c..7727f9cb52 100644 --- a/resources/qml/PrintMonitor.qml +++ b/resources/qml/PrintMonitor.qml @@ -26,7 +26,6 @@ Column OutputDeviceHeader { - width: parent.width outputDevice: connectedDevice } diff --git a/resources/qml/PrinterOutput/OutputDeviceHeader.qml b/resources/qml/PrinterOutput/OutputDeviceHeader.qml index d5ce32786c..03e6d78699 100644 --- a/resources/qml/PrinterOutput/OutputDeviceHeader.qml +++ b/resources/qml/PrinterOutput/OutputDeviceHeader.qml @@ -16,7 +16,7 @@ Item Rectangle { - anchors.fill: parent + height: childrenRect.height color: UM.Theme.getColor("setting_category") property var activePrinter: outputDevice != null ? outputDevice.activePrinter : null diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml index 0e0eec7277..2a0a523026 100644 --- a/resources/qml/SaveButton.qml +++ b/resources/qml/SaveButton.qml @@ -7,6 +7,7 @@ import QtQuick.Controls.Styles 1.1 import QtQuick.Layouts 1.1 import UM 1.1 as UM +import Cura 1.0 as Cura Item { id: base; @@ -257,7 +258,8 @@ Item { onClicked: { forceActiveFocus(); - UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, { "filter_by_machine": true, "preferred_mimetype":Printer.preferredOutputMimetype }); + UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, + { "filter_by_machine": true, "preferred_mimetypes": Cura.MachineManager.activeMachine.preferred_output_file_formats }); } style: ButtonStyle { diff --git a/resources/qml/Settings/SettingComboBox.qml b/resources/qml/Settings/SettingComboBox.qml index 5462c26398..5d283d5ebb 100644 --- a/resources/qml/Settings/SettingComboBox.qml +++ b/resources/qml/Settings/SettingComboBox.qml @@ -20,13 +20,6 @@ SettingItem anchors.fill: parent - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.NoButton - onWheel: wheel.accepted = true - } - background: Rectangle { color: diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 83f06ebc5f..4c00a60d0e 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -71,13 +71,6 @@ SettingItem currentIndex: propertyProvider.properties.value - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.NoButton - onWheel: wheel.accepted = true; - } - property string color: "#fff" Binding diff --git a/resources/qml/Settings/SettingOptionalExtruder.qml b/resources/qml/Settings/SettingOptionalExtruder.qml index db79468315..2d4f25125f 100644 --- a/resources/qml/Settings/SettingOptionalExtruder.qml +++ b/resources/qml/Settings/SettingOptionalExtruder.qml @@ -76,13 +76,6 @@ SettingItem when: control.model.items.length > 0 } - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.NoButton - onWheel: wheel.accepted = true; - } - property string color: "#fff" Binding diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 1b3f0cbc20..e17f11bf99 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -561,6 +561,28 @@ Item visible: machineExtruderCount.properties.value > 1 } + Instantiator + { + id: customMenuItems + model: Cura.SidebarCustomMenuItemsModel { } + MenuItem + { + text: model.name + iconName: model.icon_name + onTriggered: + { + customMenuItems.model.callMenuItemMethod(name, model.actions, {"key": contextMenu.key}) + } + } + onObjectAdded: contextMenu.insertItem(index, object) + onObjectRemoved: contextMenu.removeItem(object) + } + + MenuSeparator + { + visible: customMenuItems.count > 0 + } + MenuItem { //: Settings context menu action diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 4e8911b3c1..6ee33dd2f2 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -476,8 +476,8 @@ Column { id: buildplateRow height: UM.Theme.getSize("sidebar_setup").height - // TODO Temporary hidden, add back again when feature ready - visible: false //Cura.MachineManager.hasVariantBuildplates && !sidebar.hideSettings + // TODO Only show in dev mode. Remove check when feature ready + visible: CuraSDKVersion == "dev" ? Cura.MachineManager.hasVariantBuildplates && !sidebar.hideSettings : false anchors { @@ -533,6 +533,7 @@ Column rightMargin: UM.Theme.getSize("sidebar_margin").width } + // TODO This was added to replace the buildplate selector. Remove this component when the feature is ready Label { id: materialCompatibilityLabel @@ -542,7 +543,7 @@ Column text: catalog.i18nc("@label", "Use glue with this material combination") font: UM.Theme.getFont("very_small") color: UM.Theme.getColor("text") - visible: buildplateCompatibilityError || buildplateCompatibilityWarning + visible: CuraSDKVersion == "dev" ? false : buildplateCompatibilityError || buildplateCompatibilityWarning wrapMode: Text.WordWrap opacity: 0.5 } diff --git a/resources/qml/Toolbar.qml b/resources/qml/Toolbar.qml index 613a462db9..a04b3650df 100644 --- a/resources/qml/Toolbar.qml +++ b/resources/qml/Toolbar.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -21,8 +21,8 @@ Item { id: buttons; - anchors.bottom: parent.bottom; - anchors.left: parent.left; + anchors.bottom: parent.bottom + anchors.left: parent.left spacing: UM.Theme.getSize("button_lining").width Repeater @@ -34,20 +34,22 @@ Item height: childrenRect.height Button { - text: model.name + text: model.name + (model.shortcut ? (" (" + model.shortcut + ")") : "") iconSource: (UM.Theme.getIcon(model.icon) != "") ? UM.Theme.getIcon(model.icon) : "file:///" + model.location + "/" + model.icon checkable: true checked: model.active enabled: model.enabled && UM.Selection.hasSelection && UM.Controller.toolsEnabled style: UM.Theme.styles.tool_button - onCheckedChanged: { - if (checked) { - base.activeY = y + onCheckedChanged: + { + if (checked) + { + base.activeY = y; } } - //Workaround since using ToolButton"s onClicked would break the binding of the checked property, instead + //Workaround since using ToolButton's onClicked would break the binding of the checked property, instead //just catch the click so we do not trigger that behaviour. MouseArea { @@ -57,7 +59,7 @@ Item forceActiveFocus() //First grab focus, so all the text fields are updated if(parent.checked) { - UM.Controller.setActiveTool(null) + UM.Controller.setActiveTool(null); } else { @@ -96,11 +98,13 @@ Item width: { - if (panel.item && panel.width > 0){ - return Math.max(panel.width + 2 * UM.Theme.getSize("default_margin").width) + if (panel.item && panel.width > 0) + { + return Math.max(panel.width + 2 * UM.Theme.getSize("default_margin").width); } - else { - return 0 + else + { + return 0; } } height: panel.item ? panel.height + 2 * UM.Theme.getSize("default_margin").height : 0; @@ -124,7 +128,7 @@ Item x: UM.Theme.getSize("default_margin").width; y: UM.Theme.getSize("default_margin").height; - source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : ""; + source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : "" enabled: UM.Controller.toolsEnabled; } } @@ -148,6 +152,6 @@ Item anchors.horizontalCenter: parent.horizontalCenter } - visible: toolHint.text != ""; + visible: toolHint.text != "" } } diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/WorkspaceSummaryDialog.qml index 079d840ae7..24e94beb88 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/WorkspaceSummaryDialog.qml @@ -24,6 +24,10 @@ UM.Dialog signal yes(); + function accept() { // pressing enter will call this function + close(); + yes(); + } onClosing: { @@ -290,4 +294,4 @@ UM.Dialog } } } -} \ No newline at end of file +} diff --git a/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg b/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg new file mode 100644 index 0000000000..a302f5b513 --- /dev/null +++ b/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Fast +definition = dagoma_discoeasy200 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pla + +[values] +material_print_temperature = =default_material_print_temperature + 10 +material_bed_temperature_layer_0 = =default_material_bed_temperature + 10 diff --git a/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg b/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg new file mode 100644 index 0000000000..b26eb1d910 --- /dev/null +++ b/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg @@ -0,0 +1,13 @@ +[general] +version = 4 +name = Fine +definition = dagoma_discoeasy200 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_pla + +[values] diff --git a/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg b/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg new file mode 100644 index 0000000000..9ec56f696a --- /dev/null +++ b/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Standard +definition = dagoma_discoeasy200 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_pla + +[values] +material_print_temperature = =default_material_print_temperature + 5 +material_bed_temperature_layer_0 = =default_material_bed_temperature + 5 diff --git a/resources/quality/dagoma/dagoma_global_fast.inst.cfg b/resources/quality/dagoma/dagoma_global_fast.inst.cfg new file mode 100644 index 0000000000..28569387f2 --- /dev/null +++ b/resources/quality/dagoma/dagoma_global_fast.inst.cfg @@ -0,0 +1,14 @@ +[general] +version = 4 +name = Fast +definition = dagoma_discoeasy200 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +global_quality = True + +[values] +layer_height = 0.2 diff --git a/resources/quality/dagoma/dagoma_global_fine.inst.cfg b/resources/quality/dagoma/dagoma_global_fine.inst.cfg new file mode 100644 index 0000000000..1f7d577c1b --- /dev/null +++ b/resources/quality/dagoma/dagoma_global_fine.inst.cfg @@ -0,0 +1,14 @@ +[general] +version = 4 +name = Fine +definition = dagoma_discoeasy200 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +global_quality = True + +[values] +layer_height = 0.1 diff --git a/resources/quality/dagoma/dagoma_global_standard.inst.cfg b/resources/quality/dagoma/dagoma_global_standard.inst.cfg new file mode 100644 index 0000000000..167062c1d7 --- /dev/null +++ b/resources/quality/dagoma/dagoma_global_standard.inst.cfg @@ -0,0 +1,14 @@ +[general] +version = 4 +name = Standard +definition = dagoma_discoeasy200 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +global_quality = True + +[values] +layer_height = 0.15 diff --git a/resources/quality/dagoma/dagoma_neva_magis_pla_fast.inst.cfg b/resources/quality/dagoma/dagoma_neva_magis_pla_fast.inst.cfg new file mode 100644 index 0000000000..e52cba165c --- /dev/null +++ b/resources/quality/dagoma/dagoma_neva_magis_pla_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Fast +definition = dagoma_neva_magis + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pla + +[values] +material_print_temperature = =default_material_print_temperature + 10 +material_bed_temperature_layer_0 = =default_material_bed_temperature + 10 diff --git a/resources/quality/dagoma/dagoma_neva_magis_pla_fine.inst.cfg b/resources/quality/dagoma/dagoma_neva_magis_pla_fine.inst.cfg new file mode 100644 index 0000000000..033cfbc8fa --- /dev/null +++ b/resources/quality/dagoma/dagoma_neva_magis_pla_fine.inst.cfg @@ -0,0 +1,13 @@ +[general] +version = 4 +name = Fine +definition = dagoma_neva_magis + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_pla + +[values] diff --git a/resources/quality/dagoma/dagoma_neva_magis_pla_standard.inst.cfg b/resources/quality/dagoma/dagoma_neva_magis_pla_standard.inst.cfg new file mode 100644 index 0000000000..d07d5b58d5 --- /dev/null +++ b/resources/quality/dagoma/dagoma_neva_magis_pla_standard.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Standard +definition = dagoma_neva_magis + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_pla + +[values] +material_print_temperature = =default_material_print_temperature + 5 +material_bed_temperature_layer_0 = =default_material_bed_temperature + 5 diff --git a/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg b/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg new file mode 100644 index 0000000000..efdf2f7d32 --- /dev/null +++ b/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Fast +definition = dagoma_neva + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pla + +[values] +material_print_temperature = =default_material_print_temperature + 10 +material_bed_temperature_layer_0 = =default_material_bed_temperature + 10 diff --git a/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg b/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg new file mode 100644 index 0000000000..50915db112 --- /dev/null +++ b/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg @@ -0,0 +1,13 @@ +[general] +version = 4 +name = Fine +definition = dagoma_neva + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_pla + +[values] diff --git a/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg b/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg new file mode 100644 index 0000000000..ed67800eac --- /dev/null +++ b/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Standard +definition = dagoma_neva + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_pla + +[values] +material_print_temperature = =default_material_print_temperature + 5 +material_bed_temperature_layer_0 = =default_material_bed_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg new file mode 100644 index 0000000000..f540400575 --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg @@ -0,0 +1,24 @@ +[general] +version = 4 +name = Fast (beta) +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_abs + +[values] +adhesion_type = raft +cool_fan_enabled = True +cool_fan_full_at_height = =layer_height * 2 +cool_fan_speed = 50 +cool_fan_speed_max = 50 +cool_fan_speed_min = 50 +cool_min_layer_time = 5 +cool_min_speed = 20 +material_bed_temperature = 80 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 + diff --git a/resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg similarity index 65% rename from resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg rename to resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg index 87d4031f28..2214813913 100644 --- a/resources/quality/deltacomb/deltacomb_abs_fast.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg @@ -1,7 +1,7 @@ [general] version = 4 +name = Normal (beta) definition = deltacomb -name = Fast Quality (beta) [metadata] setting_version = 5 @@ -12,13 +12,12 @@ material = generic_abs [values] adhesion_type = raft -layer_height = 0.2 -layer_height_0 = 0.2 cool_fan_enabled = True -cool_fan_full_at_height = 0.4 +cool_fan_full_at_height = =layer_height * 2 cool_fan_speed = 50 cool_fan_speed_max = 50 cool_fan_speed_min = 50 -cool_min_layer_time = 3 +cool_min_layer_time = 5 cool_min_speed = 20 material_bed_temperature = 80 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_abs_high.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg similarity index 62% rename from resources/quality/deltacomb/deltacomb_abs_high.inst.cfg rename to resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg index f24b6f9662..c196209553 100644 --- a/resources/quality/deltacomb/deltacomb_abs_high.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg @@ -1,24 +1,23 @@ [general] version = 4 +name = Extra Fine (beta) definition = deltacomb -name = High Quality (beta) [metadata] setting_version = 5 type = quality quality_type = high -weight = 1 +weight = 0 material = generic_abs [values] adhesion_type = raft -layer_height = 0.1 -layer_height_0 = 0.1 cool_fan_enabled = True -cool_fan_full_at_height = 0.2 +cool_fan_full_at_height = =layer_height * 2 cool_fan_speed = 50 cool_fan_speed_max = 50 cool_fan_speed_min = 50 -cool_min_layer_time = 3 +cool_min_layer_time = 5 cool_min_speed = 20 material_bed_temperature = 80 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg similarity index 66% rename from resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg rename to resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg index a5069cd827..332e1890c6 100644 --- a/resources/quality/deltacomb/deltacomb_abs_normal.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg @@ -1,7 +1,7 @@ [general] version = 4 +name = Fine (beta) definition = deltacomb -name = Normal Quality (beta) [metadata] setting_version = 5 @@ -12,13 +12,12 @@ material = generic_abs [values] adhesion_type = raft -layer_height = 0.15 -layer_height_0 = 0.15 cool_fan_enabled = True -cool_fan_full_at_height = 0.3 +cool_fan_full_at_height = =layer_height * 2 cool_fan_speed = 50 cool_fan_speed_max = 50 cool_fan_speed_min = 50 -cool_min_layer_time = 3 +cool_min_layer_time = 5 cool_min_speed = 20 material_bed_temperature = 80 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg new file mode 100644 index 0000000000..674174c0bd --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 4 +name = Extra Fast (beta) +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +material = generic_abs + +[values] +adhesion_type = raft +cool_fan_enabled = True +cool_fan_full_at_height = =layer_height * 2 +cool_fan_speed = 50 +cool_fan_speed_max = 50 +cool_fan_speed_min = 50 +cool_min_layer_time = 5 +cool_min_speed = 20 +material_bed_temperature = 80 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg new file mode 100755 index 0000000000..f8887810d5 --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Fast +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +global_quality = True + +[values] +layer_height = 0.2 +layer_height_0 = =layer_height diff --git a/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg new file mode 100755 index 0000000000..99030a084b --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Normal +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +global_quality = True + +[values] +layer_height = 0.15 +layer_height_0 = =layer_height diff --git a/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg new file mode 100755 index 0000000000..d6d853466a --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Extra Fine +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = high +weight = 0 +global_quality = True + +[values] +layer_height = 0.05 +layer_height_0 = =layer_height * 2 diff --git a/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg new file mode 100755 index 0000000000..a3bafadeec --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Fine +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +global_quality = True + +[values] +layer_height = 0.1 +layer_height_0 = =layer_height * 2 diff --git a/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg new file mode 100755 index 0000000000..84c6e66f61 --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg @@ -0,0 +1,15 @@ +[general] +version = 4 +name = Extra Fast +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +global_quality = True + +[values] +layer_height = 0.3 +layer_height_0 = =layer_height diff --git a/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg b/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg deleted file mode 100644 index 0deac00593..0000000000 --- a/resources/quality/deltacomb/deltacomb_nylon_fast.inst.cfg +++ /dev/null @@ -1,57 +0,0 @@ -[general] -version = 4 -name = Fast Quality (beta) -definition = deltacomb - -[metadata] -setting_version = 5 -type = quality -quality_type = fast -weight = -1 -material = generic_nylon - -[values] -adhesion_type = raft -brim_width = 4 -cool_fan_enabled = False -cool_fan_full_at_height = 0.45 -cool_fan_speed = 0 -cool_fan_speed_max = 0 -cool_fan_speed_min = 0 -cool_min_layer_time = 5 -cool_min_speed = 0 -infill_overlap = 15 -infill_sparse_density = 24 -layer_height = 0.20 -layer_height_0 = 0.15 -line_width = =machine_nozzle_size -material_flow = 100 -raft_airgap = 0.22 -raft_base_line_width= =line_width * 2 -raft_base_thickness = =layer_height_0 * 2 -raft_interface_line_width = =line_width -raft_interface_thickness = =layer_height -raft_margin = 5 -raft_surface_layers = 2 -raft_surface_line_width = =line_width -raft_surface_thickness = =layer_height -retraction_hop = 0.5 -retraction_hop_enabled = False -retraction_hop_only_when_collides = True -skin_overlap = 10 -skirt_brim_minimal_length = 75 -skirt_gap = 1.5 -skirt_line_count = 5 -speed_infill = =speed_print -speed_layer_0 = =math.ceil(speed_print * 25 / 50) -speed_print = 50 -speed_topbottom = =math.ceil(speed_print * 40 / 50) -speed_travel = 200 -speed_wall_0 = =math.ceil(speed_print * 40 / 50) -speed_wall_x = =speed_print -support_angle = 70 -support_type = buildplate -support_z_distance = 0.15 -top_bottom_thickness = 0.8 -wall_thickness = 0.8 -z_seam_type = random diff --git a/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg b/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg deleted file mode 100644 index a5d00b40e7..0000000000 --- a/resources/quality/deltacomb/deltacomb_nylon_high.inst.cfg +++ /dev/null @@ -1,57 +0,0 @@ -[general] -version = 4 -name = High Quality (beta) -definition = deltacomb - -[metadata] -setting_version = 5 -type = quality -quality_type = high -weight = 1 -material = generic_nylon - -[values] -adhesion_type = raft -brim_width = 4 -cool_fan_enabled = False -cool_fan_full_at_height = 0.45 -cool_fan_speed = 0 -cool_fan_speed_max = 0 -cool_fan_speed_min = 0 -cool_min_layer_time = 5 -cool_min_speed = 0 -infill_overlap = 15 -infill_sparse_density = 24 -layer_height = 0.10 -layer_height_0 = 0.10 -line_width = =machine_nozzle_size -material_flow = 100 -raft_airgap = 0.22 -raft_base_line_width= =line_width * 2 -raft_base_thickness = =layer_height_0 * 2 -raft_interface_line_width = =line_width -raft_interface_thickness = =layer_height -raft_margin = 5 -raft_surface_layers = 2 -raft_surface_line_width = =line_width -raft_surface_thickness = =layer_height -retraction_hop = 0.5 -retraction_hop_enabled = False -retraction_hop_only_when_collides = True -skin_overlap = 10 -skirt_brim_minimal_length = 75 -skirt_gap = 1.5 -skirt_line_count = 5 -speed_infill = =speed_print -speed_layer_0 = =math.ceil(speed_print * 25 / 50) -speed_print = 50 -speed_topbottom = =math.ceil(speed_print * 40 / 50) -speed_travel = 200 -speed_wall_0 = =math.ceil(speed_print * 40 / 50) -speed_wall_x = =speed_print -support_angle = 70 -support_type = buildplate -support_z_distance = 0.15 -top_bottom_thickness = 0.8 -wall_thickness = 0.8 -z_seam_type = random diff --git a/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg b/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg deleted file mode 100644 index 06e79c8dc2..0000000000 --- a/resources/quality/deltacomb/deltacomb_nylon_normal.inst.cfg +++ /dev/null @@ -1,57 +0,0 @@ -[general] -version = 4 -name = Normal Quality (beta) -definition = deltacomb - -[metadata] -setting_version = 5 -type = quality -quality_type = normal -weight = 0 -material = generic_nylon - -[values] -adhesion_type = raft -brim_width = 4 -cool_fan_enabled = False -cool_fan_full_at_height = 0.45 -cool_fan_speed = 0 -cool_fan_speed_max = 0 -cool_fan_speed_min = 0 -cool_min_layer_time = 5 -cool_min_speed = 0 -infill_overlap = 15 -infill_sparse_density = 24 -layer_height = 0.15 -layer_height_0 = 0.10 -line_width = =machine_nozzle_size -material_flow = 100 -raft_airgap = 0.22 -raft_base_line_width= =line_width * 2 -raft_base_thickness = =layer_height_0 * 2 -raft_interface_line_width = =line_width -raft_interface_thickness = =layer_height -raft_margin = 5 -raft_surface_layers = 2 -raft_surface_line_width = =line_width -raft_surface_thickness = =layer_height -retraction_hop = 0.5 -retraction_hop_enabled = False -retraction_hop_only_when_collides = True -skin_overlap = 10 -skirt_brim_minimal_length = 75 -skirt_gap = 1.5 -skirt_line_count = 5 -speed_infill = =speed_print -speed_layer_0 = =math.ceil(speed_print * 25 / 50) -speed_print = 50 -speed_topbottom = =math.ceil(speed_print * 40 / 50) -speed_travel = 200 -speed_wall_0 = =math.ceil(speed_print * 40 / 50) -speed_wall_x = =speed_print -support_angle = 70 -support_type = buildplate -support_z_distance = 0.15 -top_bottom_thickness = 0.8 -wall_thickness = 0.8 -z_seam_type = random diff --git a/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg new file mode 100644 index 0000000000..c4f884486e --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 4 +name = Fast +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pla + +[values] +adhesion_type = skirt +cool_fan_enabled = True +cool_fan_full_at_height = =layer_height +cool_fan_speed = 100 +cool_fan_speed_max = 100 +cool_fan_speed_min = 100 +cool_min_layer_time = 5 +cool_min_speed = 20 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg similarity index 70% rename from resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg rename to resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg index ea4a2908b3..714d4e3517 100644 --- a/resources/quality/deltacomb/deltacomb_pla_fast.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg @@ -1,7 +1,7 @@ [general] version = 4 +name = Normal definition = deltacomb -name = Fast Quality [metadata] setting_version = 5 @@ -12,12 +12,11 @@ material = generic_pla [values] adhesion_type = skirt -layer_height = 0.2 -layer_height_0 = 0.2 cool_fan_enabled = True -cool_fan_full_at_height = 0.4 +cool_fan_full_at_height = =layer_height cool_fan_speed = 100 cool_fan_speed_max = 100 cool_fan_speed_min = 100 cool_min_layer_time = 5 cool_min_speed = 20 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_pla_high.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg similarity index 79% rename from resources/quality/deltacomb/deltacomb_pla_high.inst.cfg rename to resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg index 69f8478cfe..774b8969c0 100644 --- a/resources/quality/deltacomb/deltacomb_pla_high.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg @@ -1,21 +1,19 @@ [general] version = 4 +name = Extra Fine definition = deltacomb -name = High Quality [metadata] setting_version = 5 type = quality quality_type = high -weight = 1 +weight = 0 material = generic_pla [values] adhesion_type = skirt -layer_height = 0.1 -layer_height_0 = 0.1 cool_fan_enabled = True -cool_fan_full_at_height = 0.2 +cool_fan_full_at_height = =layer_height cool_fan_speed = 100 cool_fan_speed_max = 100 cool_fan_speed_min = 100 diff --git a/resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg similarity index 71% rename from resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg rename to resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg index 2e9dca5c25..58470ed650 100644 --- a/resources/quality/deltacomb/deltacomb_pla_normal.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg @@ -1,7 +1,7 @@ [general] version = 4 +name = Fine definition = deltacomb -name = Normal Quality [metadata] setting_version = 5 @@ -12,12 +12,11 @@ material = generic_pla [values] adhesion_type = skirt -layer_height = 0.15 -layer_height_0 = 0.15 cool_fan_enabled = True -cool_fan_full_at_height = 0.3 +cool_fan_full_at_height = =layer_height cool_fan_speed = 100 cool_fan_speed_max = 100 cool_fan_speed_min = 100 cool_min_layer_time = 5 cool_min_speed = 20 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg new file mode 100644 index 0000000000..9c00877c24 --- /dev/null +++ b/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 4 +name = Extra Fast +definition = deltacomb + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +material = generic_pla + +[values] +adhesion_type = skirt +cool_fan_enabled = True +cool_fan_full_at_height = =layer_height +cool_fan_speed = 100 +cool_fan_speed_max = 100 +cool_fan_speed_min = 100 +cool_min_layer_time = 5 +cool_min_speed = 20 +material_print_temperature_layer_0 = =default_material_print_temperature + 5 diff --git a/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg new file mode 100644 index 0000000000..ac4f9ee81d --- /dev/null +++ b/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg @@ -0,0 +1,17 @@ +[general] +version = 4 +name = Coarse +definition = peopoly_moai + +[metadata] +setting_version = 5 +type = quality +quality_type = coarse +weight = 3 + +[values] +layer_height = 0.08 +speed_print = 90 +speed_travel = 120 +speed_travel_layer_0 = 100 +speed_wall = 90 diff --git a/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg new file mode 100644 index 0000000000..2d21b1f7e0 --- /dev/null +++ b/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 4 +name = Draft +definition = peopoly_moai + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = 4 + +[values] +layer_height = 0.1 +speed_print = 85 +speed_travel = 120 +speed_travel_layer_0 = 100 +speed_wall = 85 +speed_slowdown_layers = 2 diff --git a/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg new file mode 100644 index 0000000000..796c2cff3c --- /dev/null +++ b/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 4 +name = Extra High +definition = peopoly_moai + +[metadata] +setting_version = 5 +type = quality +quality_type = extra_high +weight = 0 + +[values] +layer_height = 0.02 +speed_print = 185 +speed_travel = 185 +speed_travel_layer_0 = 100 +speed_wall = 185 +speed_slowdown_layers = 5 diff --git a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg index 36b5f21ff8..b36163d9f1 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg @@ -1,6 +1,6 @@ [general] version = 4 -name = Extra Fine +name = High definition = peopoly_moai [metadata] @@ -10,8 +10,9 @@ quality_type = high weight = 1 [values] -infill_sparse_density = 70 -layer_height = 0.05 -top_bottom_thickness = 0.4 -wall_thickness = 0.4 -speed_print = 150 +layer_height = 0.04 +speed_print = 140 +speed_travel = 140 +speed_travel_layer_0 = 100 +speed_wall = 140 +speed_slowdown_layers = 4 diff --git a/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg deleted file mode 100644 index 48ffd07f33..0000000000 --- a/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[general] -version = 4 -name = Maximum Quality -definition = peopoly_moai - -[metadata] -setting_version = 5 -type = quality -quality_type = extra_high -weight = 2 - -[values] -infill_sparse_density = 70 -layer_height = 0.025 -top_bottom_thickness = 0.4 -wall_thickness = 0.4 -speed_print = 200 diff --git a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg index f5fe799ac3..cf67591ab2 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg @@ -1,17 +1,17 @@ [general] version = 4 -name = Fine +name = Normal definition = peopoly_moai [metadata] setting_version = 5 type = quality quality_type = normal -weight = 0 +weight = 2 [values] -infill_sparse_density = 70 -layer_height = 0.1 -top_bottom_thickness = 0.4 -wall_thickness = 0.4 -speed_print = 100 +layer_height = 0.06 +speed_print = 120 +speed_travel = 120 +speed_travel_layer_0 = 100 +speed_wall = 120 diff --git a/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg b/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg new file mode 100644 index 0000000000..8c6349d27a --- /dev/null +++ b/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg @@ -0,0 +1,31 @@ +[general] +version = 4 +name = TiZYX K25 Normal +definition = tizyx_k25 + +[metadata] +quality_type = normal +setting_version = 5 +type = quality +global_quality = True + +[values] +adhesion_type = skirt +skirt_line_count = 2 +skirt_gap = 2 +cool_fan_speed_0 = 100 +fill_outline_gaps = True +infill_angles = [0,90 ] +infill_sparse_density = 15 +layer_height = 0.2 +layer_height_0 = 0.25 +material_diameter = 1.75 +retraction_amount = 2.5 +retraction_min_travel = 2 +retraction_speed = 30 +skin_angles = [0,90] +speed_print = 60 +speed_topbottom = 50 +speed_wall_0 = 40 +top_layers = 4 +wall_line_count = 2 diff --git a/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg index 428f5c1101..5139a1fea8 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg @@ -15,8 +15,6 @@ variant = AA 0.25 cool_fan_speed = 40 infill_overlap = 15 material_final_print_temperature = =material_print_temperature - 5 -prime_tower_size = 12 -prime_tower_min_volume = 2 retraction_prime_speed = 25 speed_topbottom = =math.ceil(speed_print * 30 / 55) wall_thickness = 0.92 diff --git a/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg index 127032e118..4e81b4f39e 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg @@ -12,8 +12,6 @@ material = generic_cpe variant = AA 0.25 [values] -prime_tower_size = 12 -prime_tower_min_volume = 2 retraction_extrusion_window = 0.5 speed_infill = =math.ceil(speed_print * 40 / 55) speed_topbottom = =math.ceil(speed_print * 30 / 55) diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg index 52fe1cb01d..b6e6fdecb6 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg @@ -25,17 +25,15 @@ jerk_support = =math.ceil(jerk_print * 25 / 25) jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) machine_nozzle_cool_down_speed = 0.5 machine_nozzle_heat_up_speed = 2.5 -material_bed_temperature_layer_0 = 0 material_final_print_temperature = =material_print_temperature - 21 material_flow = 105 material_initial_print_temperature = =material_print_temperature - 16 material_print_temperature = =default_material_print_temperature - 2 -material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature + 4 material_standby_temperature = 100 multiple_mesh_overlap = 0.2 prime_tower_enable = True prime_tower_flow = 100 -prime_tower_min_volume = 10 retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg index 857ea39491..b64d37310e 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg @@ -26,17 +26,15 @@ jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) layer_height = 0.4 machine_nozzle_cool_down_speed = 0.5 machine_nozzle_heat_up_speed = 2.5 -material_bed_temperature_layer_0 = 0 material_final_print_temperature = =material_print_temperature - 21 material_flow = 105 material_initial_print_temperature = =material_print_temperature - 16 material_print_temperature = =default_material_print_temperature + 2 -material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 multiple_mesh_overlap = 0.2 prime_tower_enable = True prime_tower_flow = 100 -prime_tower_min_volume = 15 retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg index 10673c133a..d9e8f9ec2e 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg @@ -26,16 +26,14 @@ jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) layer_height = 0.3 machine_nozzle_cool_down_speed = 0.5 machine_nozzle_heat_up_speed = 2.5 -material_bed_temperature_layer_0 = 0 material_final_print_temperature = =material_print_temperature - 21 material_flow = 105 material_initial_print_temperature = =material_print_temperature - 16 -material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature + 2 material_standby_temperature = 100 multiple_mesh_overlap = 0.2 prime_tower_enable = True prime_tower_flow = 100 -prime_tower_min_volume = 20 retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg index e58a1bd87d..f2e05b08e8 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg @@ -15,8 +15,6 @@ variant = AA 0.25 cool_fan_speed = 40 infill_overlap = 15 material_final_print_temperature = =material_print_temperature - 5 -prime_tower_size = 12 -prime_tower_min_volume = 2 retraction_prime_speed = 25 speed_topbottom = =math.ceil(speed_print * 30 / 55) wall_thickness = 0.92 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg index 1c1833a385..2068ed51c0 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg @@ -12,8 +12,6 @@ material = generic_cpe variant = AA 0.25 [values] -prime_tower_size = 12 -prime_tower_min_volume = 2 retraction_extrusion_window = 0.5 speed_infill = =math.ceil(speed_print * 40 / 55) speed_topbottom = =math.ceil(speed_print * 30 / 55) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg new file mode 100644 index 0000000000..c8d64f9dcb --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg @@ -0,0 +1,36 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_abs +variant = AA 0.4 +buildplate = Aluminum + +[values] +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_print_temperature = =default_material_print_temperature + 20 +material_initial_print_temperature = =material_print_temperature - 15 +material_final_print_temperature = =material_print_temperature - 20 +prime_tower_enable = False +skin_overlap = 20 +speed_print = 60 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 35 / 60) +speed_wall = =math.ceil(speed_print * 45 / 60) +speed_wall_0 = =math.ceil(speed_wall * 35 / 45) +wall_thickness = 1 + +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +speed_infill = =math.ceil(speed_print * 50 / 60) + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg new file mode 100644 index 0000000000..c7fa604e89 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg @@ -0,0 +1,35 @@ +[general] +version = 4 +name = Normal +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_abs +variant = AA 0.4 +buildplate = Aluminum + +[values] +cool_min_speed = 7 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_print_temperature = =default_material_print_temperature + 15 +material_initial_print_temperature = =material_print_temperature - 15 +material_final_print_temperature = =material_print_temperature - 20 +prime_tower_enable = False +speed_print = 60 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 30 / 60) +speed_wall = =math.ceil(speed_print * 40 / 60) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) + +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +speed_infill = =math.ceil(speed_print * 45 / 60) + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg new file mode 100644 index 0000000000..187023d3c0 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg @@ -0,0 +1,34 @@ +[general] +version = 4 +name = Extra Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = high +weight = 1 +material = generic_abs +variant = AA 0.4 +buildplate = Aluminum + +[values] +cool_min_speed = 12 +machine_nozzle_cool_down_speed = 0.8 +machine_nozzle_heat_up_speed = 1.5 +material_print_temperature = =default_material_print_temperature + 5 +material_initial_print_temperature = =material_print_temperature - 15 +material_final_print_temperature = =material_print_temperature - 20 +prime_tower_enable = False +speed_print = 50 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 30 / 50) +speed_wall = =math.ceil(speed_print * 30 / 50) + +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +speed_infill = =math.ceil(speed_print * 40 / 50) + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..81cb27f060 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg @@ -0,0 +1,34 @@ +[general] +version = 4 +name = Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_abs +variant = AA 0.4 +buildplate = Aluminum + +[values] +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_print_temperature = =default_material_print_temperature + 10 +material_initial_print_temperature = =material_print_temperature - 15 +material_final_print_temperature = =material_print_temperature - 20 +prime_tower_enable = False +speed_print = 55 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 30 / 55) +speed_wall = =math.ceil(speed_print * 30 / 55) + +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +speed_infill = =math.ceil(speed_print * 40 / 55) + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.17 + diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg new file mode 100644 index 0000000000..46e3483a6a --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg @@ -0,0 +1,54 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_cpe_plus +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +cool_fan_speed_max = 80 +cool_min_speed = 5 +infill_line_width = =round(line_width * 0.35 / 0.35, 2) +infill_overlap = 0 +infill_wipe_dist = 0 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 10 +material_print_temperature_layer_0 = =material_print_temperature +multiple_mesh_overlap = 0 +prime_tower_enable = True +prime_tower_wipe_enabled = True +retraction_combing = off +retraction_extrusion_window = 1 +retraction_hop = 0.2 +retraction_hop_enabled = False +retraction_hop_only_when_collides = True +skin_overlap = 20 +speed_layer_0 = 20 +speed_print = 50 +speed_topbottom = =math.ceil(speed_print * 40 / 50) + +speed_wall = =math.ceil(speed_print * 50 / 50) +speed_wall_0 = =math.ceil(speed_wall * 40 / 50) +support_bottom_distance = =support_z_distance +support_z_distance = =layer_height +wall_0_inset = 0 +wall_thickness = 1 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.17 + diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg new file mode 100644 index 0000000000..5c235b656a --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg @@ -0,0 +1,52 @@ +[general] +version = 4 +name = Normal +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_cpe_plus +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +cool_fan_speed_max = 80 +cool_min_speed = 6 +infill_line_width = =round(line_width * 0.35 / 0.35, 2) +infill_overlap = 0 +infill_wipe_dist = 0 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 10 +material_print_temperature_layer_0 = =material_print_temperature +multiple_mesh_overlap = 0 +prime_tower_enable = True +prime_tower_wipe_enabled = True +retraction_combing = off +retraction_extrusion_window = 1 +retraction_hop = 0.2 +retraction_hop_enabled = False +retraction_hop_only_when_collides = True +skin_overlap = 20 +speed_layer_0 = 20 +speed_print = 45 +speed_topbottom = =math.ceil(speed_print * 35 / 45) + +speed_wall = =math.ceil(speed_print * 45 / 45) +speed_wall_0 = =math.ceil(speed_wall * 35 / 45) +support_bottom_distance = =support_z_distance +support_z_distance = =layer_height +wall_0_inset = 0 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg new file mode 100644 index 0000000000..326a730fe4 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg @@ -0,0 +1,55 @@ +[general] +version = 4 +name = Extra Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = high +weight = 1 +material = generic_cpe_plus +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +cool_fan_speed_max = 50 +cool_min_speed = 5 +infill_line_width = =round(line_width * 0.35 / 0.35, 2) +infill_overlap = 0 +infill_wipe_dist = 0 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature +multiple_mesh_overlap = 0 +prime_tower_enable = True +prime_tower_wipe_enabled = True +retraction_combing = off +retraction_extrusion_window = 1 +retraction_hop = 0.2 +retraction_hop_enabled = False +retraction_hop_only_when_collides = True +skin_overlap = 20 +speed_layer_0 = 20 +speed_print = 40 +speed_topbottom = =math.ceil(speed_print * 30 / 35) + +speed_wall = =math.ceil(speed_print * 35 / 40) +speed_wall_0 = =math.ceil(speed_wall * 30 / 35) +support_bottom_distance = =support_z_distance +support_z_distance = =layer_height +wall_0_inset = 0 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.17 + diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..d40b2db90e --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg @@ -0,0 +1,54 @@ +[general] +version = 4 +name = Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_cpe_plus +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +cool_fan_speed_max = 50 +cool_min_speed = 7 +infill_line_width = =round(line_width * 0.35 / 0.35, 2) +infill_overlap = 0 +infill_wipe_dist = 0 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 5 +material_print_temperature_layer_0 = =material_print_temperature +multiple_mesh_overlap = 0 +prime_tower_enable = True +prime_tower_wipe_enabled = True +retraction_combing = off +retraction_extrusion_window = 1 +retraction_hop = 0.2 +retraction_hop_enabled = False +retraction_hop_only_when_collides = True +skin_overlap = 20 +speed_layer_0 = 20 +speed_print = 40 +speed_topbottom = =math.ceil(speed_print * 30 / 35) + +speed_wall = =math.ceil(speed_print * 35 / 40) +speed_wall_0 = =math.ceil(speed_wall * 30 / 35) +support_bottom_distance = =support_z_distance +support_z_distance = =layer_height +wall_0_inset = 0 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg new file mode 100644 index 0000000000..c812066e0c --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg @@ -0,0 +1,35 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_cpe +variant = AA 0.4 +buildplate = Aluminum + +[values] +material_print_temperature = =default_material_print_temperature + 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_final_print_temperature = =material_print_temperature - 10 +skin_overlap = 20 +speed_print = 60 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 35 / 60) +speed_wall = =math.ceil(speed_print * 45 / 60) +speed_wall_0 = =math.ceil(speed_wall * 35 / 45) +wall_thickness = 1 + + +infill_pattern = zigzag +speed_infill = =math.ceil(speed_print * 50 / 60) +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg new file mode 100644 index 0000000000..ef634316da --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg @@ -0,0 +1,33 @@ +[general] +version = 4 +name = Normal +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_cpe +variant = AA 0.4 +buildplate = Aluminum + +[values] +cool_min_speed = 7 +material_print_temperature = =default_material_print_temperature + 5 +material_initial_print_temperature = =material_print_temperature - 5 +material_final_print_temperature = =material_print_temperature - 10 +speed_print = 60 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 30 / 60) +speed_wall = =math.ceil(speed_print * 40 / 60) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) + +infill_pattern = zigzag +speed_infill = =math.ceil(speed_print * 50 / 60) +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg new file mode 100644 index 0000000000..cda97e6ab3 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg @@ -0,0 +1,34 @@ +[general] +version = 4 +name = Extra Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = high +weight = 1 +material = generic_cpe +variant = AA 0.4 +buildplate = Aluminum + +[values] +cool_min_speed = 12 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_print_temperature = =default_material_print_temperature - 5 +material_initial_print_temperature = =material_print_temperature - 5 +material_final_print_temperature = =material_print_temperature - 10 +speed_print = 50 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 30 / 50) +speed_wall = =math.ceil(speed_print * 30 / 50) + +infill_pattern = zigzag +speed_infill = =math.ceil(speed_print * 40 / 50) +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..5a75f3b6e3 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg @@ -0,0 +1,32 @@ +[general] +version = 4 +name = Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_cpe +variant = AA 0.4 +buildplate = Aluminum + +[values] +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_initial_print_temperature = =material_print_temperature - 5 +material_final_print_temperature = =material_print_temperature - 10 +speed_print = 55 +speed_layer_0 = 20 +speed_topbottom = =math.ceil(speed_print * 30 / 55) +speed_wall = =math.ceil(speed_print * 30 / 55) + +infill_pattern = zigzag +speed_infill = =math.ceil(speed_print * 45 / 55) +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg new file mode 100644 index 0000000000..f05ecddc25 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg @@ -0,0 +1,69 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pc +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = brim +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 90 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 6 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap = 0 +infill_overlap_mm = 0.05 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 10 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +raft_interface_thickness = =max(layer_height * 1.5, 0.225) +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg new file mode 100644 index 0000000000..6103519f1c --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg @@ -0,0 +1,69 @@ +[general] +version = 4 +name = Normal +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_pc +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = brim +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 85 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 7 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap_mm = 0.05 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature + 10 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +raft_interface_thickness = =max(layer_height * 1.5, 0.225) +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 + +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg new file mode 100644 index 0000000000..130afb8c91 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg @@ -0,0 +1,70 @@ +[general] +version = 4 +name = Extra Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = high +weight = 1 +material = generic_pc +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = brim +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 50 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 8 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap = 0 +infill_overlap_mm = 0.05 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature - 10 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +raft_interface_thickness = =max(layer_height * 1.5, 0.225) +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 + +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..9e1bf394d4 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg @@ -0,0 +1,68 @@ +[general] +version = 4 +name = Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_pc +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +adhesion_type = brim +brim_width = 20 +cool_fan_full_at_height = =layer_height_0 + layer_height +cool_fan_speed_max = 50 +cool_min_layer_time_fan_speed_max = 5 +cool_min_speed = 5 +infill_line_width = =round(line_width * 0.4 / 0.35, 2) +infill_overlap = 0 +infill_pattern = triangles +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +ooze_shield_angle = 40 +prime_tower_enable = True +prime_tower_wipe_enabled = True +raft_airgap = 0.25 +raft_interface_thickness = =max(layer_height * 1.5, 0.225) +retraction_count_max = 80 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 15 +skin_overlap = 30 +speed_layer_0 = 25 +speed_print = 50 +speed_topbottom = 25 + +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 25 / 40) +support_bottom_distance = =support_z_distance +support_interface_density = 87.5 +support_interface_pattern = lines +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +wall_0_inset = 0 +wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) +wall_thickness = 1.2 + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.17 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg new file mode 100644 index 0000000000..6124dff257 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg @@ -0,0 +1,65 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pp +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +brim_width = 20 +cool_fan_speed_max = 100 +cool_min_layer_time = 7 +cool_min_layer_time_fan_speed_max = 7 +cool_min_speed = 2.5 +infill_line_width = =round(line_width * 0.38 / 0.38, 2) +infill_overlap = 0 +infill_pattern = tetrahedral +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +line_width = =machine_nozzle_size * 0.95 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_bed_temperature_layer_0 = =material_bed_temperature +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature - 5 +material_print_temperature_layer_0 = =material_print_temperature + 5 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +prime_tower_enable = False +prime_tower_size = 16 +prime_tower_wipe_enabled = True +retraction_count_max = 12 +retraction_extra_prime_amount = 0.8 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 18 +speed_equalize_flow_enabled = True +speed_layer_0 = 15 +speed_print = 25 +speed_topbottom = =math.ceil(speed_print * 25 / 25) +speed_travel_layer_0 = 50 +speed_wall = =math.ceil(speed_print * 25 / 25) +speed_wall_0 = =math.ceil(speed_wall * 25 / 25) +support_angle = 50 +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +wall_0_inset = 0 +wall_line_width_x = =line_width +wall_thickness = =line_width * 3 + +default_material_bed_temperature = 95 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg new file mode 100644 index 0000000000..2791e9f5d5 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg @@ -0,0 +1,67 @@ +[general] +version = 4 +name = Normal +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = fast +weight = -1 +material = generic_pp +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +brim_width = 20 +cool_fan_speed_max = 100 +cool_min_layer_time = 7 +cool_min_layer_time_fan_speed_max = 7 +cool_min_speed = 2.5 +infill_line_width = =round(line_width * 0.38 / 0.38, 2) +infill_overlap = 0 +infill_pattern = tetrahedral +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +line_width = =machine_nozzle_size * 0.95 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_bed_temperature_layer_0 = =material_bed_temperature +material_final_print_temperature = =material_print_temperature - 12 +material_initial_print_temperature = =material_print_temperature - 2 +material_print_temperature = =default_material_print_temperature - 13 +material_print_temperature_layer_0 = =material_print_temperature + 3 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +prime_tower_enable = False +prime_tower_size = 16 +prime_tower_wipe_enabled = True +retraction_count_max = 12 +retraction_extra_prime_amount = 0.8 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 18 +speed_equalize_flow_enabled = True +speed_layer_0 = 15 +speed_print = 25 +speed_topbottom = =math.ceil(speed_print * 25 / 25) + +speed_travel_layer_0 = 50 +speed_wall = =math.ceil(speed_print * 25 / 25) +speed_wall_0 = =math.ceil(speed_wall * 25 / 25) +support_angle = 50 +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +top_bottom_thickness = 1.1 +wall_0_inset = 0 +wall_line_width_x = =line_width +wall_thickness = =line_width * 3 + +default_material_bed_temperature = 95 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg new file mode 100644 index 0000000000..f78b4048fb --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg @@ -0,0 +1,68 @@ +[general] +version = 4 +name = Fine +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = normal +weight = 0 +material = generic_pp +variant = AA 0.4 +buildplate = Aluminum + +[values] +acceleration_enabled = True +acceleration_print = 4000 +brim_width = 20 +cool_fan_speed_max = 100 +cool_min_layer_time = 7 +cool_min_layer_time_fan_speed_max = 7 +cool_min_speed = 2.5 +infill_line_width = =round(line_width * 0.38 / 0.38, 2) +infill_overlap = 0 +infill_pattern = tetrahedral +infill_wipe_dist = 0.1 +jerk_enabled = True +jerk_print = 25 +line_width = =machine_nozzle_size * 0.95 +machine_min_cool_heat_time_window = 15 +machine_nozzle_cool_down_speed = 0.85 +machine_nozzle_heat_up_speed = 1.5 +material_bed_temperature_layer_0 = =material_bed_temperature +material_final_print_temperature = =material_print_temperature - 10 +material_initial_print_temperature = =material_print_temperature - 5 +material_print_temperature = =default_material_print_temperature - 15 +material_print_temperature_layer_0 = =material_print_temperature + 3 +material_standby_temperature = 100 +multiple_mesh_overlap = 0 +prime_tower_enable = False +prime_tower_size = 16 +prime_tower_wipe_enabled = True +retraction_count_max = 12 +retraction_extra_prime_amount = 0.8 +retraction_extrusion_window = 1 +retraction_hop = 2 +retraction_hop_only_when_collides = True +retraction_min_travel = 0.8 +retraction_prime_speed = 18 +speed_equalize_flow_enabled = True +speed_layer_0 = 15 +speed_print = 25 +speed_topbottom = =math.ceil(speed_print * 25 / 25) + +speed_travel_layer_0 = 50 +speed_wall = =math.ceil(speed_print * 25 / 25) +speed_wall_0 = =math.ceil(speed_wall * 25 / 25) +support_angle = 50 +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 35 +top_bottom_thickness = 1 +wall_0_inset = 0 +wall_line_width_x = =line_width +wall_thickness = =line_width * 3 + +default_material_bed_temperature = 95 + diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg index 889ffaf567..e8c58ce32c 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg @@ -23,17 +23,15 @@ jerk_support = =math.ceil(jerk_print * 25 / 25) jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) machine_nozzle_cool_down_speed = 0.5 machine_nozzle_heat_up_speed = 2.5 -material_bed_temperature_layer_0 = 0 material_final_print_temperature = =material_print_temperature - 21 material_flow = 105 material_initial_print_temperature = =material_print_temperature - 16 material_print_temperature = =default_material_print_temperature - 2 -material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature + 4 material_standby_temperature = 100 multiple_mesh_overlap = 0.2 prime_tower_enable = True prime_tower_flow = 100 -prime_tower_min_volume = 10 retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg index fca907e8fd..ff723c4ed4 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg @@ -24,17 +24,15 @@ jerk_support = =math.ceil(jerk_print * 25 / 25) jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) machine_nozzle_cool_down_speed = 0.5 machine_nozzle_heat_up_speed = 2.5 -material_bed_temperature_layer_0 = 0 material_final_print_temperature = =material_print_temperature - 21 material_flow = 105 material_initial_print_temperature = =material_print_temperature - 16 material_print_temperature = =default_material_print_temperature + 2 -material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 multiple_mesh_overlap = 0.2 prime_tower_enable = True prime_tower_flow = 100 -prime_tower_min_volume = 20 retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg index 673d64d432..7e36e9d354 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg @@ -24,16 +24,14 @@ jerk_support = =math.ceil(jerk_print * 25 / 25) jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) machine_nozzle_cool_down_speed = 0.5 machine_nozzle_heat_up_speed = 2.5 -material_bed_temperature_layer_0 = 0 material_final_print_temperature = =material_print_temperature - 21 material_flow = 105 material_initial_print_temperature = =material_print_temperature - 16 -material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =material_print_temperature + 2 material_standby_temperature = 100 multiple_mesh_overlap = 0.2 prime_tower_enable = True prime_tower_flow = 100 -prime_tower_min_volume = 15 retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg new file mode 100644 index 0000000000..37dceff349 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg @@ -0,0 +1,28 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_abs +variant = AA 0.8 +buildplate = Aluminum + +[values] +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature + 20 +material_standby_temperature = 100 +speed_print = 50 +speed_topbottom = =math.ceil(speed_print * 30 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) +retract_at_layer_change = False + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg new file mode 100644 index 0000000000..eac339baa8 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg @@ -0,0 +1,28 @@ +[general] +version = 4 +name = Sprint +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = superdraft +weight = -4 +material = generic_abs +variant = AA 0.8 +buildplate = Aluminum + +[values] +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature + 25 +material_standby_temperature = 100 +speed_print = 50 +speed_topbottom = =math.ceil(speed_print * 30 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) +retract_at_layer_change = False + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg new file mode 100644 index 0000000000..590496df0f --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg @@ -0,0 +1,28 @@ +[general] +version = 4 +name = Extra Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +material = generic_abs +variant = AA 0.8 +buildplate = Aluminum + +[values] +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature + 22 +material_standby_temperature = 100 +speed_print = 50 +speed_topbottom = =math.ceil(speed_print * 30 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) +retract_at_layer_change = False + +material_bed_temperature_layer_0 = 100 +default_material_bed_temperature = 90 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg new file mode 100644 index 0000000000..3e74390840 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg @@ -0,0 +1,44 @@ +[general] +version = 4 +name = Fast - Experimental +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_cpe_plus +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 14 +cool_fan_full_at_height = =layer_height_0 + 14 * layer_height +infill_before_walls = True +line_width = =machine_nozzle_size * 0.9375 +machine_nozzle_cool_down_speed = 0.9 +machine_nozzle_heat_up_speed = 1.4 +material_print_temperature = =default_material_print_temperature - 10 +material_print_temperature_layer_0 = =material_print_temperature +material_standby_temperature = 100 +prime_tower_enable = True +retraction_combing = off +retraction_hop = 0.1 +retraction_hop_enabled = False +skin_overlap = 0 +speed_layer_0 = 15 +speed_print = 50 +speed_slowdown_layers = 15 +speed_topbottom = =math.ceil(speed_print * 35 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 35 / 40) +support_bottom_distance = =support_z_distance +support_line_width = =round(line_width * 0.6 / 0.7, 2) +support_z_distance = =layer_height +top_bottom_thickness = 1.2 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg new file mode 100644 index 0000000000..4c1b807430 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg @@ -0,0 +1,44 @@ +[general] +version = 4 +name = Sprint +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = superdraft +weight = -4 +material = generic_cpe_plus +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 14 +cool_fan_full_at_height = =layer_height_0 + 7 * layer_height +infill_before_walls = True +line_width = =machine_nozzle_size * 0.9375 +machine_nozzle_cool_down_speed = 0.9 +machine_nozzle_heat_up_speed = 1.4 +material_print_temperature = =default_material_print_temperature - 5 +material_print_temperature_layer_0 = =material_print_temperature +material_standby_temperature = 100 +prime_tower_enable = True +retraction_combing = off +retraction_hop = 0.1 +retraction_hop_enabled = False +skin_overlap = 0 +speed_layer_0 = 15 +speed_print = 50 +speed_slowdown_layers = 8 +speed_topbottom = =math.ceil(speed_print * 35 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 35 / 40) +support_bottom_distance = =support_z_distance +support_line_width = =round(line_width * 0.6 / 0.7, 2) +support_z_distance = =layer_height +top_bottom_thickness = 1.2 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg new file mode 100644 index 0000000000..11aefc90cd --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg @@ -0,0 +1,44 @@ +[general] +version = 4 +name = Extra Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +material = generic_cpe_plus +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 14 +cool_fan_full_at_height = =layer_height_0 + 9 * layer_height +infill_before_walls = True +line_width = =machine_nozzle_size * 0.9375 +machine_nozzle_cool_down_speed = 0.9 +machine_nozzle_heat_up_speed = 1.4 +material_print_temperature = =default_material_print_temperature - 7 +material_print_temperature_layer_0 = =material_print_temperature +material_standby_temperature = 100 +prime_tower_enable = True +retraction_combing = off +retraction_hop = 0.1 +retraction_hop_enabled = False +skin_overlap = 0 +speed_layer_0 = 15 +speed_print = 50 +speed_slowdown_layers = 10 +speed_topbottom = =math.ceil(speed_print * 35 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 35 / 40) +support_bottom_distance = =support_z_distance +support_line_width = =round(line_width * 0.6 / 0.7, 2) +support_z_distance = =layer_height +top_bottom_thickness = 1.2 + +material_bed_temperature_layer_0 = 115 +default_material_bed_temperature = 105 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg new file mode 100644 index 0000000000..80c0585061 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg @@ -0,0 +1,31 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_cpe +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 15 +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature + 15 +material_standby_temperature = 100 +prime_tower_enable = True +speed_print = 40 +speed_topbottom = =math.ceil(speed_print * 25 / 40) +speed_wall = =math.ceil(speed_print * 30 / 40) + +jerk_travel = 50 +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg new file mode 100644 index 0000000000..5dcc454173 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg @@ -0,0 +1,32 @@ +[general] +version = 4 +name = Sprint +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = superdraft +weight = -4 +material = generic_cpe +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 15 +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature + 20 +material_standby_temperature = 100 +prime_tower_enable = True +speed_print = 45 +speed_topbottom = =math.ceil(speed_print * 30 / 45) +speed_wall = =math.ceil(speed_print * 40 / 45) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) + +jerk_travel = 50 +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg new file mode 100644 index 0000000000..8423e109e8 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg @@ -0,0 +1,31 @@ +[general] +version = 4 +name = Extra Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +material = generic_cpe +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 15 +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature + 17 +material_standby_temperature = 100 +prime_tower_enable = True +speed_print = 40 +speed_topbottom = =math.ceil(speed_print * 25 / 40) +speed_wall = =math.ceil(speed_print * 30 / 40) + +jerk_travel = 50 +prime_tower_purge_volume = 1 + +material_bed_temperature_layer_0 = 90 +default_material_bed_temperature = 80 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg new file mode 100644 index 0000000000..747e2fe8a5 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg @@ -0,0 +1,37 @@ +[general] +version = 4 +name = Fast - Experimental +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = 0 +material = generic_pc +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 10 +cool_fan_full_at_height = =layer_height_0 + 14 * layer_height +infill_before_walls = True +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature - 5 +material_print_temperature_layer_0 = =material_print_temperature +material_standby_temperature = 100 +raft_airgap = 0.5 +raft_margin = 15 +skin_overlap = 0 +speed_layer_0 = 15 +speed_print = 50 +speed_slowdown_layers = 15 +speed_topbottom = =math.ceil(speed_print * 25 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) +support_line_width = =round(line_width * 0.6 / 0.7, 2) + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg new file mode 100644 index 0000000000..689652dc06 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg @@ -0,0 +1,36 @@ +[general] +version = 4 +name = Sprint +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = superdraft +weight = -2 +material = generic_pc +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 10 +cool_fan_full_at_height = =layer_height_0 + 7 * layer_height +infill_before_walls = True +line_width = =machine_nozzle_size * 0.875 +material_print_temperature_layer_0 = =material_print_temperature +material_standby_temperature = 100 +raft_airgap = 0.5 +raft_margin = 15 +skin_overlap = 0 +speed_layer_0 = 15 +speed_print = 50 +speed_slowdown_layers = 8 +speed_topbottom = =math.ceil(speed_print * 25 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) +support_line_width = =round(line_width * 0.6 / 0.7, 2) + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg new file mode 100644 index 0000000000..0480ee5620 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg @@ -0,0 +1,38 @@ +[general] +version = 4 +name = Extra Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -1 +material = generic_pc +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 10 +cool_fan_full_at_height = =layer_height_0 + 9 * layer_height +infill_before_walls = True +line_width = =machine_nozzle_size * 0.875 +material_print_temperature = =default_material_print_temperature - 2 +material_print_temperature_layer_0 = =material_print_temperature +material_standby_temperature = 100 +raft_airgap = 0.5 +raft_margin = 15 +skin_overlap = 0 +speed_layer_0 = 15 +speed_print = 50 +speed_slowdown_layers = 10 +speed_topbottom = =math.ceil(speed_print * 25 / 50) +speed_wall = =math.ceil(speed_print * 40 / 50) +speed_wall_0 = =math.ceil(speed_wall * 30 / 40) +support_line_width = =round(line_width * 0.6 / 0.7, 2) + +material_bed_temperature_layer_0 = 125 +default_material_bed_temperature = 115 +prime_blob_enable = False +layer_height_0 = 0.3 + diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg new file mode 100644 index 0000000000..b80af1b75f --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg @@ -0,0 +1,55 @@ +[general] +version = 4 +name = Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = draft +weight = -2 +material = generic_pp +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 25 +cool_min_layer_time_fan_speed_max = 6 +cool_min_speed = 17 +top_skin_expand_distance = =line_width * 2 +infill_before_walls = True +infill_line_width = =round(line_width * 0.7 / 0.8, 2) +infill_pattern = tetrahedral +jerk_prime_tower = =math.ceil(jerk_print * 25 / 25) +jerk_support = =math.ceil(jerk_print * 25 / 25) +jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) +material_bed_temperature_layer_0 = =material_bed_temperature +material_print_temperature = =default_material_print_temperature - 2 +material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_standby_temperature = 100 +multiple_mesh_overlap = 0.2 +prime_tower_enable = True +prime_tower_flow = 100 +prime_tower_wall_thickness = =prime_tower_line_width * 2 +retract_at_layer_change = False +retraction_count_max = 12 +retraction_extra_prime_amount = 0.5 +retraction_hop = 0.5 +retraction_min_travel = 1.5 +retraction_prime_speed = 15 +skin_line_width = =round(line_width * 0.78 / 0.8, 2) + +speed_wall_x = =math.ceil(speed_wall * 30 / 30) +support_bottom_distance = =support_z_distance +support_line_width = =round(line_width * 0.7 / 0.8, 2) +support_offset = =line_width +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 45 +top_bottom_thickness = 1.6 +travel_compensate_overlapping_walls_0_enabled = False +wall_0_wipe_dist = =line_width * 2 +wall_line_width_x = =round(line_width * 0.8 / 0.8, 2) +wall_thickness = 1.6 + +default_material_bed_temperature = 95 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg new file mode 100644 index 0000000000..970e0971a9 --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg @@ -0,0 +1,56 @@ +[general] +version = 4 +name = Sprint +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = superdraft +weight = -4 +material = generic_pp +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 25 +cool_min_layer_time_fan_speed_max = 6 +cool_min_speed = 17 +top_skin_expand_distance = =line_width * 2 +infill_before_walls = True +infill_line_width = =round(line_width * 0.7 / 0.8, 2) +infill_pattern = tetrahedral +jerk_prime_tower = =math.ceil(jerk_print * 25 / 25) +jerk_support = =math.ceil(jerk_print * 25 / 25) +jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) +material_bed_temperature_layer_0 = =material_bed_temperature +material_print_temperature = =default_material_print_temperature + 2 +material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_standby_temperature = 100 +multiple_mesh_overlap = 0.2 +prime_tower_enable = True +prime_tower_flow = 100 +prime_tower_wall_thickness = =prime_tower_line_width * 2 +retract_at_layer_change = False +retraction_count_max = 12 +retraction_extra_prime_amount = 0.5 +retraction_hop = 0.5 +retraction_min_travel = 1.5 +retraction_prime_speed = 15 +skin_line_width = =round(line_width * 0.78 / 0.8, 2) + +speed_wall_x = =math.ceil(speed_wall * 30 / 30) +support_bottom_distance = =support_z_distance +support_line_width = =round(line_width * 0.7 / 0.8, 2) +support_offset = =line_width +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 45 +top_bottom_thickness = 1.6 +travel_compensate_overlapping_walls_0_enabled = False +wall_0_wipe_dist = =line_width * 2 +wall_line_width_x = =round(line_width * 0.8 / 0.8, 2) +wall_thickness = 1.6 + +default_material_bed_temperature = 95 + diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg new file mode 100644 index 0000000000..e51ba3207b --- /dev/null +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg @@ -0,0 +1,54 @@ +[general] +version = 4 +name = Extra Fast +definition = ultimaker_s5 + +[metadata] +setting_version = 5 +type = quality +quality_type = verydraft +weight = -3 +material = generic_pp +variant = AA 0.8 +buildplate = Aluminum + +[values] +brim_width = 25 +cool_min_layer_time_fan_speed_max = 6 +cool_min_speed = 17 +top_skin_expand_distance = =line_width * 2 +infill_before_walls = True +infill_line_width = =round(line_width * 0.7 / 0.8, 2) +infill_pattern = tetrahedral +jerk_prime_tower = =math.ceil(jerk_print * 25 / 25) +jerk_support = =math.ceil(jerk_print * 25 / 25) +jerk_wall_0 = =math.ceil(jerk_wall * 15 / 25) +material_bed_temperature_layer_0 = =material_bed_temperature +material_print_temperature_layer_0 = =default_material_print_temperature + 2 +material_standby_temperature = 100 +multiple_mesh_overlap = 0.2 +prime_tower_enable = True +prime_tower_flow = 100 +prime_tower_wall_thickness = =prime_tower_line_width * 2 +retract_at_layer_change = False +retraction_count_max = 12 +retraction_extra_prime_amount = 0.5 +retraction_hop = 0.5 +retraction_min_travel = 1.5 +retraction_prime_speed = 15 +skin_line_width = =round(line_width * 0.78 / 0.8, 2) + +speed_wall_x = =math.ceil(speed_wall * 30 / 30) +support_bottom_distance = =support_z_distance +support_line_width = =round(line_width * 0.7 / 0.8, 2) +support_offset = =line_width +switch_extruder_prime_speed = 15 +switch_extruder_retraction_amount = 20 +switch_extruder_retraction_speeds = 45 +top_bottom_thickness = 1.6 +travel_compensate_overlapping_walls_0_enabled = False +wall_0_wipe_dist = =line_width * 2 +wall_line_width_x = =round(line_width * 0.8 / 0.8, 2) +wall_thickness = 1.6 + +default_material_bed_temperature = 95 diff --git a/resources/setting_visibility/advanced.cfg b/resources/setting_visibility/advanced.cfg index 43edb13495..9cee353f0c 100644 --- a/resources/setting_visibility/advanced.cfg +++ b/resources/setting_visibility/advanced.cfg @@ -37,6 +37,7 @@ infill_extruder_nr infill_sparse_density infill_line_distance infill_pattern +infill_multiplier infill_overlap infill_sparse_thickness gradual_infill_steps diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index 0f15247eb7..0ca2cbab70 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -37,6 +37,7 @@ bottom_thickness bottom_layers top_bottom_pattern top_bottom_pattern_0 +connect_skin_polygons skin_angles wall_0_inset optimize_wall_printing_order @@ -73,6 +74,8 @@ infill_sparse_density infill_line_distance infill_pattern zig_zaggify_infill +connect_infill_polygons +infill_multiplier infill_angles infill_offset_x infill_offset_y diff --git a/resources/themes/cura-light/icons/favorites_star_empty.svg b/resources/themes/cura-light/icons/favorites_star_empty.svg new file mode 100644 index 0000000000..bb1205e7a7 --- /dev/null +++ b/resources/themes/cura-light/icons/favorites_star_empty.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/resources/themes/cura-light/icons/favorites_star_full.svg b/resources/themes/cura-light/icons/favorites_star_full.svg new file mode 100644 index 0000000000..aad45c5d02 --- /dev/null +++ b/resources/themes/cura-light/icons/favorites_star_full.svg @@ -0,0 +1,6 @@ + + + + + diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 7bcdafce98..c408146669 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -315,7 +315,13 @@ "tab_status_disconnected": [200, 200, 200, 255], "printer_config_matched": [12, 169, 227, 255], - "printer_config_mismatch": [127, 127, 127, 255] + "printer_config_mismatch": [127, 127, 127, 255], + + "favorites_header_bar": [245, 245, 245, 255], + "favorites_header_hover": [245, 245, 245, 255], + "favorites_header_text": [31, 36, 39, 255], + "favorites_header_text_hover": [31, 36, 39, 255], + "favorites_row_selected": [196, 239, 255, 255] }, "sizes": { @@ -372,6 +378,10 @@ "small_button": [2, 2], "small_button_icon": [1.5, 1.5], + "favorites_row": [2, 2], + "favorites_button": [2, 2], + "favorites_button_icon": [1.2, 1.2], + "printer_status_icon": [1.8, 1.8], "printer_sync_icon": [1.2, 1.2], diff --git a/resources/variants/ultimaker3_bb0.8.inst.cfg b/resources/variants/ultimaker3_bb0.8.inst.cfg index 9ad4284b40..ace0bf3a94 100644 --- a/resources/variants/ultimaker3_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_bb0.8.inst.cfg @@ -40,7 +40,6 @@ material_print_temperature = =default_material_print_temperature + 10 material_standby_temperature = 100 multiple_mesh_overlap = 0 prime_tower_enable = False -prime_tower_min_volume = 20 prime_tower_wipe_enabled = True raft_acceleration = =acceleration_layer_0 raft_airgap = 0 diff --git a/resources/variants/ultimaker3_bb04.inst.cfg b/resources/variants/ultimaker3_bb04.inst.cfg index f07a4a55f9..d571cabc9b 100644 --- a/resources/variants/ultimaker3_bb04.inst.cfg +++ b/resources/variants/ultimaker3_bb04.inst.cfg @@ -22,7 +22,6 @@ jerk_support_bottom = =math.ceil(jerk_support_interface * 1 / 10) machine_nozzle_heat_up_speed = 1.5 machine_nozzle_id = BB 0.4 machine_nozzle_tip_outer_diameter = 1.0 -prime_tower_min_volume = 15 raft_base_speed = 20 raft_interface_speed = 20 raft_speed = 25 diff --git a/resources/variants/ultimaker3_extended_aa0.25.inst.cfg b/resources/variants/ultimaker3_extended_aa0.25.inst.cfg index b2f81e101c..714b017653 100644 --- a/resources/variants/ultimaker3_extended_aa0.25.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.25.inst.cfg @@ -11,7 +11,6 @@ hardware_type = nozzle [values] brim_width = 7 infill_line_width = 0.23 -infill_overlap = 0 layer_height_0 = 0.17 line_width = 0.23 machine_nozzle_cool_down_speed = 0.85 @@ -21,10 +20,18 @@ machine_nozzle_size = 0.25 machine_nozzle_tip_outer_diameter = 0.65 material_final_print_temperature = =material_print_temperature - 10 material_initial_print_temperature = =material_print_temperature - 5 +raft_airgap = 0.3 +raft_base_thickness = =resolveOrValue('layer_height_0') * 1.2 +raft_interface_line_spacing = =raft_interface_line_width + 0.2 +raft_interface_line_width = =line_width * 2 raft_interface_thickness = =layer_height * 1.5 +raft_jerk = =jerk_print +raft_margin = 15 +raft_surface_layers = 2 retraction_count_max = 25 retraction_extrusion_window = 1 retraction_min_travel = 0.7 +retraction_prime_speed = =retraction_speed skin_overlap = 15 speed_layer_0 = 20 speed_print = 55 @@ -32,8 +39,12 @@ speed_topbottom = 20 speed_wall = =math.ceil(speed_print * 30 / 55) support_angle = 60 support_bottom_distance = =support_z_distance / 2 +support_pattern = zigzag support_top_distance = =support_z_distance +support_use_towers = True support_z_distance = =layer_height * 2 +switch_extruder_prime_speed = =switch_extruder_retraction_speeds +switch_extruder_retraction_amount = =machine_heat_zone_length top_bottom_thickness = 1.2 wall_line_width_x = 0.23 wall_thickness = 1.3 diff --git a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg index d7a76d538a..fe760c93b8 100644 --- a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg @@ -40,7 +40,6 @@ material_print_temperature = =default_material_print_temperature + 10 material_standby_temperature = 100 multiple_mesh_overlap = 0 prime_tower_enable = False -prime_tower_min_volume = 20 prime_tower_wipe_enabled = True raft_acceleration = =acceleration_layer_0 raft_airgap = 0 diff --git a/resources/variants/ultimaker3_extended_bb04.inst.cfg b/resources/variants/ultimaker3_extended_bb04.inst.cfg index 6e882cfa04..742dc9896e 100644 --- a/resources/variants/ultimaker3_extended_bb04.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb04.inst.cfg @@ -22,7 +22,6 @@ jerk_support_bottom = =math.ceil(jerk_support_interface * 1 / 10) machine_nozzle_heat_up_speed = 1.5 machine_nozzle_id = BB 0.4 machine_nozzle_tip_outer_diameter = 1.0 -prime_tower_min_volume = 15 raft_base_speed = 20 raft_interface_speed = 20 raft_speed = 25 diff --git a/resources/variants/ultimaker_s5_bb0.8.inst.cfg b/resources/variants/ultimaker_s5_bb0.8.inst.cfg index 6b954041ab..c1c5c1a10b 100644 --- a/resources/variants/ultimaker_s5_bb0.8.inst.cfg +++ b/resources/variants/ultimaker_s5_bb0.8.inst.cfg @@ -40,7 +40,6 @@ material_print_temperature = =default_material_print_temperature + 10 material_standby_temperature = 100 multiple_mesh_overlap = 0 prime_tower_enable = False -prime_tower_min_volume = 20 prime_tower_wipe_enabled = True raft_acceleration = =acceleration_layer_0 raft_airgap = 0 diff --git a/resources/variants/ultimaker_s5_bb04.inst.cfg b/resources/variants/ultimaker_s5_bb04.inst.cfg index 634920ca65..b5ff8d51f6 100644 --- a/resources/variants/ultimaker_s5_bb04.inst.cfg +++ b/resources/variants/ultimaker_s5_bb04.inst.cfg @@ -22,7 +22,6 @@ jerk_support_bottom = =math.ceil(jerk_support_interface * 1 / 10) machine_nozzle_heat_up_speed = 1.5 machine_nozzle_id = BB 0.4 machine_nozzle_tip_outer_diameter = 1.0 -prime_tower_min_volume = 20 raft_base_speed = 20 raft_interface_speed = 20 raft_speed = 25 diff --git a/tests/Settings/TestCuraContainerRegistry.py b/tests/Settings/TestCuraContainerRegistry.py index 38b2e0f6ea..af478c3b2b 100644 --- a/tests/Settings/TestCuraContainerRegistry.py +++ b/tests/Settings/TestCuraContainerRegistry.py @@ -1,61 +1,15 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import os #To find the directory with test files and find the test files. -import pytest #This module contains unit tests. -import shutil #To copy files to make a temporary file. import unittest.mock #To mock and monkeypatch stuff. -import urllib.parse -import copy -import cura.CuraApplication -from cura.Settings.CuraContainerRegistry import CuraContainerRegistry #The class we're testing. +from UM.Settings.DefinitionContainer import DefinitionContainer from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks. from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks. -from UM.Resources import Resources #Mocking some functions of this. import UM.Settings.InstanceContainer #Creating instance containers to register. import UM.Settings.ContainerRegistry #Making empty container stacks. import UM.Settings.ContainerStack #Setting the container registry here properly. -from UM.Settings.DefinitionContainer import DefinitionContainer -from UM.Settings.ContainerRegistry import ContainerRegistry - -def creteEmptyContainers(): - empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() - empty_variant_container = copy.deepcopy(empty_container) - empty_variant_container.setMetaDataEntry("id", "empty_variant") - empty_variant_container.setMetaDataEntry("type", "variant") - ContainerRegistry.getInstance().addContainer(empty_variant_container) - - empty_material_container = copy.deepcopy(empty_container) - empty_material_container.setMetaDataEntry("id", "empty_material") - empty_material_container.setMetaDataEntry("type", "material") - ContainerRegistry.getInstance().addContainer(empty_material_container) - - empty_quality_container = copy.deepcopy(empty_container) - empty_quality_container.setMetaDataEntry("id", "empty_quality") - empty_quality_container.setName("Not Supported") - empty_quality_container.setMetaDataEntry("quality_type", "not_supported") - empty_quality_container.setMetaDataEntry("type", "quality") - empty_quality_container.setMetaDataEntry("supported", False) - ContainerRegistry.getInstance().addContainer(empty_quality_container) - - empty_quality_changes_container = copy.deepcopy(empty_container) - empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes") - empty_quality_changes_container.setMetaDataEntry("type", "quality_changes") - ContainerRegistry.getInstance().addContainer(empty_quality_changes_container) - -## Gives a fresh CuraContainerRegistry instance. -@pytest.fixture() -def container_registry(): - registry = CuraContainerRegistry() - UM.Settings.InstanceContainer.setContainerRegistry(registry) - UM.Settings.ContainerStack.setContainerRegistry(registry) - return registry - -## Gives an arbitrary definition container. -@pytest.fixture() -def definition_container(): - return DefinitionContainer(container_id = "Test Definition") def teardown(): #If the temporary file for the legacy file rename test still exists, remove it. @@ -64,44 +18,47 @@ def teardown(): os.remove(temporary_file) ## Tests whether addContainer properly converts to ExtruderStack. -def test_addContainerExtruderStack(container_registry, definition_container): - creteEmptyContainers() +def test_addContainerExtruderStack(container_registry, definition_container, definition_changes_container): container_registry.addContainer(definition_container) + container_registry.addContainer(definition_changes_container) - container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Container Stack") #A container we're going to convert. + container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Extruder Stack") #A container we're going to convert. container_stack.setMetaDataEntry("type", "extruder_train") #This is now an extruder train. container_stack.insertContainer(0, definition_container) #Add a definition to it so it doesn't complain. + container_stack.insertContainer(1, definition_changes_container) mock_super_add_container = unittest.mock.MagicMock() #Takes the role of the Uranium-ContainerRegistry where the resulting containers get registered. with unittest.mock.patch("UM.Settings.ContainerRegistry.ContainerRegistry.addContainer", mock_super_add_container): container_registry.addContainer(container_stack) - assert len(mock_super_add_container.call_args_list) == 2 #Called only once. - assert len(mock_super_add_container.call_args_list[1][0]) == 1 #Called with one parameter. - assert type(mock_super_add_container.call_args_list[1][0][0]) == ExtruderStack + assert len(mock_super_add_container.call_args_list) == 1 #Called only once. + assert len(mock_super_add_container.call_args_list[0][0]) == 1 #Called with one parameter. + assert type(mock_super_add_container.call_args_list[0][0][0]) == ExtruderStack ## Tests whether addContainer properly converts to GlobalStack. -def test_addContainerGlobalStack(container_registry, definition_container): +def test_addContainerGlobalStack(container_registry, definition_container, definition_changes_container): container_registry.addContainer(definition_container) + container_registry.addContainer(definition_changes_container) - container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Container Stack") #A container we're going to convert. + container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Global Stack") #A container we're going to convert. container_stack.setMetaDataEntry("type", "machine") #This is now a global stack. container_stack.insertContainer(0, definition_container) #Must have a definition. + container_stack.insertContainer(1, definition_changes_container) #Must have a definition changes. mock_super_add_container = unittest.mock.MagicMock() #Takes the role of the Uranium-ContainerRegistry where the resulting containers get registered. with unittest.mock.patch("UM.Settings.ContainerRegistry.ContainerRegistry.addContainer", mock_super_add_container): container_registry.addContainer(container_stack) - assert len(mock_super_add_container.call_args_list) == 2 #Called only once. - assert len(mock_super_add_container.call_args_list[1][0]) == 1 #Called with one parameter. - assert type(mock_super_add_container.call_args_list[1][0][0]) == GlobalStack + assert len(mock_super_add_container.call_args_list) == 1 #Called only once. + assert len(mock_super_add_container.call_args_list[0][0]) == 1 #Called with one parameter. + assert type(mock_super_add_container.call_args_list[0][0][0]) == GlobalStack def test_addContainerGoodSettingVersion(container_registry, definition_container): from cura.CuraApplication import CuraApplication definition_container.getMetaData()["setting_version"] = CuraApplication.SettingVersion container_registry.addContainer(definition_container) - instance = UM.Settings.InstanceContainer.InstanceContainer(container_id = "Test Instance") + instance = UM.Settings.InstanceContainer.InstanceContainer(container_id = "Test Instance Right Version") instance.setMetaDataEntry("setting_version", CuraApplication.SettingVersion) instance.setDefinition(definition_container.getId()) @@ -116,7 +73,7 @@ def test_addContainerNoSettingVersion(container_registry, definition_container): definition_container.getMetaData()["setting_version"] = CuraApplication.SettingVersion container_registry.addContainer(definition_container) - instance = UM.Settings.InstanceContainer.InstanceContainer(container_id = "Test Instance") + instance = UM.Settings.InstanceContainer.InstanceContainer(container_id = "Test Instance No Version") #Don't add setting_version metadata. instance.setDefinition(definition_container.getId()) @@ -131,7 +88,7 @@ def test_addContainerBadSettingVersion(container_registry, definition_container) definition_container.getMetaData()["setting_version"] = CuraApplication.SettingVersion container_registry.addContainer(definition_container) - instance = UM.Settings.InstanceContainer.InstanceContainer(container_id = "Test Instance") + instance = UM.Settings.InstanceContainer.InstanceContainer(container_id = "Test Instance Wrong Version") instance.setMetaDataEntry("setting_version", 9001) #Wrong version! instance.setDefinition(definition_container.getId()) @@ -140,38 +97,3 @@ def test_addContainerBadSettingVersion(container_registry, definition_container) container_registry.addContainer(instance) mock_super_add_container.assert_not_called() #Should not get passed on to UM.Settings.ContainerRegistry.addContainer, because the setting_version doesn't match its definition! - -## Tests whether loading gives objects of the correct type. -# @pytest.mark.parametrize("filename, output_class", [ -# ("ExtruderLegacy.stack.cfg", ExtruderStack), -# ("MachineLegacy.stack.cfg", GlobalStack), -# ("Left.extruder.cfg", ExtruderStack), -# ("Global.global.cfg", GlobalStack), -# ("Global.stack.cfg", GlobalStack) -# ]) -# def test_loadTypes(filename, output_class, container_registry): -# #Mock some dependencies. -# Resources.getAllResourcesOfType = unittest.mock.MagicMock(return_value = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)]) #Return just this tested file. -# -# def findContainers(container_type = 0, id = None): -# if id == "some_instance": -# return [UM.Settings.ContainerRegistry._EmptyInstanceContainer(id)] -# elif id == "some_definition": -# return [DefinitionContainer(container_id = id)] -# else: -# return [] -# -# container_registry.findContainers = findContainers -# -# with unittest.mock.patch("cura.Settings.GlobalStack.GlobalStack.findContainer"): -# with unittest.mock.patch("os.remove"): -# container_registry.load() -# -# #Check whether the resulting type was correct. -# stack_id = filename.split(".")[0] -# for container_id, container in container_registry._containers.items(): #Stupid ContainerRegistry class doesn't expose any way of getting at this except by prodding the privates. -# if container_id == stack_id: #This is the one we're testing. -# assert type(container) == output_class -# break -# else: -# assert False #Container stack with specified ID was not loaded. \ No newline at end of file diff --git a/tests/Settings/TestExtruderStack.py b/tests/Settings/TestExtruderStack.py index 7c463fb9be..df2e1075d1 100644 --- a/tests/Settings/TestExtruderStack.py +++ b/tests/Settings/TestExtruderStack.py @@ -1,43 +1,17 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import pytest #This module contains automated tests. import unittest.mock #For the mocking and monkeypatching functionality. -import copy -import cura.CuraApplication +import cura.Settings.CuraContainerStack #To get the list of container types. import UM.Settings.ContainerRegistry #To create empty instance containers. import UM.Settings.ContainerStack #To set the container registry the container stacks use. from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer. from UM.Settings.InstanceContainer import InstanceContainer #To check against the class of InstanceContainer. -import cura.Settings.ExtruderStack #The module we're testing. from cura.Settings.Exceptions import InvalidContainerError, InvalidOperationError #To check whether the correct exceptions are raised. - from cura.Settings.ExtruderManager import ExtruderManager -from UM.Settings.ContainerRegistry import ContainerRegistry -from cura.Settings.GlobalStack import GlobalStack - -## Fake container registry that always provides all containers you ask of. -@pytest.yield_fixture() -def container_registry(): - registry = unittest.mock.MagicMock() - registry.return_value = unittest.mock.NonCallableMagicMock() - registry.findInstanceContainers = lambda *args, registry = registry, **kwargs: [registry.return_value] - registry.findDefinitionContainers = lambda *args, registry = registry, **kwargs: [registry.return_value] - - UM.Settings.ContainerRegistry.ContainerRegistry._ContainerRegistry__instance = registry - UM.Settings.ContainerStack._containerRegistry = registry - - yield registry - - UM.Settings.ContainerRegistry.ContainerRegistry._ContainerRegistry__instance = None - UM.Settings.ContainerStack._containerRegistry = None - -## An empty extruder stack to test with. -@pytest.fixture() -def extruder_stack() -> cura.Settings.ExtruderStack.ExtruderStack: - creteEmptyContainers() - return cura.Settings.ExtruderStack.ExtruderStack("TestStack") +from cura.Settings.cura_empty_instance_containers import empty_container ## Gets an instance container with a specified container type. # @@ -48,31 +22,6 @@ def getInstanceContainer(container_type) -> InstanceContainer: container.setMetaDataEntry("type", container_type) return container -def creteEmptyContainers(): - empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() - empty_variant_container = copy.deepcopy(empty_container) - empty_variant_container.setMetaDataEntry("id", "empty_variant") - empty_variant_container.setMetaDataEntry("type", "variant") - ContainerRegistry.getInstance().addContainer(empty_variant_container) - - empty_material_container = copy.deepcopy(empty_container) - empty_material_container.setMetaDataEntry("id", "empty_material") - empty_material_container.setMetaDataEntry("type", "material") - ContainerRegistry.getInstance().addContainer(empty_material_container) - - empty_quality_container = copy.deepcopy(empty_container) - empty_quality_container.setMetaDataEntry("id", "empty_quality") - empty_quality_container.setName("Not Supported") - empty_quality_container.setMetaDataEntry("quality_type", "not_supported") - empty_quality_container.setMetaDataEntry("type", "quality") - empty_quality_container.setMetaDataEntry("supported", False) - ContainerRegistry.getInstance().addContainer(empty_quality_container) - - empty_quality_changes_container = copy.deepcopy(empty_container) - empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes") - empty_quality_changes_container.setMetaDataEntry("type", "quality_changes") - ContainerRegistry.getInstance().addContainer(empty_quality_changes_container) - class DefinitionContainerSubClass(DefinitionContainer): def __init__(self): super().__init__(container_id = "SubDefinitionContainer") @@ -179,12 +128,30 @@ def test_constrainVariantInvalid(container, extruder_stack): def test_constrainVariantValid(container, extruder_stack): extruder_stack.variant = container #Should not give an error. +#Tests setting definition changes profiles to invalid containers. +@pytest.mark.parametrize("container", [ + getInstanceContainer(container_type = "wrong container type"), + getInstanceContainer(container_type = "material"), #Existing, but still wrong type. + DefinitionContainer(container_id = "wrong class") +]) +def test_constrainDefinitionChangesInvalid(container, global_stack): + with pytest.raises(InvalidContainerError): #Invalid container, should raise an error. + global_stack.definitionChanges = container + +#Test setting definition changes profiles. +@pytest.mark.parametrize("container", [ + getInstanceContainer(container_type = "definition_changes"), + InstanceContainerSubClass(container_type = "definition_changes") +]) +def test_constrainDefinitionChangesValid(container, global_stack): + global_stack.definitionChanges = container #Should not give an error. + #Tests setting definitions to invalid containers. @pytest.mark.parametrize("container", [ getInstanceContainer(container_type = "wrong class"), getInstanceContainer(container_type = "material"), #Existing, but still wrong class. ]) -def test_constrainVariantInvalid(container, extruder_stack): +def test_constrainDefinitionInvalid(container, extruder_stack): with pytest.raises(InvalidContainerError): #Invalid container, should raise an error. extruder_stack.definition = container @@ -196,23 +163,22 @@ def test_constrainVariantInvalid(container, extruder_stack): def test_constrainDefinitionValid(container, extruder_stack): extruder_stack.definition = container #Should not give an error. -## Tests whether deserialising completes the missing containers with empty -# ones. -@pytest.mark.skip #The test currently fails because the definition container doesn't have a category, which is wrong but we don't have time to refactor that right now. -def test_deserializeCompletesEmptyContainers(extruder_stack: cura.Settings.ExtruderStack): - extruder_stack._containers = [DefinitionContainer(container_id = "definition")] #Set the internal state of this stack manually. +## Tests whether deserialising completes the missing containers with empty ones. +def test_deserializeCompletesEmptyContainers(extruder_stack): + extruder_stack._containers = [DefinitionContainer(container_id = "definition"), extruder_stack.definitionChanges] #Set the internal state of this stack manually. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize. extruder_stack.deserialize("") assert len(extruder_stack.getContainers()) == len(cura.Settings.CuraContainerStack._ContainerIndexes.IndexTypeMap) #Needs a slot for every type. for container_type_index in cura.Settings.CuraContainerStack._ContainerIndexes.IndexTypeMap: - if container_type_index == cura.Settings.CuraContainerStack._ContainerIndexes.Definition: #We're not checking the definition. + if container_type_index in \ + (cura.Settings.CuraContainerStack._ContainerIndexes.Definition, + cura.Settings.CuraContainerStack._ContainerIndexes.DefinitionChanges): # We're not checking the definition or definition_changes continue - assert extruder_stack.getContainer(container_type_index).getId() == "empty" #All others need to be empty. + assert extruder_stack.getContainer(container_type_index) == empty_container #All others need to be empty. -## Tests whether an instance container with the wrong type gets removed when -# deserialising. +## Tests whether an instance container with the wrong type gets removed when deserialising. def test_deserializeRemovesWrongInstanceContainer(extruder_stack): extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = getInstanceContainer(container_type = "wrong type") extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition") @@ -222,8 +188,7 @@ def test_deserializeRemovesWrongInstanceContainer(extruder_stack): assert extruder_stack.quality == extruder_stack._empty_instance_container #Replaced with empty. -## Tests whether a container with the wrong class gets removed when -# deserialising. +## Tests whether a container with the wrong class gets removed when deserialising. def test_deserializeRemovesWrongContainerClass(extruder_stack): extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = DefinitionContainer(container_id = "wrong class") extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition") @@ -233,8 +198,7 @@ def test_deserializeRemovesWrongContainerClass(extruder_stack): assert extruder_stack.quality == extruder_stack._empty_instance_container #Replaced with empty. -## Tests whether an instance container in the definition spot results in an -# error. +## Tests whether an instance container in the definition spot results in an error. def test_deserializeWrongDefinitionClass(extruder_stack): extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = getInstanceContainer(container_type = "definition") #Correct type but wrong class. @@ -242,8 +206,7 @@ def test_deserializeWrongDefinitionClass(extruder_stack): with pytest.raises(UM.Settings.ContainerStack.InvalidContainerStackError): #Must raise an error that there is no definition container. extruder_stack.deserialize("") -## Tests whether an instance container with the wrong type is moved into the -# correct slot by deserialising. +## Tests whether an instance container with the wrong type is moved into the correct slot by deserialising. def test_deserializeMoveInstanceContainer(extruder_stack): extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = getInstanceContainer(container_type = "material") #Not in the correct spot. extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition") @@ -251,26 +214,21 @@ def test_deserializeMoveInstanceContainer(extruder_stack): with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize. extruder_stack.deserialize("") - assert extruder_stack.quality.getId() == "empty" - assert extruder_stack.material.getId() != "empty" -from UM.Settings.Validator import Validator -## Tests whether a definition container in the wrong spot is moved into the -# correct spot by deserialising. -@pytest.mark.skip #The test currently fails because the definition container doesn't have a category, which is wrong but we don't have time to refactor that right now. + assert extruder_stack.quality == empty_container + assert extruder_stack.material != empty_container + +## Tests whether a definition container in the wrong spot is moved into the correct spot by deserialising. def test_deserializeMoveDefinitionContainer(extruder_stack): extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Material] = DefinitionContainer(container_id = "some definition") #Not in the correct spot. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize. extruder_stack.deserialize("") - assert extruder_stack.material.getId() == "empty" - assert extruder_stack.definition.getId() != "empty" + assert extruder_stack.material == empty_container + assert extruder_stack.definition != empty_container - UM.Settings.ContainerStack._containerRegistry = None - -## Tests whether getProperty properly applies the stack-like behaviour on its -# containers. -def test_getPropertyFallThrough(extruder_stack): +## Tests whether getProperty properly applies the stack-like behaviour on its containers. +def test_getPropertyFallThrough(global_stack, extruder_stack): # ExtruderStack.setNextStack calls registerExtruder for backward compatibility, but we do not need a complete extruder manager ExtruderManager._ExtruderManager__instance = unittest.mock.MagicMock() @@ -300,8 +258,7 @@ def test_getPropertyFallThrough(extruder_stack): with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking. extruder_stack.definition = mock_layer_heights[container_indices.Definition] #There's a layer height in here! - stack = GlobalStack("PyTest GlobalStack") - extruder_stack.setNextStack(stack) + extruder_stack.setNextStack(global_stack) assert extruder_stack.getProperty("layer_height", "value") == container_indices.Definition extruder_stack.variant = mock_layer_heights[container_indices.Variant] @@ -340,4 +297,4 @@ def test_setPropertyUser(key, property, value, extruder_stack): extruder_stack.setProperty(key, property, value) #The actual test. - extruder_stack.userChanges.setProperty.assert_called_once_with(key, property, value) #Make sure that the user container gets a setProperty call. \ No newline at end of file + extruder_stack.userChanges.setProperty.assert_called_once_with(key, property, value, None, False) #Make sure that the user container gets a setProperty call. \ No newline at end of file diff --git a/tests/Settings/TestGlobalStack.py b/tests/Settings/TestGlobalStack.py index 3e74e3e575..f8052aa4bb 100755 --- a/tests/Settings/TestGlobalStack.py +++ b/tests/Settings/TestGlobalStack.py @@ -1,43 +1,19 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import pytest #This module contains unit tests. import unittest.mock #To monkeypatch some mocks in place of dependencies. -import copy -import cura.CuraApplication -import cura.Settings.GlobalStack #The module we're testing. import cura.Settings.CuraContainerStack #To get the list of container types. -from cura.Settings.Exceptions import TooManyExtrudersError, InvalidContainerError, InvalidOperationError #To test raising these errors. +from cura.Settings.Exceptions import InvalidContainerError, InvalidOperationError #To test raising these errors. from UM.Settings.DefinitionContainer import DefinitionContainer #To test against the class DefinitionContainer. from UM.Settings.InstanceContainer import InstanceContainer #To test against the class InstanceContainer. from UM.Settings.SettingInstance import InstanceState import UM.Settings.ContainerRegistry import UM.Settings.ContainerStack import UM.Settings.SettingDefinition #To add settings to the definition. -from UM.Settings.ContainerRegistry import ContainerRegistry -## Fake container registry that always provides all containers you ask of. -@pytest.yield_fixture() -def container_registry(): - registry = unittest.mock.MagicMock() - registry.return_value = unittest.mock.NonCallableMagicMock() - registry.findInstanceContainers = lambda *args, registry = registry, **kwargs: [registry.return_value] - registry.findDefinitionContainers = lambda *args, registry = registry, **kwargs: [registry.return_value] - - UM.Settings.ContainerRegistry.ContainerRegistry._ContainerRegistry__instance = registry - UM.Settings.ContainerStack._containerRegistry = registry - - yield registry - - UM.Settings.ContainerRegistry.ContainerRegistry._ContainerRegistry__instance = None - UM.Settings.ContainerStack._containerRegistry = None - -#An empty global stack to test with. -@pytest.fixture() -def global_stack() -> cura.Settings.GlobalStack.GlobalStack: - creteEmptyContainers() - return cura.Settings.GlobalStack.GlobalStack("TestStack") +from cura.Settings.cura_empty_instance_containers import empty_container ## Gets an instance container with a specified container type. # @@ -48,31 +24,6 @@ def getInstanceContainer(container_type) -> InstanceContainer: container.setMetaDataEntry("type", container_type) return container -def creteEmptyContainers(): - empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() - empty_variant_container = copy.deepcopy(empty_container) - empty_variant_container.setMetaDataEntry("id", "empty_variant") - empty_variant_container.setMetaDataEntry("type", "variant") - ContainerRegistry.getInstance().addContainer(empty_variant_container) - - empty_material_container = copy.deepcopy(empty_container) - empty_material_container.setMetaDataEntry("id", "empty_material") - empty_material_container.setMetaDataEntry("type", "material") - ContainerRegistry.getInstance().addContainer(empty_material_container) - - empty_quality_container = copy.deepcopy(empty_container) - empty_quality_container.setMetaDataEntry("id", "empty_quality") - empty_quality_container.setName("Not Supported") - empty_quality_container.setMetaDataEntry("quality_type", "not_supported") - empty_quality_container.setMetaDataEntry("type", "quality") - empty_quality_container.setMetaDataEntry("supported", False) - ContainerRegistry.getInstance().addContainer(empty_quality_container) - - empty_quality_changes_container = copy.deepcopy(empty_container) - empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes") - empty_quality_changes_container.setMetaDataEntry("type", "quality_changes") - ContainerRegistry.getInstance().addContainer(empty_quality_changes_container) - class DefinitionContainerSubClass(DefinitionContainer): def __init__(self): super().__init__(container_id = "SubDefinitionContainer") @@ -229,7 +180,7 @@ def test_constrainDefinitionChangesValid(container, global_stack): getInstanceContainer(container_type = "wrong class"), getInstanceContainer(container_type = "material"), #Existing, but still wrong class. ]) -def test_constrainVariantInvalid(container, global_stack): +def test_constrainDefinitionInvalid(container, global_stack): with pytest.raises(InvalidContainerError): #Invalid container, should raise an error. global_stack.definition = container @@ -241,23 +192,22 @@ def test_constrainVariantInvalid(container, global_stack): def test_constrainDefinitionValid(container, global_stack): global_stack.definition = container #Should not give an error. -## Tests whether deserialising completes the missing containers with empty -# ones. -@pytest.mark.skip #The test currently fails because the definition container doesn't have a category, which is wrong but we don't have time to refactor that right now. -def test_deserializeCompletesEmptyContainers(global_stack: cura.Settings.GlobalStack): - global_stack._containers = [DefinitionContainer(container_id = "definition")] #Set the internal state of this stack manually. +## Tests whether deserialising completes the missing containers with empty ones. The initial containers are just the +# definition and the definition_changes (that cannot be empty after CURA-5281) +def test_deserializeCompletesEmptyContainers(global_stack): + global_stack._containers = [DefinitionContainer(container_id = "definition"), global_stack.definitionChanges] #Set the internal state of this stack manually. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize. global_stack.deserialize("") assert len(global_stack.getContainers()) == len(cura.Settings.CuraContainerStack._ContainerIndexes.IndexTypeMap) #Needs a slot for every type. for container_type_index in cura.Settings.CuraContainerStack._ContainerIndexes.IndexTypeMap: - if container_type_index == cura.Settings.CuraContainerStack._ContainerIndexes.Definition: #We're not checking the definition. + if container_type_index in \ + (cura.Settings.CuraContainerStack._ContainerIndexes.Definition, cura.Settings.CuraContainerStack._ContainerIndexes.DefinitionChanges): #We're not checking the definition or definition_changes continue - assert global_stack.getContainer(container_type_index).getId() == "empty" #All others need to be empty. + assert global_stack.getContainer(container_type_index) == empty_container #All others need to be empty. -## Tests whether an instance container with the wrong type gets removed when -# deserialising. +## Tests whether an instance container with the wrong type gets removed when deserialising. def test_deserializeRemovesWrongInstanceContainer(global_stack): global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = getInstanceContainer(container_type = "wrong type") global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition") @@ -267,8 +217,7 @@ def test_deserializeRemovesWrongInstanceContainer(global_stack): assert global_stack.quality == global_stack._empty_instance_container #Replaced with empty. -## Tests whether a container with the wrong class gets removed when -# deserialising. +## Tests whether a container with the wrong class gets removed when deserialising. def test_deserializeRemovesWrongContainerClass(global_stack): global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = DefinitionContainer(container_id = "wrong class") global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition") @@ -278,8 +227,7 @@ def test_deserializeRemovesWrongContainerClass(global_stack): assert global_stack.quality == global_stack._empty_instance_container #Replaced with empty. -## Tests whether an instance container in the definition spot results in an -# error. +## Tests whether an instance container in the definition spot results in an error. def test_deserializeWrongDefinitionClass(global_stack): global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = getInstanceContainer(container_type = "definition") #Correct type but wrong class. @@ -287,8 +235,7 @@ def test_deserializeWrongDefinitionClass(global_stack): with pytest.raises(UM.Settings.ContainerStack.InvalidContainerStackError): #Must raise an error that there is no definition container. global_stack.deserialize("") -## Tests whether an instance container with the wrong type is moved into the -# correct slot by deserialising. +## Tests whether an instance container with the wrong type is moved into the correct slot by deserialising. def test_deserializeMoveInstanceContainer(global_stack): global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = getInstanceContainer(container_type = "material") #Not in the correct spot. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition") @@ -296,25 +243,20 @@ def test_deserializeMoveInstanceContainer(global_stack): with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize. global_stack.deserialize("") - assert global_stack.quality.getId() == "empty" - assert global_stack.material.getId() != "empty" + assert global_stack.quality == empty_container + assert global_stack.material != empty_container -## Tests whether a definition container in the wrong spot is moved into the -# correct spot by deserialising. -@pytest.mark.skip #The test currently fails because the definition container doesn't have a category, which is wrong but we don't have time to refactor that right now. +## Tests whether a definition container in the wrong spot is moved into the correct spot by deserialising. def test_deserializeMoveDefinitionContainer(global_stack): global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Material] = DefinitionContainer(container_id = "some definition") #Not in the correct spot. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize. global_stack.deserialize("") - assert global_stack.material.getId() == "empty" - assert global_stack.definition.getId() != "empty" + assert global_stack.material == empty_container + assert global_stack.definition != empty_container - UM.Settings.ContainerStack._containerRegistry = None - -## Tests whether getProperty properly applies the stack-like behaviour on its -# containers. +## Tests whether getProperty properly applies the stack-like behaviour on its containers. def test_getPropertyFallThrough(global_stack): #A few instance container mocks to put in the stack. mock_layer_heights = {} #For each container type, a mock container that defines layer height to something unique. @@ -365,8 +307,7 @@ def test_getPropertyNoResolveInDefinition(global_stack): global_stack.definition = value assert global_stack.getProperty("material_bed_temperature", "value") == 10 #No resolve, so fall through to value. -## In definitions, when the value is asked and there is a resolve function, it -# must get the resolve first. +## In definitions, when the value is asked and there is a resolve function, it must get the resolve first. def test_getPropertyResolveInDefinition(global_stack): resolve_and_value = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature. resolve_and_value.getProperty = lambda key, property, context = None: (7.5 if property == "resolve" else 5) if (key == "material_bed_temperature" and property in ("resolve", "value")) else None #7.5 resolve, 5 value. @@ -375,8 +316,7 @@ def test_getPropertyResolveInDefinition(global_stack): global_stack.definition = resolve_and_value assert global_stack.getProperty("material_bed_temperature", "value") == 7.5 #Resolve wins in the definition. -## In instance containers, when the value is asked and there is a resolve -# function, it must get the value first. +## In instance containers, when the value is asked and there is a resolve function, it must get the value first. def test_getPropertyResolveInInstance(global_stack): container_indices = cura.Settings.CuraContainerStack._ContainerIndexes instance_containers = {} @@ -402,8 +342,7 @@ def test_getPropertyResolveInInstance(global_stack): global_stack.userChanges = instance_containers[container_indices.UserChanges] assert global_stack.getProperty("material_bed_temperature", "value") == 5 -## Tests whether the value in instances gets evaluated before the resolve in -# definitions. +## Tests whether the value in instances gets evaluated before the resolve in definitions. def test_getPropertyInstancesBeforeResolve(global_stack): value = unittest.mock.MagicMock() #Sets just the value. value.getProperty = lambda key, property, context = None: (10 if property == "value" else (InstanceState.User if property != "limit_to_extruder" else "-1")) if key == "material_bed_temperature" else None @@ -417,8 +356,7 @@ def test_getPropertyInstancesBeforeResolve(global_stack): assert global_stack.getProperty("material_bed_temperature", "value") == 10 -## Tests whether the hasUserValue returns true for settings that are changed in -# the user-changes container. +## Tests whether the hasUserValue returns true for settings that are changed in the user-changes container. def test_hasUserValueUserChanges(global_stack): container = unittest.mock.MagicMock() container.getMetaDataEntry = unittest.mock.MagicMock(return_value = "user") @@ -429,8 +367,7 @@ def test_hasUserValueUserChanges(global_stack): assert not global_stack.hasUserValue("infill_sparse_density") assert not global_stack.hasUserValue("") -## Tests whether the hasUserValue returns true for settings that are changed in -# the quality-changes container. +## Tests whether the hasUserValue returns true for settings that are changed in the quality-changes container. def test_hasUserValueQualityChanges(global_stack): container = unittest.mock.MagicMock() container.getMetaDataEntry = unittest.mock.MagicMock(return_value = "quality_changes") @@ -441,8 +378,7 @@ def test_hasUserValueQualityChanges(global_stack): assert not global_stack.hasUserValue("infill_sparse_density") assert not global_stack.hasUserValue("") -## Tests whether a container in some other place on the stack is correctly not -# recognised as user value. +## Tests whether a container in some other place on the stack is correctly not recognised as user value. def test_hasNoUserValue(global_stack): container = unittest.mock.MagicMock() container.getMetaDataEntry = unittest.mock.MagicMock(return_value = "quality") @@ -481,4 +417,4 @@ def test_setPropertyUser(key, property, value, global_stack): global_stack.setProperty(key, property, value) #The actual test. - global_stack.userChanges.setProperty.assert_called_once_with(key, property, value) #Make sure that the user container gets a setProperty call. \ No newline at end of file + global_stack.userChanges.setProperty.assert_called_once_with(key, property, value, None, False) #Make sure that the user container gets a setProperty call. \ No newline at end of file diff --git a/tests/Settings/conftest.py b/tests/Settings/conftest.py new file mode 100644 index 0000000000..c2d8854f05 --- /dev/null +++ b/tests/Settings/conftest.py @@ -0,0 +1,54 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Uranium is released under the terms of the LGPLv3 or higher. + +# The purpose of this class is to create fixtures or methods that can be shared among all settings tests. + +import pytest + +from UM.Settings.ContainerRegistry import ContainerRegistry +from UM.Settings.ContainerStack import setContainerRegistry +from UM.Settings.DefinitionContainer import DefinitionContainer #To provide definition containers in the registry fixtures. +from UM.Settings.InstanceContainer import InstanceContainer +from cura.Settings.CuraContainerRegistry import CuraContainerRegistry +from cura.Settings.ExtruderStack import ExtruderStack +from cura.Settings.GlobalStack import GlobalStack +import cura.Settings.CuraContainerStack + +# Returns the CuraContainerRegistry instance with some empty containers. +@pytest.fixture() +def container_registry(application) -> CuraContainerRegistry: + ContainerRegistry._ContainerRegistry__instance= None # Need to reset since we only allow one instance + registry = CuraContainerRegistry(application) + setContainerRegistry(registry) + return registry + +# Gives an arbitrary definition container. +@pytest.fixture() +def definition_container() -> DefinitionContainer: + return DefinitionContainer(container_id = "Test Definition") + +# Gives an arbitrary definition changes container. +@pytest.fixture() +def definition_changes_container() -> InstanceContainer: + definition_changes_container = InstanceContainer(container_id = "Test Definition Changes") + definition_changes_container.setMetaDataEntry("type", "definition_changes") + # Add current setting version to the instance container + from cura.CuraApplication import CuraApplication + definition_changes_container.getMetaData()["setting_version"] = CuraApplication.SettingVersion + return definition_changes_container + +# An empty global stack to test with. +# There is a restriction here that the definition changes cannot be an empty container. Added in CURA-5281 +@pytest.fixture() +def global_stack(definition_changes_container) -> GlobalStack: + global_stack = GlobalStack("TestGlobalStack") + global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.DefinitionChanges] = definition_changes_container + return global_stack + +# An empty extruder stack to test with. +# There is a restriction here that the definition changes cannot be an empty container. Added in CURA-5281 +@pytest.fixture() +def extruder_stack(definition_changes_container) -> ExtruderStack: + extruder_stack= ExtruderStack("TestExtruderStack") + extruder_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.DefinitionChanges] = definition_changes_container + return extruder_stack \ No newline at end of file diff --git a/tests/Settings/stacks/Complete.extruder.cfg b/tests/Settings/stacks/Complete.extruder.cfg deleted file mode 100644 index 789c0978f3..0000000000 --- a/tests/Settings/stacks/Complete.extruder.cfg +++ /dev/null @@ -1,12 +0,0 @@ -[general] -version = 3 -name = Complete -id = Complete - -[containers] -0 = some_user_changes -1 = some_quality_changes -2 = some_quality -3 = some_material -4 = some_variant -5 = some_definition diff --git a/tests/Settings/stacks/Complete.global.cfg b/tests/Settings/stacks/Complete.global.cfg deleted file mode 100644 index f7f613991a..0000000000 --- a/tests/Settings/stacks/Complete.global.cfg +++ /dev/null @@ -1,13 +0,0 @@ -[general] -version = 3 -name = Complete -id = Complete - -[containers] -0 = some_user_changes -1 = some_quality_changes -2 = some_quality -3 = some_material -4 = some_variant -5 = some_definition_changes -6 = some_definition diff --git a/tests/Settings/stacks/ExtruderLegacy.stack.cfg b/tests/Settings/stacks/ExtruderLegacy.stack.cfg deleted file mode 100644 index 4a6c419e40..0000000000 --- a/tests/Settings/stacks/ExtruderLegacy.stack.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[general] -version = 3 -name = Legacy Extruder Stack -id = ExtruderLegacy - -[metadata] -type = extruder_train - -[containers] -3 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/Global.global.cfg b/tests/Settings/stacks/Global.global.cfg deleted file mode 100644 index 9034c1d0d0..0000000000 --- a/tests/Settings/stacks/Global.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Global -id = Global - -[containers] -3 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/Global.stack.cfg b/tests/Settings/stacks/Global.stack.cfg deleted file mode 100644 index aa1693d878..0000000000 --- a/tests/Settings/stacks/Global.stack.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[general] -version = 3 -name = Global -id = Global - -[metadata] -type = machine - -[containers] -3 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/Left.extruder.cfg b/tests/Settings/stacks/Left.extruder.cfg deleted file mode 100644 index 8ba45d6754..0000000000 --- a/tests/Settings/stacks/Left.extruder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Left -id = Left - -[containers] -3 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/MachineLegacy.stack.cfg b/tests/Settings/stacks/MachineLegacy.stack.cfg deleted file mode 100644 index 147d63c596..0000000000 --- a/tests/Settings/stacks/MachineLegacy.stack.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[general] -version = 3 -name = Legacy Global Stack -id = MachineLegacy - -[metadata] -type = machine - -[containers] -3 = some_instance -6 = some_definition \ No newline at end of file diff --git a/tests/Settings/stacks/OnlyDefinition.extruder.cfg b/tests/Settings/stacks/OnlyDefinition.extruder.cfg deleted file mode 100644 index e58512b27f..0000000000 --- a/tests/Settings/stacks/OnlyDefinition.extruder.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[general] -version = 3 -name = Only Definition -id = OnlyDefinition - -[containers] -5 = some_definition diff --git a/tests/Settings/stacks/OnlyDefinition.global.cfg b/tests/Settings/stacks/OnlyDefinition.global.cfg deleted file mode 100644 index 9534353ed5..0000000000 --- a/tests/Settings/stacks/OnlyDefinition.global.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[general] -version = 3 -name = Only Definition -id = OnlyDefinition - -[containers] -6 = some_definition diff --git a/tests/Settings/stacks/OnlyDefinitionChanges.global.cfg b/tests/Settings/stacks/OnlyDefinitionChanges.global.cfg deleted file mode 100644 index 39e2105b7d..0000000000 --- a/tests/Settings/stacks/OnlyDefinitionChanges.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Definition Changes -id = OnlyDefinitionChanges - -[containers] -5 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/OnlyMaterial.extruder.cfg b/tests/Settings/stacks/OnlyMaterial.extruder.cfg deleted file mode 100644 index 49a9d12389..0000000000 --- a/tests/Settings/stacks/OnlyMaterial.extruder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Material -id = OnlyMaterial - -[containers] -3 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/OnlyMaterial.global.cfg b/tests/Settings/stacks/OnlyMaterial.global.cfg deleted file mode 100644 index 715651a9b9..0000000000 --- a/tests/Settings/stacks/OnlyMaterial.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Material -id = OnlyMaterial - -[containers] -3 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/OnlyQuality.extruder.cfg b/tests/Settings/stacks/OnlyQuality.extruder.cfg deleted file mode 100644 index aaf7fb30c5..0000000000 --- a/tests/Settings/stacks/OnlyQuality.extruder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Quality -id = OnlyQuality - -[containers] -2 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/OnlyQuality.global.cfg b/tests/Settings/stacks/OnlyQuality.global.cfg deleted file mode 100644 index f07a35666e..0000000000 --- a/tests/Settings/stacks/OnlyQuality.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Quality -id = OnlyQuality - -[containers] -2 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/OnlyQualityChanges.extruder.cfg b/tests/Settings/stacks/OnlyQualityChanges.extruder.cfg deleted file mode 100644 index 653bad840c..0000000000 --- a/tests/Settings/stacks/OnlyQualityChanges.extruder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Quality Changes -id = OnlyQualityChanges - -[containers] -1 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/OnlyQualityChanges.global.cfg b/tests/Settings/stacks/OnlyQualityChanges.global.cfg deleted file mode 100644 index 17d279377a..0000000000 --- a/tests/Settings/stacks/OnlyQualityChanges.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Quality Changes -id = OnlyQualityChanges - -[containers] -1 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/OnlyUser.extruder.cfg b/tests/Settings/stacks/OnlyUser.extruder.cfg deleted file mode 100644 index abf812a859..0000000000 --- a/tests/Settings/stacks/OnlyUser.extruder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only User -id = OnlyUser - -[containers] -0 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/OnlyUser.global.cfg b/tests/Settings/stacks/OnlyUser.global.cfg deleted file mode 100644 index 31371d2c51..0000000000 --- a/tests/Settings/stacks/OnlyUser.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only User -id = OnlyUser - -[containers] -0 = some_instance -6 = some_definition diff --git a/tests/Settings/stacks/OnlyVariant.extruder.cfg b/tests/Settings/stacks/OnlyVariant.extruder.cfg deleted file mode 100644 index a31997a6fd..0000000000 --- a/tests/Settings/stacks/OnlyVariant.extruder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Variant -id = OnlyVariant - -[containers] -4 = some_instance -5 = some_definition diff --git a/tests/Settings/stacks/OnlyVariant.global.cfg b/tests/Settings/stacks/OnlyVariant.global.cfg deleted file mode 100644 index 158d533ac8..0000000000 --- a/tests/Settings/stacks/OnlyVariant.global.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 3 -name = Only Variant -id = OnlyVariant - -[containers] -4 = some_instance -6 = some_definition diff --git a/tests/TestArrange.py b/tests/TestArrange.py index f383fc0cf3..7de3ec1d8d 100755 --- a/tests/TestArrange.py +++ b/tests/TestArrange.py @@ -1,9 +1,11 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + import numpy from cura.Arranging.Arrange import Arrange from cura.Arranging.ShapeArray import ShapeArray - ## Triangle of area 12 def gimmeTriangle(): return numpy.array([[-3, 1], [3, 1], [0, -3]], dtype=numpy.int32) @@ -102,7 +104,7 @@ def test_centerFirst_rectangular(): ## Test centerFirst -def test_centerFirst_rectangular(): +def test_centerFirst_rectangular2(): ar = Arrange(10, 20, 5, 10, scale = 1) ar.centerFirst() print(ar._priority) diff --git a/tests/TestMachineAction.py b/tests/TestMachineAction.py index 0118874a0b..7121fcc218 100755 --- a/tests/TestMachineAction.py +++ b/tests/TestMachineAction.py @@ -1,11 +1,10 @@ -#Todo: Write tests +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. import pytest -# QtApplication needs to be imported first to prevent import errors. -from UM.Qt.QtApplication import QtApplication from cura.MachineAction import MachineAction -from cura.MachineActionManager import MachineActionManager, NotUniqueMachineActionError, UnknownMachineActionError +from cura.MachineActionManager import NotUniqueMachineActionError, UnknownMachineActionError class Machine: def __init__(self, key = ""): @@ -14,66 +13,64 @@ class Machine: def getKey(self): return self._key -def test_addMachineAction(): - - machine_manager = MachineActionManager() +def test_addMachineAction(machine_action_manager): test_action = MachineAction(key = "test_action") test_action_2 = MachineAction(key = "test_action_2") test_machine = Machine("test_machine") - machine_manager.addMachineAction(test_action) - machine_manager.addMachineAction(test_action_2) + machine_action_manager.addMachineAction(test_action) + machine_action_manager.addMachineAction(test_action_2) - assert machine_manager.getMachineAction("test_action") == test_action - assert machine_manager.getMachineAction("key_that_doesnt_exist") is None + assert machine_action_manager.getMachineAction("test_action") == test_action + assert machine_action_manager.getMachineAction("key_that_doesnt_exist") is None # Adding the same machine action is not allowed. with pytest.raises(NotUniqueMachineActionError): - machine_manager.addMachineAction(test_action) + machine_action_manager.addMachineAction(test_action) # Check that the machine has no supported actions yet. - assert machine_manager.getSupportedActions(test_machine) == list() + assert machine_action_manager.getSupportedActions(test_machine) == list() # Check if adding a supported action works. - machine_manager.addSupportedAction(test_machine, "test_action") - assert machine_manager.getSupportedActions(test_machine) == [test_action, ] + machine_action_manager.addSupportedAction(test_machine, "test_action") + assert machine_action_manager.getSupportedActions(test_machine) == [test_action, ] # Check that adding a unknown action doesn't change anything. - machine_manager.addSupportedAction(test_machine, "key_that_doesnt_exist") - assert machine_manager.getSupportedActions(test_machine) == [test_action, ] + machine_action_manager.addSupportedAction(test_machine, "key_that_doesnt_exist") + assert machine_action_manager.getSupportedActions(test_machine) == [test_action, ] # Check if adding multiple supported actions works. - machine_manager.addSupportedAction(test_machine, "test_action_2") - assert machine_manager.getSupportedActions(test_machine) == [test_action, test_action_2] + machine_action_manager.addSupportedAction(test_machine, "test_action_2") + assert machine_action_manager.getSupportedActions(test_machine) == [test_action, test_action_2] # Check that the machine has no required actions yet. - assert machine_manager.getRequiredActions(test_machine) == set() + assert machine_action_manager.getRequiredActions(test_machine) == set() ## Ensure that only known actions can be added. with pytest.raises(UnknownMachineActionError): - machine_manager.addRequiredAction(test_machine, "key_that_doesnt_exist") + machine_action_manager.addRequiredAction(test_machine, "key_that_doesnt_exist") ## Check if adding single required action works - machine_manager.addRequiredAction(test_machine, "test_action") - assert machine_manager.getRequiredActions(test_machine) == [test_action, ] + machine_action_manager.addRequiredAction(test_machine, "test_action") + assert machine_action_manager.getRequiredActions(test_machine) == [test_action, ] # Check if adding multiple required actions works. - machine_manager.addRequiredAction(test_machine, "test_action_2") - assert machine_manager.getRequiredActions(test_machine) == [test_action, test_action_2] + machine_action_manager.addRequiredAction(test_machine, "test_action_2") + assert machine_action_manager.getRequiredActions(test_machine) == [test_action, test_action_2] # Ensure that firstStart actions are empty by default. - assert machine_manager.getFirstStartActions(test_machine) == [] + assert machine_action_manager.getFirstStartActions(test_machine) == [] # Check if adding multiple (the same) actions to first start actions work. - machine_manager.addFirstStartAction(test_machine, "test_action") - machine_manager.addFirstStartAction(test_machine, "test_action") - assert machine_manager.getFirstStartActions(test_machine) == [test_action, test_action] + machine_action_manager.addFirstStartAction(test_machine, "test_action") + machine_action_manager.addFirstStartAction(test_machine, "test_action") + assert machine_action_manager.getFirstStartActions(test_machine) == [test_action, test_action] # Check if inserting an action works - machine_manager.addFirstStartAction(test_machine, "test_action_2", index = 1) - assert machine_manager.getFirstStartActions(test_machine) == [test_action, test_action_2, test_action] + machine_action_manager.addFirstStartAction(test_machine, "test_action_2", index = 1) + assert machine_action_manager.getFirstStartActions(test_machine) == [test_action, test_action_2, test_action] # Check that adding a unknown action doesn't change anything. - machine_manager.addFirstStartAction(test_machine, "key_that_doesnt_exist", index = 1) - assert machine_manager.getFirstStartActions(test_machine) == [test_action, test_action_2, test_action] + machine_action_manager.addFirstStartAction(test_machine, "key_that_doesnt_exist", index = 1) + assert machine_action_manager.getFirstStartActions(test_machine) == [test_action, test_action_2, test_action] diff --git a/tests/TestProfileRequirements.py b/tests/TestProfileRequirements.py index f75ca9da8d..97641fe753 100644 --- a/tests/TestProfileRequirements.py +++ b/tests/TestProfileRequirements.py @@ -1,3 +1,6 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + import configparser #To read the profiles. import os #To join paths. import pytest @@ -11,6 +14,7 @@ import pytest # often that we updated the variants for the UM3 but forgot about the UM3E. @pytest.mark.parametrize("um3_file, um3e_file", [ #List the corresponding files below. + ("ultimaker3_aa0.25.inst.cfg", "ultimaker3_extended_aa0.25.inst.cfg"), ("ultimaker3_aa0.8.inst.cfg", "ultimaker3_extended_aa0.8.inst.cfg"), ("ultimaker3_aa04.inst.cfg", "ultimaker3_extended_aa04.inst.cfg"), ("ultimaker3_bb0.8.inst.cfg", "ultimaker3_extended_bb0.8.inst.cfg"), diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000..77d215815a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,25 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +# The purpose of this class is to create fixtures or methods that can be shared among all tests. + +import unittest.mock +import pytest + +from UM.Qt.QtApplication import QtApplication #QtApplication import is required, even though it isn't used. +from cura.CuraApplication import CuraApplication +from cura.MachineActionManager import MachineActionManager + + + +# Create a CuraApplication object that will be shared among all tests. It needs to be initialized. +# Since we need to use it more that once, we create the application the first time and use its instance afterwards. +@pytest.fixture() +def application() -> CuraApplication: + app = unittest.mock.MagicMock() + return app + +# Returns a MachineActionManager instance. +@pytest.fixture() +def machine_action_manager(application) -> MachineActionManager: + return MachineActionManager(application)