CURA-4400 fixed merge conflicts

This commit is contained in:
Jack Ha 2018-03-05 16:47:40 +01:00
commit bad637eb14
121 changed files with 1157 additions and 936 deletions

View file

@ -821,6 +821,7 @@ class BuildVolume(SceneNode):
offset_y = extruder.getProperty("machine_nozzle_offset_y", "value") offset_y = extruder.getProperty("machine_nozzle_offset_y", "value")
if offset_y is None: if offset_y is None:
offset_y = 0 offset_y = 0
offset_y = -offset_y #Y direction of g-code is the inverse of Y direction of Cura's scene space.
result[extruder_id] = [] result[extruder_id] = []
for polygon in machine_disallowed_polygons: for polygon in machine_disallowed_polygons:

View file

@ -57,10 +57,10 @@ from cura.Settings.MachineNameValidator import MachineNameValidator
from cura.Machines.Models.BuildPlateModel import BuildPlateModel from cura.Machines.Models.BuildPlateModel import BuildPlateModel
from cura.Machines.Models.NozzleModel import NozzleModel from cura.Machines.Models.NozzleModel import NozzleModel
from cura.Machines.Models.QualityProfilesModel import QualityProfilesModel from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfilesDropDownMenuModel
from cura.Machines.Models.CustomQualityProfilesModel import CustomQualityProfilesModel from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel
from cura.Machines.Models.Other.MultiBuildPlateModel import MultiBuildPlateModel from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel
from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel
from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel
@ -399,8 +399,8 @@ class CuraApplication(QtApplication):
self.getCuraSceneController().setActiveBuildPlate(0) # Initialize self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
self._quality_profile_model = None self._quality_profile_drop_down_menu_model = None
self._custom_quality_profile_model = None self._custom_quality_profile_drop_down_menu_model = None
CuraApplication.Created = True CuraApplication.Created = True
@ -859,6 +859,7 @@ class CuraApplication(QtApplication):
def getVariantManager(self, *args): def getVariantManager(self, *args):
return self._variant_manager return self._variant_manager
@pyqtSlot(result = QObject)
def getMaterialManager(self, *args): def getMaterialManager(self, *args):
return self._material_manager return self._material_manager
@ -918,15 +919,15 @@ class CuraApplication(QtApplication):
def getPrintInformation(self): def getPrintInformation(self):
return self._print_information return self._print_information
def getQualityProfileModel(self, *args, **kwargs): def getQualityProfilesDropDownMenuModel(self, *args, **kwargs):
if self._quality_profile_model is None: if self._quality_profile_drop_down_menu_model is None:
self._quality_profile_model = QualityProfilesModel(self) self._quality_profile_drop_down_menu_model = QualityProfilesDropDownMenuModel(self)
return self._quality_profile_model return self._quality_profile_drop_down_menu_model
def getCustomQualityProfilesModel(self, *args, **kwargs): def getCustomQualityProfilesDropDownMenuModel(self, *args, **kwargs):
if self._custom_quality_profile_model is None: if self._custom_quality_profile_drop_down_menu_model is None:
self._custom_quality_profile_model = CustomQualityProfilesModel(self) self._custom_quality_profile_drop_down_menu_model = CustomQualityProfilesDropDownMenuModel(self)
return self._custom_quality_profile_model return self._custom_quality_profile_drop_down_menu_model
## Registers objects for the QML engine to use. ## Registers objects for the QML engine to use.
# #
@ -960,8 +961,10 @@ class CuraApplication(QtApplication):
qmlRegisterType(MaterialManagementModel, "Cura", 1, 0, "MaterialManagementModel") qmlRegisterType(MaterialManagementModel, "Cura", 1, 0, "MaterialManagementModel")
qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel") qmlRegisterType(QualityManagementModel, "Cura", 1, 0, "QualityManagementModel")
qmlRegisterSingletonType(QualityProfilesModel, "Cura", 1, 0, "QualityProfilesModel", self.getQualityProfileModel) qmlRegisterSingletonType(QualityProfilesDropDownMenuModel, "Cura", 1, 0,
qmlRegisterSingletonType(CustomQualityProfilesModel, "Cura", 1, 0, "CustomQualityProfilesModel", self.getCustomQualityProfilesModel) "QualityProfilesDropDownMenuModel", self.getQualityProfilesDropDownMenuModel)
qmlRegisterSingletonType(CustomQualityProfilesDropDownMenuModel, "Cura", 1, 0,
"CustomQualityProfilesDropDownMenuModel", self.getCustomQualityProfilesDropDownMenuModel)
qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel") qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel")
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler") qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")

View file

@ -1,6 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
# #
# A MaterialGroup represents a group of material InstanceContainers that are derived from a single material profile. # A MaterialGroup represents a group of material InstanceContainers that are derived from a single material profile.
# The main InstanceContainer which has the ID of the material profile file name is called the "root_material". For # The main InstanceContainer which has the ID of the material profile file name is called the "root_material". For

View file

@ -2,16 +2,24 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from collections import defaultdict, OrderedDict from collections import defaultdict, OrderedDict
from typing import Optional import copy
import uuid
from typing import Optional, TYPE_CHECKING
from PyQt5.Qt import QTimer, QObject, pyqtSignal from PyQt5.Qt import QTimer, QObject, pyqtSignal, pyqtSlot
from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.SettingFunction import SettingFunction
from UM.Util import parseBool
from .MaterialNode import MaterialNode from .MaterialNode import MaterialNode
from .MaterialGroup import MaterialGroup from .MaterialGroup import MaterialGroup
if TYPE_CHECKING:
from cura.Settings.GlobalStack import GlobalStack
# #
# MaterialManager maintains a number of maps and trees for material lookup. # MaterialManager maintains a number of maps and trees for material lookup.
@ -29,6 +37,7 @@ class MaterialManager(QObject):
def __init__(self, container_registry, parent = None): def __init__(self, container_registry, parent = None):
super().__init__(parent) super().__init__(parent)
self._application = Application.getInstance()
self._container_registry = container_registry # type: ContainerRegistry self._container_registry = container_registry # type: ContainerRegistry
self._fallback_materials_map = dict() # material_type -> generic material metadata self._fallback_materials_map = dict() # material_type -> generic material metadata
@ -260,6 +269,20 @@ class MaterialManager(QObject):
return material_id_metadata_dict return material_id_metadata_dict
#
# A convenience function to get available materials for the given machine with the extruder position.
#
def getAvailableMaterialsForMachineExtruder(self, machine: "GlobalStack",
extruder_stack: "ExtruderStack") -> Optional[dict]:
machine_definition_id = machine.definition.getId()
variant_name = None
if extruder_stack.variant.getId() != "empty_variant":
variant_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_id, variant_name, diameter)
# #
# Gets MaterialNode for the given extruder and machine with the given material name. # Gets MaterialNode for the given extruder and machine with the given material name.
# Returns None if: # Returns None if:
@ -315,7 +338,7 @@ class MaterialManager(QObject):
# This function returns the generic root material ID for the given material type, where material types are "PLA", # This function returns the generic root material ID for the given material type, where material types are "PLA",
# "ABS", etc. # "ABS", etc.
# #
def getFallbackMaterialIdByMaterialType(self, material_type: str) -> str: def getFallbackMaterialIdByMaterialType(self, material_type: str) -> Optional[str]:
# For safety # For safety
if material_type not in self._fallback_materials_map: if material_type not in self._fallback_materials_map:
Logger.log("w", "The material type [%s] does not have a fallback material" % material_type) Logger.log("w", "The material type [%s] does not have a fallback material" % material_type)
@ -325,3 +348,132 @@ class MaterialManager(QObject):
return self.getRootMaterialIDWithoutDiameter(fallback_material["id"]) return self.getRootMaterialIDWithoutDiameter(fallback_material["id"])
else: else:
return None return None
def getDefaultMaterial(self, global_stack: "GlobalStack", extruder_variant_name: str) -> Optional["MaterialNode"]:
node = None
machine_definition = global_stack.definition
if parseBool(machine_definition.getMetaDataEntry("has_materials", False)):
material_diameter = machine_definition.getProperty("material_diameter", "value")
if isinstance(material_diameter, SettingFunction):
material_diameter = material_diameter(global_stack)
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,
material_diameter, root_material_id)
return node
#
# Methods for GUI
#
#
# Sets the new name for the given material.
#
@pyqtSlot("QVariant", str)
def setMaterialName(self, material_node: "MaterialNode", name: str):
root_material_id = material_node.metadata["base_file"]
if self._container_registry.isReadOnly(root_material_id):
Logger.log("w", "Cannot set name of read-only container %s.", root_material_id)
return
material_group = self.getMaterialGroup(root_material_id)
material_group.root_material_node.getContainer().setName(name)
#
# Removes the given material.
#
@pyqtSlot("QVariant")
def removeMaterial(self, material_node: "MaterialNode"):
root_material_id = material_node.metadata["base_file"]
material_group = self.getMaterialGroup(root_material_id)
if not material_group:
Logger.log("d", "Unable to remove the material with id %s, because it doesn't exist.", root_material_id)
return
nodes_to_remove = [material_group.root_material_node] + material_group.derived_material_node_list
for node in nodes_to_remove:
self._container_registry.removeContainer(node.metadata["id"])
#
# Creates a duplicate of a material, which has the same GUID and base_file metadata.
# Returns the root material ID of the duplicated material if successful.
#
@pyqtSlot("QVariant", result = str)
def duplicateMaterial(self, material_node, new_base_id = None, new_metadata = None) -> Optional[str]:
root_material_id = material_node.metadata["base_file"]
material_group = self.getMaterialGroup(root_material_id)
if not material_group:
Logger.log("i", "Unable to duplicate the material with id %s, because it doesn't exist.", root_material_id)
return None
base_container = material_group.root_material_node.getContainer()
# Ensure all settings are saved.
self._application.saveSettings()
# Create a new ID & container to hold the data.
new_containers = []
if new_base_id is None:
new_base_id = self._container_registry.uniqueName(base_container.getId())
new_base_container = copy.deepcopy(base_container)
new_base_container.getMetaData()["id"] = new_base_id
new_base_container.getMetaData()["base_file"] = new_base_id
if new_metadata is not None:
for key, value in new_metadata.items():
new_base_container.getMetaData()[key] = value
new_containers.append(new_base_container)
# Clone all of them.
for node in material_group.derived_material_node_list:
container_to_copy = node.getContainer()
# Create unique IDs for every clone.
new_id = new_base_id
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(" ", "_")
new_container = copy.deepcopy(container_to_copy)
new_container.getMetaData()["id"] = new_id
new_container.getMetaData()["base_file"] = new_base_id
if new_metadata is not None:
for key, value in new_metadata.items():
new_container.getMetaData()[key] = value
new_containers.append(new_container)
for container_to_add in new_containers:
container_to_add.setDirty(True)
self._container_registry.addContainer(container_to_add)
return new_base_id
#
# Create a new material by cloning Generic PLA for the current material diameter and generate a new GUID.
#
@pyqtSlot(result = str)
def createMaterial(self) -> str:
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
# Ensure all settings are saved.
self._application.saveSettings()
global_stack = self._application.getGlobalContainerStack()
approximate_diameter = str(round(global_stack.getProperty("material_diameter", "value")))
root_material_id = "generic_pla"
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
material_group = self.getMaterialGroup(root_material_id)
# Create a new ID & container to hold the data.
new_id = self._container_registry.uniqueName("custom_material")
new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
"brand": catalog.i18nc("@label", "Custom"),
"GUID": str(uuid.uuid4()),
}
self.duplicateMaterial(material_group.root_material_node,
new_base_id = new_id,
new_metadata = new_metadata)
return new_id

View file

@ -1,41 +1,17 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
def getAvailableMaterials(extruder_position: Optional[int] = None): #
from cura.CuraApplication import CuraApplication # This is the base model class for GenericMaterialsModel and BrandMaterialsModel
machine_manager = CuraApplication.getInstance().getMachineManager() # Those 2 models are used by the material drop down menu to show generic materials and branded materials separately.
extruder_manager = CuraApplication.getInstance().getExtruderManager() # The extruder position defined here is being used to bound a menu to the correct extruder. This is used in the top
material_manager = CuraApplication.getInstance().getMaterialManager() # bar menu "Settings" -> "Extruder nr" -> "Material" -> this menu
#
active_global_stack = machine_manager.activeMachine
extruder_stack = extruder_manager.getActiveExtruderStack()
if extruder_position is not None:
if active_global_stack is not None:
extruder_stack = active_global_stack.extruders.get(str(extruder_position))
if active_global_stack is None or extruder_stack is None:
Logger.log("d", "Active global stack [%s] or extruder stack [%s] is None, setting material list to empty.",
active_global_stack, extruder_stack)
return
machine_definition_id = active_global_stack.definition.getId()
variant_name = None
if extruder_stack.variant.getId() != "empty_variant":
variant_name = extruder_stack.variant.getName()
diameter = extruder_stack.approximateMaterialDiameter
# Fetch the available materials (ContainerNode) for the current active machine and extruder setup.
result_dict = material_manager.getAvailableMaterials(machine_definition_id, variant_name, diameter)
return result_dict
class BaseMaterialsModel(ListModel): class BaseMaterialsModel(ListModel):
RootMaterialIdRole = Qt.UserRole + 1 RootMaterialIdRole = Qt.UserRole + 1
IdRole = Qt.UserRole + 2 IdRole = Qt.UserRole + 2

View file

@ -5,9 +5,12 @@ from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from .BaseMaterialsModel import BaseMaterialsModel, getAvailableMaterials from .BaseMaterialsModel import BaseMaterialsModel
#
# This is an intermediate model to group materials with different colours for a same brand and type.
#
class MaterialsModelGroupedByType(ListModel): class MaterialsModelGroupedByType(ListModel):
NameRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 1
ColorsRole = Qt.UserRole + 2 ColorsRole = Qt.UserRole + 2
@ -19,7 +22,18 @@ class MaterialsModelGroupedByType(ListModel):
self.addRoleName(self.ColorsRole, "colors") self.addRoleName(self.ColorsRole, "colors")
## Brand --> Material Type -> list of materials #
# 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): class BrandMaterialsModel(ListModel):
NameRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 1
MaterialsRole = Qt.UserRole + 2 MaterialsRole = Qt.UserRole + 2
@ -36,12 +50,12 @@ class BrandMaterialsModel(ListModel):
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
self._machine_manager = CuraApplication.getInstance().getMachineManager() self._machine_manager = CuraApplication.getInstance().getMachineManager()
extruder_manager = CuraApplication.getInstance().getExtruderManager() self._extruder_manager = CuraApplication.getInstance().getExtruderManager()
material_manager = CuraApplication.getInstance().getMaterialManager() self._material_manager = CuraApplication.getInstance().getMaterialManager()
self._machine_manager.globalContainerChanged.connect(self._update) self._machine_manager.globalContainerChanged.connect(self._update)
extruder_manager.activeExtruderChanged.connect(self._update) self._extruder_manager.activeExtruderChanged.connect(self._update)
material_manager.materialsUpdated.connect(self._update) self._material_manager.materialsUpdated.connect(self._update)
self._update() self._update()
@ -59,15 +73,21 @@ class BrandMaterialsModel(ListModel):
if global_stack is None: if global_stack is None:
self.setItems([]) self.setItems([])
return 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)]
result_dict = getAvailableMaterials(self._extruder_position) available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack,
if result_dict is None: extruder_stack)
if available_material_dict is None:
self.setItems([]) self.setItems([])
return return
brand_item_list = [] brand_item_list = []
brand_group_dict = {} brand_group_dict = {}
for root_material_id, container_node in result_dict.items(): for root_material_id, container_node in available_material_dict.items():
metadata = container_node.metadata metadata = container_node.metadata
brand = metadata["brand"] brand = metadata["brand"]
# Only add results for generic materials # Only add results for generic materials
@ -109,4 +129,3 @@ class BrandMaterialsModel(ListModel):
brand_item_list.append(brand_item) brand_item_list.append(brand_item)
self.setItems(brand_item_list) self.setItems(brand_item_list)

View file

@ -1,21 +1,20 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from cura.Machines.Models.QualityProfilesModel import QualityProfilesModel from cura.Machines.Models.QualityProfilesDropDownMenuModel import QualityProfilesDropDownMenuModel
# #
# This model is used for the custom profile items in the profile drop down menu. # This model is used for the custom profile items in the profile drop down menu.
# #
class CustomQualityProfilesModel(QualityProfilesModel): class CustomQualityProfilesDropDownMenuModel(QualityProfilesDropDownMenuModel):
def _update(self): def _update(self):
Logger.log("d", "Updating %s ...", self.__class__.__name__) Logger.log("d", "Updating %s ...", self.__class__.__name__)
active_global_stack = Application.getInstance().getMachineManager().activeMachine active_global_stack = self._machine_manager.activeMachine
if active_global_stack is None: if active_global_stack is None:
self.setItems([]) self.setItems([])
Logger.log("d", "No active GlobalStack, set %s as empty.", self.__class__.__name__) Logger.log("d", "No active GlobalStack, set %s as empty.", self.__class__.__name__)

View file

@ -1,7 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from .BaseMaterialsModel import BaseMaterialsModel, getAvailableMaterials from .BaseMaterialsModel import BaseMaterialsModel
class GenericMaterialsModel(BaseMaterialsModel): class GenericMaterialsModel(BaseMaterialsModel):
@ -25,14 +25,20 @@ class GenericMaterialsModel(BaseMaterialsModel):
if global_stack is None: if global_stack is None:
self.setItems([]) self.setItems([])
return 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]
result_dict = getAvailableMaterials(self._extruder_position) available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack,
if result_dict is None: extruder_stack)
if available_material_dict is None:
self.setItems([]) self.setItems([])
return return
item_list = [] item_list = []
for root_material_id, container_node in result_dict.items(): for root_material_id, container_node in available_material_dict.items():
metadata = container_node.metadata metadata = container_node.metadata
# Only add results for generic materials # Only add results for generic materials
if metadata["brand"].lower() != "generic": if metadata["brand"].lower() != "generic":

View file

@ -5,8 +5,6 @@ from PyQt5.QtCore import Qt, pyqtProperty
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from .BaseMaterialsModel import getAvailableMaterials
# #
# This model is for the Material management page. # This model is for the Material management page.
@ -52,12 +50,12 @@ class MaterialManagementModel(ListModel):
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
self._container_registry = CuraApplication.getInstance().getContainerRegistry() self._container_registry = CuraApplication.getInstance().getContainerRegistry()
self._machine_manager = CuraApplication.getInstance().getMachineManager() self._machine_manager = CuraApplication.getInstance().getMachineManager()
extruder_manager = CuraApplication.getInstance().getExtruderManager() self._extruder_manager = CuraApplication.getInstance().getExtruderManager()
material_manager = CuraApplication.getInstance().getMaterialManager() self._material_manager = CuraApplication.getInstance().getMaterialManager()
self._machine_manager.globalContainerChanged.connect(self._update) self._machine_manager.globalContainerChanged.connect(self._update)
extruder_manager.activeExtruderChanged.connect(self._update) self._extruder_manager.activeExtruderChanged.connect(self._update)
material_manager.materialsUpdated.connect(self._update) self._material_manager.materialsUpdated.connect(self._update)
self._update() self._update()
@ -66,14 +64,16 @@ class MaterialManagementModel(ListModel):
if global_stack is None: if global_stack is None:
self.setItems([]) self.setItems([])
return return
active_extruder_stack = self._machine_manager.activeStack
result_dict = getAvailableMaterials() available_material_dict = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack,
if result_dict is None: active_extruder_stack)
if available_material_dict is None:
self.setItems([]) self.setItems([])
return return
material_list = [] material_list = []
for root_material_id, container_node in result_dict.items(): for root_material_id, container_node in available_material_dict.items():
keys_to_fetch = ("name", keys_to_fetch = ("name",
"brand", "brand",
"material", "material",

View file

@ -1,3 +1,6 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtSignal, pyqtProperty from PyQt5.QtCore import pyqtSignal, pyqtProperty
from UM.Application import Application from UM.Application import Application
@ -5,6 +8,10 @@ from UM.Scene.Selection import Selection
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
#
# This is the model for multi build plate feature.
# This has nothing to do with the build plate types you can choose on the sidebar for a machine.
#
class MultiBuildPlateModel(ListModel): class MultiBuildPlateModel(ListModel):
maxBuildPlateChanged = pyqtSignal() maxBuildPlateChanged = pyqtSignal()

View file

@ -6,6 +6,9 @@ from PyQt5.QtCore import Qt, pyqtSlot
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
#
# This the QML model for the quality management page.
#
class QualityManagementModel(ListModel): class QualityManagementModel(ListModel):
NameRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 1
IsReadOnlyRole = Qt.UserRole + 2 IsReadOnlyRole = Qt.UserRole + 2
@ -24,7 +27,7 @@ class QualityManagementModel(ListModel):
self._container_registry = CuraApplication.getInstance().getContainerRegistry() self._container_registry = CuraApplication.getInstance().getContainerRegistry()
self._machine_manager = CuraApplication.getInstance().getMachineManager() self._machine_manager = CuraApplication.getInstance().getMachineManager()
self._extruder_manager = CuraApplication.getInstance().getExtruderManager() self._extruder_manager = CuraApplication.getInstance().getExtruderManager()
self._quality_manager = CuraApplication.getInstance()._quality_manager self._quality_manager = CuraApplication.getInstance().getQualityManager()
self._machine_manager.globalContainerChanged.connect(self._update) self._machine_manager.globalContainerChanged.connect(self._update)
self._quality_manager.qualitiesUpdated.connect(self._update) self._quality_manager.qualitiesUpdated.connect(self._update)
@ -32,12 +35,13 @@ class QualityManagementModel(ListModel):
self._update() self._update()
def _update(self): def _update(self):
global_stack = self._machine_manager._global_container_stack global_stack = self._machine_manager.activeMachine
quality_group_dict = self._quality_manager.getQualityGroups(global_stack) quality_group_dict = self._quality_manager.getQualityGroups(global_stack)
quality_changes_group_dict = self._quality_manager.getQualityChangesGroups(global_stack) quality_changes_group_dict = self._quality_manager.getQualityChangesGroups(global_stack)
available_quality_types = set(qt for qt, qg in quality_group_dict.items() if qg.is_available) available_quality_types = set(quality_type for quality_type, quality_group in quality_group_dict.items()
if quality_group.is_available)
if not available_quality_types and not quality_changes_group_dict: if not available_quality_types and not quality_changes_group_dict:
# Nothing to show # Nothing to show
self.setItems([]) self.setItems([])

View file

@ -6,17 +6,18 @@ from PyQt5.QtCore import Qt
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from cura.Machines.QualityManager import QualityGroup from cura.Machines.QualityManager import QualityGroup
# #
# QML Model for all built-in quality profiles. # QML Model for all built-in quality profiles. This model is used for the drop-down quality menu.
# #
class QualityProfilesModel(ListModel): class QualityProfilesDropDownMenuModel(ListModel):
NameRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 1
QualityTypeRole = Qt.UserRole + 2 QualityTypeRole = Qt.UserRole + 2
LayerHeightRole = Qt.UserRole + 3 LayerHeightRole = Qt.UserRole + 3
LayerHeightWithoutUnitRole = Qt.UserRole + 4 LayerHeightUnitRole = Qt.UserRole + 4
AvailableRole = Qt.UserRole + 5 AvailableRole = Qt.UserRole + 5
QualityGroupRole = Qt.UserRole + 6 QualityGroupRole = Qt.UserRole + 6
QualityChangesGroupRole = Qt.UserRole + 7 QualityChangesGroupRole = Qt.UserRole + 7
@ -27,17 +28,18 @@ class QualityProfilesModel(ListModel):
self.addRoleName(self.NameRole, "name") self.addRoleName(self.NameRole, "name")
self.addRoleName(self.QualityTypeRole, "quality_type") self.addRoleName(self.QualityTypeRole, "quality_type")
self.addRoleName(self.LayerHeightRole, "layer_height") self.addRoleName(self.LayerHeightRole, "layer_height")
self.addRoleName(self.LayerHeightWithoutUnitRole, "layer_height_without_unit") self.addRoleName(self.LayerHeightUnitRole, "layer_height_unit")
self.addRoleName(self.AvailableRole, "available") self.addRoleName(self.AvailableRole, "available")
self.addRoleName(self.QualityGroupRole, "quality_group") self.addRoleName(self.QualityGroupRole, "quality_group")
self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group") self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group")
# connect signals self._application = Application.getInstance()
Application.getInstance().globalContainerStackChanged.connect(self._update) self._machine_manager = self._application.getMachineManager()
Application.getInstance().getMachineManager().activeQualityGroupChanged.connect(self._update) self._quality_manager = Application.getInstance().getQualityManager()
Application.getInstance().getMachineManager().extruderChanged.connect(self._update)
self._quality_manager = Application.getInstance()._quality_manager self._application.globalContainerStackChanged.connect(self._update)
self._machine_manager.activeQualityGroupChanged.connect(self._update)
self._machine_manager.extruderChanged.connect(self._update)
self._quality_manager.qualitiesUpdated.connect(self._update) self._quality_manager.qualitiesUpdated.connect(self._update)
self._layer_height_unit = "" # This is cached self._layer_height_unit = "" # This is cached
@ -47,15 +49,15 @@ class QualityProfilesModel(ListModel):
def _update(self): def _update(self):
Logger.log("d", "Updating quality profile model ...") Logger.log("d", "Updating quality profile model ...")
machine_manager = Application.getInstance().getMachineManager() global_stack = self._machine_manager.activeMachine
global_stack = machine_manager._global_container_stack
if global_stack is None: if global_stack is None:
self.setItems([]) self.setItems([])
Logger.log("d", "No active GlobalStack, set quality profile model as empty.") Logger.log("d", "No active GlobalStack, set quality profile model as empty.")
return return
# Check for material compatibility # Check for material compatibility
if not machine_manager.activeMaterialsCompatible(): if not self._machine_manager.activeMaterialsCompatible():
Logger.log("d", "No active material compatibility, set quality profile model as empty.")
self.setItems([]) self.setItems([])
return return
@ -69,20 +71,20 @@ class QualityProfilesModel(ListModel):
item = {"name": quality_group.name, item = {"name": quality_group.name,
"quality_type": quality_group.quality_type, "quality_type": quality_group.quality_type,
"layer_height": layer_height + self._layer_height_unit, "layer_height": layer_height,
"layer_height_without_unit": layer_height, "layer_height_unit": self._layer_height_unit,
"available": quality_group.is_available, "available": quality_group.is_available,
"quality_group": quality_group} "quality_group": quality_group}
item_list.append(item) item_list.append(item)
# Sort items based on layer_height # Sort items based on layer_height
item_list = sorted(item_list, key = lambda x: float(x["layer_height_without_unit"])) item_list = sorted(item_list, key = lambda x: x["layer_height"])
self.setItems(item_list) self.setItems(item_list)
def _fetchLayerHeight(self, quality_group: "QualityGroup"): def _fetchLayerHeight(self, quality_group: "QualityGroup"):
global_stack = Application.getInstance().getMachineManager()._global_container_stack global_stack = self._machine_manager.activeMachine
if not self._layer_height_unit: if not self._layer_height_unit:
unit = global_stack.definition.getProperty("layer_height", "unit") unit = global_stack.definition.getProperty("layer_height", "unit")
if not unit: if not unit:
@ -96,10 +98,10 @@ class QualityProfilesModel(ListModel):
layer_height = default_layer_height layer_height = default_layer_height
if container.hasProperty("layer_height", "value"): if container.hasProperty("layer_height", "value"):
layer_height = str(container.getProperty("layer_height", "value")) layer_height = container.getProperty("layer_height", "value")
else: else:
# Look for layer_height in the GlobalStack from material -> definition # Look for layer_height in the GlobalStack from material -> definition
container = global_stack.definition container = global_stack.definition
if container.hasProperty("layer_height", "value"): if container.hasProperty("layer_height", "value"):
layer_height = container.getProperty("layer_height", "value") layer_height = container.getProperty("layer_height", "value")
return str(layer_height) return float(layer_height)

View file

@ -4,6 +4,7 @@
from PyQt5.QtCore import pyqtProperty, pyqtSignal, Qt from PyQt5.QtCore import pyqtProperty, pyqtSignal, Qt
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
@ -33,9 +34,10 @@ class QualitySettingsModel(ListModel):
self._container_registry = ContainerRegistry.getInstance() self._container_registry = ContainerRegistry.getInstance()
self._application = Application.getInstance() self._application = Application.getInstance()
self._quality_manager = self._application._quality_manager self._quality_manager = self._application.getQualityManager()
self._extruder_position = "" self._selected_position = "" # empty string means GlobalStack
# strings such as "0", "1", etc. mean extruder positions
self._selected_quality_item = None # The selected quality in the quality management page self._selected_quality_item = None # The selected quality in the quality management page
self._i18n_catalog = None self._i18n_catalog = None
@ -43,18 +45,18 @@ class QualitySettingsModel(ListModel):
self._update() self._update()
extruderPositionChanged = pyqtSignal() selectedPositionChanged = pyqtSignal()
selectedQualityItemChanged = pyqtSignal() selectedQualityItemChanged = pyqtSignal()
def setExtruderPosition(self, extruder_position): def setSelectedPosition(self, selected_position):
if extruder_position != self._extruder_position: if selected_position != self._selected_position:
self._extruder_position = extruder_position self._selected_position = selected_position
self.extruderPositionChanged.emit() self.selectedPositionChanged.emit()
self._update() self._update()
@pyqtProperty(str, fset = setExtruderPosition, notify = extruderPositionChanged) @pyqtProperty(str, fset = setSelectedPosition, notify = selectedPositionChanged)
def extruderPosition(self): def selectedPosition(self):
return self._extruder_position return self._selected_position
def setSelectedQualityItem(self, selected_quality_item): def setSelectedQualityItem(self, selected_quality_item):
if selected_quality_item != self._selected_quality_item: if selected_quality_item != self._selected_quality_item:
@ -73,32 +75,38 @@ class QualitySettingsModel(ListModel):
items = [] items = []
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = self._application.getGlobalContainerStack()
definition_container = global_container_stack.definition definition_container = global_container_stack.definition
quality_group = self._selected_quality_item["quality_group"] quality_group = self._selected_quality_item["quality_group"]
quality_changes_group = self._selected_quality_item["quality_changes_group"] quality_changes_group = self._selected_quality_item["quality_changes_group"]
if self._extruder_position == "": if self._selected_position == "":
quality_node = quality_group.node_for_global quality_node = quality_group.node_for_global
else: else:
quality_node = quality_group.nodes_for_extruders.get(self._extruder_position) quality_node = quality_group.nodes_for_extruders.get(self._selected_position)
settings_keys = quality_group.getAllKeys() settings_keys = quality_group.getAllKeys()
quality_containers = [quality_node.getContainer()] quality_containers = [quality_node.getContainer()]
# Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch
# the settings in that quality_changes_group.
if quality_changes_group is not None: if quality_changes_group is not None:
if self._extruder_position == "": if self._selected_position == "":
quality_changes_node = quality_changes_group.node_for_global quality_changes_node = quality_changes_group.node_for_global
else: else:
quality_changes_node = quality_changes_group.nodes_for_extruders.get(self._extruder_position) quality_changes_node = quality_changes_group.nodes_for_extruders.get(self._selected_position)
if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime
try: try:
quality_containers.insert(0, quality_changes_node.getContainer()) quality_containers.insert(0, quality_changes_node.getContainer())
except: except:
# FIXME: This is to prevent incomplete update of QualityManager # FIXME: This is to prevent incomplete update of QualityManager
Logger.logException("d", "Failed to get container for quality changes node %s", quality_changes_node)
return return
settings_keys.update(quality_changes_group.getAllKeys()) settings_keys.update(quality_changes_group.getAllKeys())
# We iterate over all definitions instead of settings in a quality/qualtiy_changes group is because in the GUI,
# the settings are grouped together by categories, and we had to go over all the definitions to figure out
# which setting belongs in which category.
current_category = "" current_category = ""
for definition in definition_container.findDefinitions(): for definition in definition_container.findDefinitions():
if definition.type == "category": if definition.type == "category":
@ -117,7 +125,7 @@ class QualitySettingsModel(ListModel):
profile_value = new_value profile_value = new_value
# Global tab should use resolve (if there is one) # Global tab should use resolve (if there is one)
if self._extruder_position == "": if self._selected_position == "":
resolve_value = global_container_stack.getProperty(definition.key, "resolve") resolve_value = global_container_stack.getProperty(definition.key, "resolve")
if resolve_value is not None and definition.key in settings_keys: if resolve_value is not None and definition.key in settings_keys:
profile_value = resolve_value profile_value = resolve_value
@ -125,10 +133,10 @@ class QualitySettingsModel(ListModel):
if profile_value is not None: if profile_value is not None:
break break
if not self._extruder_position: if not self._selected_position:
user_value = global_container_stack.userChanges.getProperty(definition.key, "value") user_value = global_container_stack.userChanges.getProperty(definition.key, "value")
else: else:
extruder_stack = global_container_stack.extruders[self._extruder_position] extruder_stack = global_container_stack.extruders[self._selected_position]
user_value = extruder_stack.userChanges.getProperty(definition.key, "value") user_value = extruder_stack.userChanges.getProperty(definition.key, "value")
if profile_value is None and user_value is None: if profile_value is None and user_value is None:

View file

@ -0,0 +1,53 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Application import Application
from .QualityGroup import QualityGroup
class QualityChangesGroup(QualityGroup):
def __init__(self, name: str, quality_type: str, parent = None):
super().__init__(name, quality_type, parent)
self._container_registry = Application.getInstance().getContainerRegistry()
def addNode(self, node: "QualityNode"):
# TODO: in 3.2 and earlier, a quality_changes container may have a field called "extruder" which contains the
# extruder definition ID it belongs to. But, in fact, we only need to know the following things:
# 1. which machine a custom profile is suitable for,
# 2. if this profile is for the GlobalStack,
# 3. if this profile is for an ExtruderStack and which one (the position).
#
# So, it is preferred to have a field like this:
# extruder_position = 1
# instead of this:
# extruder = custom_extruder_1
#
# An upgrade needs to be done if we want to do it this way. Before that, we use the extruder's definition
# to figure out its position.
#
extruder_definition_id = node.metadata.get("extruder")
if extruder_definition_id:
metadata_list = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)
if not metadata_list:
raise RuntimeError("%s cannot get metadata for extruder definition [%s]" %
(self, extruder_definition_id))
extruder_definition_metadata = metadata_list[0]
extruder_position = str(extruder_definition_metadata["position"])
if extruder_position in self.nodes_for_extruders:
raise RuntimeError("%s tries to overwrite the existing nodes_for_extruders position [%s] %s with %s" %
(self, extruder_position, self.node_for_global, node))
self.nodes_for_extruders[extruder_position] = node
else:
# This is a quality_changes for the GlobalStack
if self.node_for_global is not None:
raise RuntimeError("%s tries to overwrite the existing node_for_global %s with %s" %
(self, self.node_for_global, node))
self.node_for_global = node
def __str__(self) -> str:
return "%s[<%s>, available = %s]" % (self.__class__.__name__, self.name, self.is_available)

View file

@ -0,0 +1,50 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, List
from PyQt5.QtCore import QObject, pyqtSlot
#
# A QualityGroup represents a group of containers that must be applied to each ContainerStack when it's used.
# Some concrete examples are Quality and QualityChanges: when we select quality type "normal", this quality type
# must be applied to all stacks in a machine, although each stack can have different containers. Use an Ultimaker 3
# as an example, suppose we choose quality type "normal", the actual InstanceContainers on each stack may look
# as below:
# GlobalStack ExtruderStack 1 ExtruderStack 2
# quality container: um3_global_normal um3_aa04_pla_normal um3_aa04_abs_normal
#
# This QualityGroup is mainly used in quality and quality_changes to group the containers that can be applied to
# a machine, so when a quality/custom quality is selected, the container can be directly applied to each stack instead
# of looking them up again.
#
class QualityGroup(QObject):
def __init__(self, name: str, quality_type: str, parent = None):
super().__init__(parent)
self.name = name
self.node_for_global = None # type: Optional["QualityGroup"]
self.nodes_for_extruders = dict() # position str -> QualityGroup
self.quality_type = quality_type
self.is_available = False
@pyqtSlot(result = str)
def getName(self) -> str:
return self.name
def getAllKeys(self) -> set:
result = set()
for node in [self.node_for_global] + list(self.nodes_for_extruders.values()):
if node is None:
continue
result.update(node.getContainer().getAllKeys())
return result
def getAllNodes(self) -> List["QualityGroup"]:
result = []
if self.node_for_global is not None:
result.append(self.node_for_global)
for extruder_node in self.nodes_for_extruders.values():
result.append(extruder_node)
return result

View file

@ -1,154 +1,27 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, List from typing import TYPE_CHECKING, Optional
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.Util import parseBool from UM.Util import parseBool
from UM.Settings.InstanceContainer import InstanceContainer
from cura.Machines.ContainerNode import ContainerNode from cura.Settings.ExtruderStack import ExtruderStack
from .QualityGroup import QualityGroup
from .QualityNode import QualityNode
if TYPE_CHECKING:
from cura.Settings.GlobalStack import GlobalStack
from .QualityChangesGroup import QualityChangesGroup
# #
# Quality lookup tree structure: # Similar to MaterialManager, QualityManager maintains a number of maps and trees for quality profile lookup.
#
# <machine_definition_id>------|
# | |
# <variant_name> <root_material_id>
# |
# <root_material_id>
# |
# <quality_type>
# |
# <quality_name>
# + <quality_changes_name>
#
#
# A QualityGroup represents a group of containers that must be applied to each ContainerStack when it's used.
# Some concrete examples are Quality and QualityChanges: when we select quality type "normal", this quality type
# must be applied to all stacks in a machine, although each stack can have different containers. Use an Ultimaker 3
# as an example, suppose we choose quality type "normal", the actual InstanceContainers on each stack may look
# as below:
# GlobalStack ExtruderStack 1 ExtruderStack 2
# quality container: um3_global_normal um3_aa04_pla_normal um3_aa04_abs_normal
#
# This QualityGroup is mainly used in quality and quality_changes to group the containers that can be applied to
# a machine, so when a quality/custom quality is selected, the container can be directly applied to each stack instead
# of looking them up again.
#
class QualityGroup(QObject):
def __init__(self, name: str, quality_type: str, parent = None):
super().__init__(parent)
self.name = name
self.node_for_global = None # type: Optional["QualityGroup"]
self.nodes_for_extruders = dict() # position str -> QualityGroup
self.quality_type = quality_type
self.is_available = False
@pyqtSlot(result = str)
def getName(self) -> str:
return self.name
def getAllKeys(self) -> set:
result = set()
for node in [self.node_for_global] + list(self.nodes_for_extruders.values()):
if node is None:
continue
for key in node.getContainer().getAllKeys():
result.add(key)
return result
def getAllNodes(self) -> List["QualityGroup"]:
result = []
if self.node_for_global is not None:
result.append(self.node_for_global)
for extruder_node in self.nodes_for_extruders.values():
result.append(extruder_node)
return result
class QualityChangesGroup(QualityGroup):
def __init__(self, name: str, quality_type: str, parent = None):
super().__init__(name, quality_type, parent)
def addNode(self, node: "QualityNode"):
# TODO: in 3.2 and earlier, a quality_changes container may have a field called "extruder" which contains the
# extruder definition ID it belongs to. But, in fact, we only need to know the following things:
# 1. which machine a custom profile is suitable for,
# 2. if this profile is for the GlobalStack,
# 3. if this profile is for an ExtruderStack and which one (the position).
#
# So, it is preferred to have a field like this:
# extruder_position = 1
# instead of this:
# extruder = custom_extruder_1
#
# An upgrade needs to be done if we want to do it this way. Before that, we use the extruder's definition
# to figure out its position.
#
extruder_definition_id = node.metadata.get("extruder")
if extruder_definition_id:
container_registry = Application.getInstance().getContainerRegistry()
metadata_list = container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)
if not metadata_list:
raise RuntimeError("%s cannot get metadata for extruder definition [%s]" %
(self, extruder_definition_id))
extruder_definition_metadata = metadata_list[0]
extruder_position = str(extruder_definition_metadata["position"])
if extruder_position in self.nodes_for_extruders:
raise RuntimeError("%s tries to overwrite the existing nodes_for_extruders position [%s] %s with %s" %
(self, extruder_position, self.node_for_global, node))
self.nodes_for_extruders[extruder_position] = node
else:
# This is a quality_changes for the GlobalStack
if self.node_for_global is not None:
raise RuntimeError("%s tries to overwrite the existing node_for_global %s with %s" %
(self, self.node_for_global, node))
self.node_for_global = node
def __str__(self) -> str:
return "%s[<%s>, available = %s]" % (self.__class__.__name__, self.name, self.is_available)
#
# QualityNode is used for BOTH quality and quality_changes containers.
#
class QualityNode(ContainerNode):
def __init__(self, metadata: Optional[dict] = None):
super().__init__(metadata = metadata)
self.quality_type_map = {} # quality_type -> QualityNode for InstanceContainer
def addQualityMetadata(self, quality_type: str, metadata: dict):
if quality_type not in self.quality_type_map:
self.quality_type_map[quality_type] = QualityNode(metadata)
def getQualityNode(self, quality_type: str) -> Optional["QualityNode"]:
return self.quality_type_map.get(quality_type)
def addQualityChangesMetadata(self, quality_type: str, metadata: dict):
if quality_type not in self.quality_type_map:
self.quality_type_map[quality_type] = QualityNode()
quality_type_node = self.quality_type_map[quality_type]
name = metadata["name"]
if name not in quality_type_node.children_map:
quality_type_node.children_map[name] = QualityChangesGroup(name, quality_type)
quality_changes_group = quality_type_node.children_map[name]
quality_changes_group.addNode(QualityNode(metadata))
#
# Similar to MaterialManager, QualityManager maintains a number of maps and trees for material lookup.
# The models GUI and QML use are now only dependent on the QualityManager. That means as long as the data in # The models GUI and QML use are now only dependent on the QualityManager. That means as long as the data in
# QualityManager gets updated correctly, the GUI models should be updated correctly too, and the same goes for GUI. # QualityManager gets updated correctly, the GUI models should be updated correctly too, and the same goes for GUI.
# #
@ -164,7 +37,7 @@ class QualityManager(QObject):
def __init__(self, container_registry, parent = None): def __init__(self, container_registry, parent = None):
super().__init__(parent) super().__init__(parent)
self._application = Application.getInstance() self._application = Application.getInstance()
self._material_manager = self._application._material_manager self._material_manager = self._application.getMaterialManager()
self._container_registry = container_registry self._container_registry = container_registry
self._empty_quality_container = self._application.empty_quality_container self._empty_quality_container = self._application.empty_quality_container
@ -305,7 +178,6 @@ class QualityManager(QObject):
# Returns a dict of "custom profile name" -> QualityChangesGroup # Returns a dict of "custom profile name" -> QualityChangesGroup
def getQualityChangesGroups(self, machine: "GlobalStack") -> dict: def getQualityChangesGroups(self, machine: "GlobalStack") -> dict:
# Get machine definition ID for quality search
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
machine_node = self._machine_quality_type_to_quality_changes_dict.get(machine_definition_id) machine_node = self._machine_quality_type_to_quality_changes_dict.get(machine_definition_id)
@ -327,9 +199,15 @@ class QualityManager(QObject):
return quality_changes_group_dict return quality_changes_group_dict
#
# Gets all quality groups for the given machine. Both available and none available ones will be included.
# It returns a dictionary with "quality_type"s as keys and "QualityGroup"s as values.
# Whether a QualityGroup is available can be unknown via the field QualityGroup.is_available.
# For more details, see QualityGroup.
#
def getQualityGroups(self, machine: "GlobalStack") -> dict: def getQualityGroups(self, machine: "GlobalStack") -> dict:
# Get machine definition ID for quality search
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
# This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks # This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks
has_variant_materials = parseBool(machine.getMetaDataEntry("has_variant_materials", False)) has_variant_materials = parseBool(machine.getMetaDataEntry("has_variant_materials", False))
@ -380,6 +258,17 @@ class QualityManager(QObject):
if fallback_root_material_id: if fallback_root_material_id:
root_material_id_list.append(fallback_root_material_id) root_material_id_list.append(fallback_root_material_id)
# 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
# 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.
nodes_to_check = [] nodes_to_check = []
if variant_name: if variant_name:
@ -426,7 +315,6 @@ class QualityManager(QObject):
return quality_group_dict return quality_group_dict
def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> dict: def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> dict:
# Get machine definition ID for quality search
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine) machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
# To find the quality container for the GlobalStack, check in the following fall-back manner: # To find the quality container for the GlobalStack, check in the following fall-back manner:
@ -449,6 +337,135 @@ class QualityManager(QObject):
return quality_group_dict return quality_group_dict
#
# Methods for GUI
#
#
# Remove the given quality changes group.
#
@pyqtSlot(QObject)
def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"):
Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name)
for node in quality_changes_group.getAllNodes():
self._container_registry.removeContainer(node.metadata["id"])
#
# Rename a set of quality changes containers. Returns the new name.
#
@pyqtSlot(QObject, str, result = str)
def renameQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup", new_name: str) -> str:
Logger.log("i", "Renaming QualityChangesGroup[%s] to [%s]", quality_changes_group.name, new_name)
if new_name == quality_changes_group.name:
Logger.log("i", "QualityChangesGroup name [%s] unchanged.", quality_changes_group.name)
return new_name
new_name = self._container_registry.uniqueName(new_name)
for node in quality_changes_group.getAllNodes():
node.getContainer().setName(new_name)
quality_changes_group.name = new_name
self._application.getMachineManager().activeQualityChanged.emit()
self._application.getMachineManager().activeQualityGroupChanged.emit()
return new_name
#
# Duplicates the given quality.
#
@pyqtSlot(str, "QVariantMap")
def duplicateQualityChanges(self, quality_changes_name, quality_model_item):
global_stack = self._application.getGlobalContainerStack()
if not global_stack:
Logger.log("i", "No active global stack, cannot duplicate quality changes.")
return
quality_group = quality_model_item["quality_group"]
quality_changes_group = quality_model_item["quality_changes_group"]
if quality_changes_group is None:
# create global quality changes only
new_quality_changes = self._createQualityChanges(quality_group.quality_type, quality_changes_name,
global_stack, extruder_id = None)
self._container_registry.addContainer(new_quality_changes)
else:
new_name = self._container_registry.uniqueName(quality_changes_name)
for node in quality_changes_group.getAllNodes():
container = node.getContainer()
new_id = self._container_registry.uniqueName(container.getId())
self._container_registry.addContainer(container.duplicate(new_id, new_name))
## Create quality changes containers from the user containers in the active stacks.
#
# This will go through the global and extruder stacks and create quality_changes containers from
# the user containers in each stack. These then replace the quality_changes containers in the
# stack and clear the user settings.
@pyqtSlot(str)
def createQualityChanges(self, base_name):
machine_manager = Application.getInstance().getMachineManager()
global_stack = machine_manager.activeMachine
if not global_stack:
return
active_quality_name = machine_manager.activeQualityOrQualityChangesName
if active_quality_name == "":
Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId())
return
machine_manager.blurSettings.emit()
if base_name is None or base_name == "":
base_name = active_quality_name
unique_name = self._container_registry.uniqueName(base_name)
# Go through the active stacks and create quality_changes containers from the user containers.
stack_list = [global_stack] + list(global_stack.extruders.values())
for stack in stack_list:
user_container = stack.userChanges
quality_container = stack.quality
quality_changes_container = stack.qualityChanges
if not quality_container or not quality_changes_container:
Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId())
continue
extruder_definition_id = None
if isinstance(stack, ExtruderStack):
extruder_definition_id = stack.definition.getId()
quality_type = quality_container.getMetaDataEntry("quality_type")
new_changes = self._createQualityChanges(quality_type, unique_name, global_stack, extruder_definition_id)
from cura.Settings.ContainerManager import ContainerManager
ContainerManager.getInstance()._performMerge(new_changes, quality_changes_container, clear_settings = False)
ContainerManager.getInstance()._performMerge(new_changes, user_container)
self._container_registry.addContainer(new_changes)
#
# Create a quality changes container with the given setup.
#
def _createQualityChanges(self, quality_type: str, new_name: str, machine: "GlobalStack",
extruder_id: Optional[str]) -> "InstanceContainer":
base_id = machine.definition.getId() if extruder_id is None else extruder_id
new_id = base_id + "_" + new_name
new_id = new_id.lower().replace(" ", "_")
new_id = self._container_registry.uniqueName(new_id)
# Create a new quality_changes container for the quality.
quality_changes = InstanceContainer(new_id)
quality_changes.setName(new_name)
quality_changes.addMetaDataEntry("type", "quality_changes")
quality_changes.addMetaDataEntry("quality_type", quality_type)
# If we are creating a container for an extruder, ensure we add that to the container
if extruder_id is not None:
quality_changes.addMetaDataEntry("extruder", extruder_id)
# If the machine specifies qualities should be filtered, ensure we match the current criteria.
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
quality_changes.setDefinition(machine_definition_id)
quality_changes.addMetaDataEntry("setting_version", self._application.SettingVersion)
return quality_changes
# #
# Gets the machine definition ID that can be used to search for Quality containers that are suitable for the given # Gets the machine definition ID that can be used to search for Quality containers that are suitable for the given

View file

@ -0,0 +1,35 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
from .ContainerNode import ContainerNode
from .QualityChangesGroup import QualityChangesGroup
#
# QualityNode is used for BOTH quality and quality_changes containers.
#
class QualityNode(ContainerNode):
def __init__(self, metadata: Optional[dict] = None):
super().__init__(metadata = metadata)
self.quality_type_map = {} # quality_type -> QualityNode for InstanceContainer
def addQualityMetadata(self, quality_type: str, metadata: dict):
if quality_type not in self.quality_type_map:
self.quality_type_map[quality_type] = QualityNode(metadata)
def getQualityNode(self, quality_type: str) -> Optional["QualityNode"]:
return self.quality_type_map.get(quality_type)
def addQualityChangesMetadata(self, quality_type: str, metadata: dict):
if quality_type not in self.quality_type_map:
self.quality_type_map[quality_type] = QualityNode()
quality_type_node = self.quality_type_map[quality_type]
name = metadata["name"]
if name not in quality_type_node.children_map:
quality_type_node.children_map[name] = QualityChangesGroup(name, quality_type)
quality_changes_group = quality_type_node.children_map[name]
quality_changes_group.addNode(QualityNode(metadata))

View file

@ -1,17 +1,22 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from enum import Enum
from collections import OrderedDict from collections import OrderedDict
from typing import Optional from typing import Optional, TYPE_CHECKING
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Util import parseBool
from cura.Machines.ContainerNode import ContainerNode from cura.Machines.ContainerNode import ContainerNode
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
if TYPE_CHECKING:
from UM.Settings.DefinitionContainer import DefinitionContainer
class VariantType:
class VariantType(Enum):
BUILD_PLATE = "buildplate" BUILD_PLATE = "buildplate"
NOZZLE = "nozzle" NOZZLE = "nozzle"
@ -64,6 +69,7 @@ class VariantManager:
self._machine_to_variant_dict_map[variant_definition][variant_type] = dict() self._machine_to_variant_dict_map[variant_definition][variant_type] = dict()
variant_type = variant_metadata["hardware_type"] variant_type = variant_metadata["hardware_type"]
variant_type = VariantType(variant_type)
variant_dict = self._machine_to_variant_dict_map[variant_definition][variant_type] variant_dict = self._machine_to_variant_dict_map[variant_definition][variant_type]
if variant_name in variant_dict: if variant_name in variant_dict:
# ERROR: duplicated variant name. # ERROR: duplicated variant name.
@ -77,10 +83,29 @@ class VariantManager:
# Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present. # Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present.
# #
def getVariantNode(self, machine_definition_id: str, variant_name: str, def getVariantNode(self, machine_definition_id: str, variant_name: str,
variant_type: Optional[str] = VariantType.NOZZLE) -> Optional["ContainerNode"]: variant_type: Optional["VariantType"] = VariantType.NOZZLE) -> Optional["ContainerNode"]:
return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name) return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name)
def getVariantNodes(self, machine: "GlobalStack", def getVariantNodes(self, machine: "GlobalStack",
variant_type: Optional[str] = VariantType.NOZZLE) -> dict: variant_type: Optional["VariantType"] = VariantType.NOZZLE) -> dict:
machine_definition_id = machine.definition.getId() machine_definition_id = machine.definition.getId()
return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {}) return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {})
#
# Gets the default variant for the given machine definition.
#
def getDefaultVariantNode(self, machine_definition: "DefinitionContainer",
variant_type: VariantType) -> Optional["ContainerNode"]:
machine_definition_id = machine_definition.getId()
preferred_variant_name = None
if variant_type == VariantType.BUILD_PLATE:
if parseBool(machine_definition.getMetaDataEntry("has_variant_buildplates", False)):
preferred_variant_name = machine_definition.getMetaDataEntry("preferred_variant_buildplate_name")
else:
if parseBool(machine_definition.getMetaDataEntry("has_variants", False)):
preferred_variant_name = machine_definition.getMetaDataEntry("preferred_variant_name")
node = None
if preferred_variant_name:
node = self.getVariantNode(machine_definition_id, preferred_variant_name, variant_type)
return node

View file

@ -202,8 +202,6 @@ class PrintInformation(QObject):
if global_stack is None: if global_stack is None:
return return
# Material amount is sent as an amount of mm^3, so calculate length from that
radius = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
self._material_lengths[build_plate_number] = [] self._material_lengths[build_plate_number] = []
self._material_weights[build_plate_number] = [] self._material_weights[build_plate_number] = []
self._material_costs[build_plate_number] = [] self._material_costs[build_plate_number] = []
@ -212,16 +210,16 @@ class PrintInformation(QObject):
material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings")) material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings"))
extruder_stacks = global_stack.extruders extruder_stacks = global_stack.extruders
for extruder_key in global_stack.extruders.keys(): for position, extruder_stack in extruder_stacks.items():
index = int(extruder_key) index = int(position)
if index >= len(self._material_amounts): # Right now the _material_amounts is a list, where the index is the extruder number if index >= len(self._material_amounts):
continue continue
amount = self._material_amounts[index] amount = self._material_amounts[index]
## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some ## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some
# list comprehension filtering to solve this for us. # list comprehension filtering to solve this for us.
extruder_stack = extruder_stacks[str(index)]
density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0) density = extruder_stack.getMetaDataEntry("properties", {}).get("density", 0)
material = extruder_stack.findContainer({"type": "material"}) material = extruder_stack.findContainer({"type": "material"})
radius = extruder_stack.getProperty("material_diameter", "value") / 2
weight = float(amount) * float(density) / 1000 weight = float(amount) * float(density) / 1000
cost = 0 cost = 0
@ -240,6 +238,7 @@ class PrintInformation(QObject):
else: else:
cost = 0 cost = 0
# Material amount is sent as an amount of mm^3, so calculate length from that
if radius != 0: if radius != 0:
length = round((amount / (math.pi * radius ** 2)) / 1000, 2) length = round((amount / (math.pi * radius ** 2)) / 1000, 2)
else: else:

View file

@ -4,7 +4,7 @@ from PyQt5.QtCore import Qt, pyqtSlot, QObject
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from cura.ObjectsModel import ObjectsModel from cura.ObjectsModel import ObjectsModel
from cura.Machines.Models.Other.MultiBuildPlateModel import MultiBuildPlateModel from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel
from UM.Application import Application from UM.Application import Application
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator

View file

@ -1,7 +1,6 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import copy
import os.path import os.path
import urllib.parse import urllib.parse
import uuid import uuid
@ -29,10 +28,10 @@ from UM.i18n import i18nCatalog
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.ExtruderStack import ExtruderStack
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
## Manager class that contains common actions to deal with containers in Cura. ## Manager class that contains common actions to deal with containers in Cura.
# #
# This is primarily intended as a class to be able to perform certain actions # This is primarily intended as a class to be able to perform certain actions
@ -160,17 +159,6 @@ class ContainerManager(QObject):
return container.getProperty(setting_key, property_name) return container.getProperty(setting_key, property_name)
## Set the name of the specified material.
@pyqtSlot("QVariant", str)
def setMaterialName(self, material_node, new_name):
root_material_id = material_node.metadata["base_file"]
if self._container_registry.isReadOnly(root_material_id):
Logger.log("w", "Cannot set name of read-only container %s.", root_material_id)
return
material_group = self._material_manager.getMaterialGroup(root_material_id)
material_group.root_material_node.getContainer().setName(new_name)
@pyqtSlot(str, result = str) @pyqtSlot(str, result = str)
def makeUniqueName(self, original_name): def makeUniqueName(self, original_name):
return self._container_registry.uniqueName(original_name) return self._container_registry.uniqueName(original_name)
@ -355,191 +343,6 @@ class ContainerManager(QObject):
for container in send_emits_containers: for container in send_emits_containers:
container.sendPostponedEmits() container.sendPostponedEmits()
## Create quality changes containers from the user containers in the active stacks.
#
# This will go through the global and extruder stacks and create quality_changes containers from
# the user containers in each stack. These then replace the quality_changes containers in the
# stack and clear the user settings.
#
# \return \type{bool} True if the operation was successfully, False if not.
@pyqtSlot(str)
def createQualityChanges(self, base_name):
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return
active_quality_name = self._machine_manager.activeQualityOrQualityChangesName
if active_quality_name == "":
Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId())
return
self._machine_manager.blurSettings.emit()
if base_name is None or base_name == "":
base_name = active_quality_name
unique_name = self._container_registry.uniqueName(base_name)
# Go through the active stacks and create quality_changes containers from the user containers.
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
user_container = stack.userChanges
quality_container = stack.quality
quality_changes_container = stack.qualityChanges
if not quality_container or not quality_changes_container:
Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId())
continue
extruder_definition_id = None
if isinstance(stack, ExtruderStack):
extruder_definition_id = stack.definition.getId()
quality_type = quality_container.getMetaDataEntry("quality_type")
new_changes = self._createQualityChanges(quality_type, unique_name, global_stack, extruder_definition_id)
self._performMerge(new_changes, quality_changes_container, clear_settings = False)
self._performMerge(new_changes, user_container)
self._container_registry.addContainer(new_changes)
#
# Remove the given quality changes group
#
@pyqtSlot(QObject)
def removeQualityChangesGroup(self, quality_changes_group):
Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name)
for node in quality_changes_group.getAllNodes():
self._container_registry.removeContainer(node.metadata["id"])
#
# Rename a set of quality changes containers. Returns the new name.
#
@pyqtSlot(QObject, str, result = str)
def renameQualityChangesGroup(self, quality_changes_group, new_name) -> str:
Logger.log("i", "Renaming QualityChangesGroup[%s] to [%s]", quality_changes_group.name, new_name)
self._machine_manager.blurSettings.emit()
if new_name == quality_changes_group.name:
Logger.log("i", "QualityChangesGroup name [%s] unchanged.", quality_changes_group.name)
return new_name
new_name = self._container_registry.uniqueName(new_name)
for node in quality_changes_group.getAllNodes():
node.getContainer().setName(new_name)
self._machine_manager.activeQualityChanged.emit()
self._machine_manager.activeQualityGroupChanged.emit()
return new_name
@pyqtSlot(str, "QVariantMap")
def duplicateQualityChanges(self, quality_changes_name, quality_model_item):
global_stack = Application.getInstance().getGlobalContainerStack()
quality_group = quality_model_item["quality_group"]
quality_changes_group = quality_model_item["quality_changes_group"]
if quality_changes_group is None:
# create global quality changes only
new_quality_changes = self._createQualityChanges(quality_group.quality_type, quality_changes_name,
global_stack, extruder_id = None)
self._container_registry.addContainer(new_quality_changes)
else:
new_name = self._container_registry.uniqueName(quality_changes_name)
for node in quality_changes_group.getAllNodes():
container = node.getContainer()
new_id = self._container_registry.uniqueName(container.getId())
self._container_registry.addContainer(container.duplicate(new_id, new_name))
@pyqtSlot("QVariant")
def removeMaterial(self, material_node):
root_material_id = material_node.metadata["base_file"]
material_group = self._material_manager.getMaterialGroup(root_material_id)
if not material_group:
Logger.log("d", "Unable to remove the material with id %s, because it doesn't exist.", root_material_id)
return
nodes_to_remove = [material_group.root_material_node] + material_group.derived_material_node_list
for node in nodes_to_remove:
self._container_registry.removeContainer(node.metadata["id"])
## Create a duplicate of a material, which has the same GUID and base_file metadata
#
# \return \type{str} the id of the newly created container.
@pyqtSlot("QVariant", result = str)
def duplicateMaterial(self, material_node, new_base_id = None, new_metadata = None):
root_material_id = material_node.metadata["base_file"]
material_group = self._material_manager.getMaterialGroup(root_material_id)
if not material_group:
Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", root_material_id)
return
base_container = material_group.root_material_node.getContainer()
containers_to_copy = []
for node in material_group.derived_material_node_list:
containers_to_copy.append(node.getContainer())
# Ensure all settings are saved.
Application.getInstance().saveSettings()
# Create a new ID & container to hold the data.
new_containers = []
if new_base_id is None:
new_base_id = self._container_registry.uniqueName(base_container.getId())
new_base_container = copy.deepcopy(base_container)
new_base_container.getMetaData()["id"] = new_base_id
new_base_container.getMetaData()["base_file"] = new_base_id
if new_metadata is not None:
for key, value in new_metadata.items():
new_base_container.getMetaData()[key] = value
new_containers.append(new_base_container)
# Clone all of them.
for container_to_copy in containers_to_copy:
# Create unique IDs for every clone.
new_id = new_base_id
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(" ", "_")
new_container = copy.deepcopy(container_to_copy)
new_container.getMetaData()["id"] = new_id
new_container.getMetaData()["base_file"] = new_base_id
if new_metadata is not None:
for key, value in new_metadata.items():
new_container.getMetaData()[key] = value
new_containers.append(new_container)
for container_to_add in new_containers:
container_to_add.setDirty(True)
ContainerRegistry.getInstance().addContainer(container_to_add)
return new_base_id
## Create a new material by cloning Generic PLA for the current material diameter and setting the GUID to something unqiue
#
# \return \type{str} the id of the newly created container.
@pyqtSlot(result = str)
def createMaterial(self):
# Ensure all settings are saved.
Application.getInstance().saveSettings()
global_stack = Application.getInstance().getGlobalContainerStack()
approximate_diameter = str(round(global_stack.getProperty("material_diameter", "value")))
root_material_id = "generic_pla"
root_material_id = self._material_manager.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
material_group = self._material_manager.getMaterialGroup(root_material_id)
# Create a new ID & container to hold the data.
new_id = self._container_registry.uniqueName("custom_material")
new_metadata = {"name": catalog.i18nc("@label", "Custom Material"),
"brand": catalog.i18nc("@label", "Custom"),
"GUID": str(uuid.uuid4()),
}
self.duplicateMaterial(material_group.root_material_node,
new_base_id = new_id,
new_metadata = new_metadata)
return new_id
## Get a list of materials that have the same GUID as the reference material ## Get a list of materials that have the same GUID as the reference material
# #
# \param material_id \type{str} the id of the material for which to get the linked materials. # \param material_id \type{str} the id of the material for which to get the linked materials.
@ -643,51 +446,6 @@ class ContainerManager(QObject):
name_filter = "{0} ({1})".format(mime_type.comment, suffix_list) name_filter = "{0} ({1})".format(mime_type.comment, suffix_list)
self._container_name_filters[name_filter] = entry self._container_name_filters[name_filter] = entry
## Creates a unique ID for a container by prefixing the name with the stack ID.
#
# This method creates a unique ID for a container by prefixing it with a specified stack ID.
# This is done to ensure we have an easily identified ID for quality changes, which have the
# same name across several stacks.
#
# \param stack_id The ID of the stack to prepend.
# \param container_name The name of the container that we are creating a unique ID for.
#
# \return Container name prefixed with stack ID, in lower case with spaces replaced by underscores.
def _createUniqueId(self, stack_id, container_name):
result = stack_id + "_" + container_name
result = result.lower()
result.replace(" ", "_")
return result
## Create a quality changes container for a specified quality container.
#
# \param quality_container The quality container to create a changes container for.
# \param new_name The name of the new quality_changes container.
# \param machine_definition The machine definition this quality changes container is specific to.
# \param extruder_id
#
# \return A new quality_changes container with the specified container as base.
def _createQualityChanges(self, quality_type, new_name, machine, extruder_id):
base_id = machine.definition.getId() if extruder_id is None else extruder_id
# Create a new quality_changes container for the quality.
quality_changes = InstanceContainer(self._createUniqueId(base_id, new_name))
quality_changes.setName(new_name)
quality_changes.addMetaDataEntry("type", "quality_changes")
quality_changes.addMetaDataEntry("quality_type", quality_type)
# If we are creating a container for an extruder, ensure we add that to the container
if extruder_id is not None:
quality_changes.addMetaDataEntry("extruder", extruder_id)
# If the machine specifies qualities should be filtered, ensure we match the current criteria.
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
quality_changes.setDefinition(machine_definition_id)
from cura.CuraApplication import CuraApplication
quality_changes.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
return quality_changes
## Import single profile, file_url does not have to end with curaprofile ## Import single profile, file_url does not have to end with curaprofile
@pyqtSlot(QUrl, result="QVariantMap") @pyqtSlot(QUrl, result="QVariantMap")
def importProfile(self, file_url): def importProfile(self, file_url):

View file

@ -41,29 +41,17 @@ class CuraStackBuilder:
# get variant container for the global stack # get variant container for the global stack
global_variant_container = application.empty_variant_container global_variant_container = application.empty_variant_container
if parseBool(machine_definition.getMetaDataEntry("has_variant_buildplates", False)): global_variant_node = variant_manager.getDefaultVariantNode(machine_definition, VariantType.BUILD_PLATE)
global_variant_name = machine_definition.getMetaDataEntry("preferred_variant_buildplate_name") if global_variant_node:
if global_variant_name: global_variant_container = global_variant_node.getContainer()
variant_node = variant_manager.getVariantNode(definition_id, global_variant_name,
variant_type = VariantType.BUILD_PLATE)
if variant_node is None:
raise RuntimeError("Cannot find buildplate variant with definition [%s] and variant name [%s]" %
(definition_id, global_variant_name))
global_variant_container = variant_node.getContainer()
# get variant container for extruders # get variant container for extruders
extruder_variant_container = application.empty_variant_container extruder_variant_container = application.empty_variant_container
# Only look for the preferred variant if this machine has variants extruder_variant_node = variant_manager.getDefaultVariantNode(machine_definition, VariantType.NOZZLE)
extruder_variant_name = None extruder_variant_name = None
if parseBool(machine_definition.getMetaDataEntry("has_variants", False)): if extruder_variant_node:
extruder_variant_name = machine_definition.getMetaDataEntry("preferred_variant_name") extruder_variant_container = extruder_variant_node.getContainer()
if extruder_variant_name: extruder_variant_name = extruder_variant_container.getName()
variant_node = variant_manager.getVariantNode(definition_id, extruder_variant_name)
# Sanity check. If you see this error, the related definition files should be fixed.
if variant_node is None:
raise RuntimeError("Cannot find extruder variant with definition [%s] and variant name [%s]" %
(definition_id, extruder_variant_name))
extruder_variant_container = variant_node.getContainer()
generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName()) generated_name = registry.createUniqueName("machine", "", name, machine_definition.getName())
# Make sure the new name does not collide with any definition or (quality) profile # Make sure the new name does not collide with any definition or (quality) profile
@ -83,19 +71,8 @@ class CuraStackBuilder:
# get material container for extruders # get material container for extruders
material_container = application.empty_material_container material_container = application.empty_material_container
# Only look for the preferred material if this machine has materials material_node = material_manager.getDefaultMaterial(new_global_stack, extruder_variant_name)
if parseBool(machine_definition.getMetaDataEntry("has_materials", False)): if material_node:
material_diameter = machine_definition.getProperty("material_diameter", "value")
if isinstance(material_diameter, SettingFunction):
material_diameter = material_diameter(new_global_stack)
approximate_material_diameter = str(round(material_diameter))
root_material_id = machine_definition.getMetaDataEntry("preferred_material")
root_material_id = material_manager.getRootMaterialIDForDiameter(root_material_id, approximate_material_diameter)
material_node = material_manager.getMaterialNode(definition_id, extruder_variant_name, material_diameter, root_material_id)
# Sanity check. If you see this error, the related definition files should be fixed.
if not material_node:
raise RuntimeError("Cannot find material with definition [%s], extruder_variant_name [%s], and root_material_id [%s]" %
(definition_id, extruder_variant_name, root_material_id))
material_container = material_node.getContainer() material_container = material_node.getContainer()
# Create ExtruderStacks # Create ExtruderStacks

View file

@ -414,6 +414,33 @@ class ExtruderManager(QObject):
self.extrudersChanged.emit(global_stack_id) self.extrudersChanged.emit(global_stack_id)
self.setActiveExtruderIndex(0) self.setActiveExtruderIndex(0)
#
# This function tries to fix the problem with per-extruder-settable nozzle size and material diameter problems
# in early versions (3.0 - 3.2.1).
#
# In earlier versions, "nozzle size" and "material diameter" are only applicable to the complete machine, so all
# extruders share the same values. In this case, "nozzle size" and "material diameter" are saved in the
# GlobalStack's DefinitionChanges container.
#
# Later, we could have different "nozzle size" for each extruder, but "material diameter" could only be set for
# the entire machine. In this case, "nozzle size" should be saved in each ExtruderStack's DefinitionChanges, but
# "material diameter" still remains in the GlobalStack's DefinitionChanges.
#
# Lateer, both "nozzle size" and "material diameter" are settable per-extruder, and both settings should be saved
# in the ExtruderStack's DefinitionChanges.
#
# There were some bugs in upgrade so the data weren't saved correct as described above. This function tries fix
# this.
#
# One more thing is about material diameter and single-extrusion machines. Most single-extrusion machines don't
# specifically define their extruder definition, so they reuse "fdmextruder", but for those machines, they may
# define "material diameter = 1.75" in their machine definition, but in "fdmextruder", it's still "2.85". This
# causes a problem with incorrect default values.
#
# This is also fixed here in this way: If no "material diameter" is specified, it will look for the default value
# in both the Extruder's definition and the Global's definition. If 2 values don't match, we will use the value
# from the Global definition by setting it in the Extruder's DefinitionChanges container.
#
def _fixMaterialDiameterAndNozzleSize(self, global_stack, extruder_stack_list): def _fixMaterialDiameterAndNozzleSize(self, global_stack, extruder_stack_list):
keys_to_copy = ["material_diameter", "machine_nozzle_size"] # these will be copied over to all extruders keys_to_copy = ["material_diameter", "machine_nozzle_size"] # these will be copied over to all extruders
@ -424,22 +451,6 @@ class ExtruderManager(QObject):
if extruder_stack.definitionChanges.hasProperty(key, "value"): if extruder_stack.definitionChanges.hasProperty(key, "value"):
continue continue
#
# We cannot add a setting definition of "material_diameter" into the extruder's definition at runtime
# because all other machines which uses "fdmextruder" as the extruder definition will be affected.
#
# The problem is that single extrusion machines have their default material diameter defined in the global
# definitions. Now we automatically create an extruder stack for those machines using "fdmextruder"
# definition, which doesn't have the specific "material_diameter" and "machine_nozzle_size" defined for
# each machine. This results in wrong values which can be found in the MachineSettings dialog.
#
# To solve this, we put "material_diameter" back into the "fdmextruder" definition because modifying it in
# the extruder definition will affect all machines which uses the "fdmextruder" definition. Moreover, now
# we also check the value defined in the machine definition. If present, the value defined in the global
# stack's definition changes container will be copied. Otherwise, we will check if the default values in the
# machine definition and the extruder definition are the same, and if not, the default value in the machine
# definition will be copied to the extruder stack's definition changes.
#
setting_value_in_global_def_changes = global_stack.definitionChanges.getProperty(key, "value") setting_value_in_global_def_changes = global_stack.definitionChanges.getProperty(key, "value")
setting_value_in_global_def = global_stack.definition.getProperty(key, "value") setting_value_in_global_def = global_stack.definition.getProperty(key, "value")
setting_value = setting_value_in_global_def setting_value = setting_value_in_global_def

View file

@ -13,7 +13,7 @@ from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
from UM.Util import parseBool from UM.Util import parseBool
from . import Exceptions from . import Exceptions
from .CuraContainerStack import CuraContainerStack from .CuraContainerStack import CuraContainerStack, _ContainerIndexes
from .ExtruderManager import ExtruderManager from .ExtruderManager import ExtruderManager
if TYPE_CHECKING: if TYPE_CHECKING:
@ -69,14 +69,10 @@ class ExtruderStack(CuraContainerStack):
# \return The filament diameter for the printer # \return The filament diameter for the printer
@property @property
def materialDiameter(self) -> float: def materialDiameter(self) -> float:
containers_to_check = [self.variant, self.definitionChanges, self.definition] context = PropertyEvaluationContext(self)
context.context["evaluate_from_container_index"] = _ContainerIndexes.Variant
for container in containers_to_check: return self.getProperty("material_diameter", "value", context = context)
if container is not None:
material_diameter = container.getProperty("material_diameter", "value")
if material_diameter is not None:
return material_diameter
return -1
## Return the approximate filament diameter that the machine requires. ## Return the approximate filament diameter that the machine requires.
# #

View file

@ -119,16 +119,13 @@ class MachineManager(QObject):
if containers: if containers:
containers[0].nameChanged.connect(self._onMaterialNameChanged) containers[0].nameChanged.connect(self._onMaterialNameChanged)
# NEW
self._material_manager = self._application._material_manager self._material_manager = self._application._material_manager
self._material_manager.materialsUpdated.connect(self._onMaterialsUpdated) self._quality_manager = self._application.getQualityManager()
def _onMaterialsUpdated(self):
# When the materials lookup table gets updated, it can mean that a material has its name changed, which should # When the materials lookup table gets updated, it can mean that a material has its name changed, which should
# be reflected on the GUI. This signal emission makes sure that it happens. # be reflected on the GUI. This signal emission makes sure that it happens.
self.rootMaterialChanged.emit() self._material_manager.materialsUpdated.connect(self.rootMaterialChanged)
### NEW
activeQualityGroupChanged = pyqtSignal() activeQualityGroupChanged = pyqtSignal()
activeQualityChangesGroupChanged = pyqtSignal() activeQualityChangesGroupChanged = pyqtSignal()
@ -303,14 +300,12 @@ class MachineManager(QObject):
if containers: if containers:
global_stack = containers[0] global_stack = containers[0]
ExtruderManager.getInstance().setActiveExtruderIndex(0) # Switch to first extruder ExtruderManager.getInstance().setActiveExtruderIndex(0) # Switch to first extruder
Application.getInstance().setGlobalContainerStack(global_stack)
self._global_container_stack = global_stack self._global_container_stack = global_stack
Application.getInstance().setGlobalContainerStack(global_stack) Application.getInstance().setGlobalContainerStack(global_stack)
ExtruderManager.getInstance()._globalContainerStackChanged() ExtruderManager.getInstance()._globalContainerStackChanged()
self._initMachineState(containers[0]) self._initMachineState(containers[0])
self.updateDefaultExtruder() self.updateDefaultExtruder()
self.updateNumberExtrudersEnabled() self.updateNumberExtrudersEnabled()
self.globalContainerChanged.emit()
self._onGlobalContainerChanged() self._onGlobalContainerChanged()
self.__emitChangedSignals() self.__emitChangedSignals()
@ -835,11 +830,6 @@ class MachineManager(QObject):
container = extruder.userChanges container = extruder.userChanges
container.setProperty(setting_name, property_name, property_value) container.setProperty(setting_name, property_name, property_value)
#
# New
#
# We not fetch it from _current_root_material_id, but later we can get it from somewhere else
@pyqtProperty("QVariantList", notify = rootMaterialChanged) @pyqtProperty("QVariantList", notify = rootMaterialChanged)
def currentExtruderPositions(self): def currentExtruderPositions(self):
return sorted(list(self._current_root_material_id.keys())) return sorted(list(self._current_root_material_id.keys()))
@ -879,6 +869,10 @@ class MachineManager(QObject):
return result return result
#
# Sets all quality and quality_changes containers to empty_quality and empty_quality_changes containers
# for all stacks in the currently active machine.
#
def _setEmptyQuality(self): def _setEmptyQuality(self):
self._current_quality_group = None self._current_quality_group = None
self._current_quality_changes_group = None self._current_quality_changes_group = None
@ -911,11 +905,8 @@ class MachineManager(QObject):
self.activeQualityChangesGroupChanged.emit() self.activeQualityChangesGroupChanged.emit()
def _setQualityChangesGroup(self, quality_changes_group): def _setQualityChangesGroup(self, quality_changes_group):
# TODO: quality_changes groups depend on a quality_type. Here it's fetching the quality_types every time.
# Can we do this better, like caching the quality group a quality_changes group depends on?
quality_type = quality_changes_group.quality_type quality_type = quality_changes_group.quality_type
quality_manager = Application.getInstance()._quality_manager quality_group_dict = self._quality_manager.getQualityGroups(self._global_container_stack)
quality_group_dict = quality_manager.getQualityGroups(self._global_container_stack)
quality_group = quality_group_dict[quality_type] quality_group = quality_group_dict[quality_type]
quality_changes_container = self._empty_quality_changes_container quality_changes_container = self._empty_quality_changes_container
@ -1031,13 +1022,6 @@ class MachineManager(QObject):
self._setMaterial(position, new_material) self._setMaterial(position, new_material)
continue continue
# # Find a fallback material
# preferred_material_query = self._global_container_stack.getMetaDataEntry("preferred_material")
# preferred_material_key = preferred_material_query.replace("*", "")
# if preferred_material_key in candidate_materials:
# self._setMaterial(position, candidate_materials[preferred_material_key])
# return
@pyqtSlot("QVariant") @pyqtSlot("QVariant")
def setGlobalVariant(self, container_node): def setGlobalVariant(self, container_node):
self.blurSettings.emit() self.blurSettings.emit()

View file

@ -3,12 +3,14 @@
import copy import copy
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from UM.Signal import Signal, signalemitter from UM.Signal import Signal, signalemitter
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.Validator import ValidatorState
from PyQt5.QtCore import QTimer
from UM.Application import Application from UM.Application import Application
from cura.Settings.PerObjectContainerStack import PerObjectContainerStack from cura.Settings.PerObjectContainerStack import PerObjectContainerStack
@ -38,6 +40,10 @@ class SettingOverrideDecorator(SceneNodeDecorator):
self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId()
self._is_non_printing_mesh = False self._is_non_printing_mesh = False
self._error_check_timer = QTimer()
self._error_check_timer.setInterval(250)
self._error_check_timer.setSingleShot(True)
self._error_check_timer.timeout.connect(self._checkStackForErrors)
self._stack.propertyChanged.connect(self._onSettingChanged) self._stack.propertyChanged.connect(self._onSettingChanged)
@ -97,8 +103,21 @@ class SettingOverrideDecorator(SceneNodeDecorator):
if property_name == "value": if property_name == "value":
self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh()
Application.getInstance().getBackend().needsSlicing() if not self._is_non_printing_mesh:
Application.getInstance().getBackend().tickle() # self._error_check_timer.start()
self._checkStackForErrors()
Application.getInstance().getBackend().needsSlicing()
Application.getInstance().getBackend().tickle()
def _checkStackForErrors(self):
hasErrors = False;
for key in self._stack.getAllKeys():
validation_state = self._stack.getProperty(key, "validationState")
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
Logger.log("w", "Setting Per Object %s is not valid.", key)
hasErrors = True
break
Application.getInstance().getObjectsModel().setStacksHaveErrors(hasErrors)
## Makes sure that the stack upon which the container stack is placed is ## Makes sure that the stack upon which the container stack is placed is
# kept up to date. # kept up to date.

View file

@ -1082,6 +1082,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
CuraApplication.getInstance().getMachineManager().activeQualityChanged.emit() CuraApplication.getInstance().getMachineManager().activeQualityChanged.emit()
# Actually change the active machine. # Actually change the active machine.
#
# This is scheduled for later is because it depends on the Variant/Material/Qualitiy Managers to have the latest
# data, but those managers will only update upon a container/container metadata changed signal. Because this
# function is running on the main thread (Qt thread), although those "changed" signals have been emitted, but
# they won't take effect until this function is done.
# To solve this, we schedule _updateActiveMachine() for later so it will have the latest data.
CuraApplication.getInstance().callLater(self._updateActiveMachine, global_stack) CuraApplication.getInstance().callLater(self._updateActiveMachine, global_stack)
# Load all the nodes / meshdata of the workspace # Load all the nodes / meshdata of the workspace

View file

@ -32,11 +32,11 @@ UM.TooltipArea
if(checked) if(checked)
{ {
addedSettingsModel.setVisible(model.key, checked); addedSettingsModel.setVisible(model.key, checked);
UM.ActiveTool.triggerAction("subscribeForSettingValidation", model.key) UM.ActiveTool.triggerActionWithData("subscribeForSettingValidation", model.key)
} }
else else
{ {
UM.ActiveTool.triggerAction("unsubscribeForSettingValidation", model.key) UM.ActiveTool.triggerActionWithData("unsubscribeForSettingValidation", model.key)
addedSettingsModel.setVisible(model.key, checked); addedSettingsModel.setVisible(model.key, checked);
} }
UM.ActiveTool.forceUpdate(); UM.ActiveTool.forceUpdate();

View file

@ -242,7 +242,7 @@ Item {
onClicked: { onClicked: {
addedSettingsModel.setVisible(model.key, false) addedSettingsModel.setVisible(model.key, false)
UM.ActiveTool.triggerAction("unsubscribeForSettingValidation", model.key) UM.ActiveTool.triggerActionWithData("unsubscribeForSettingValidation", model.key)
} }
style: ButtonStyle style: ButtonStyle

View file

@ -44,7 +44,6 @@ class PerObjectSettingsTool(Tool):
self._error_check_timer.setSingleShot(True) self._error_check_timer.setSingleShot(True)
self._error_check_timer.timeout.connect(self._updateStacksHaveErrors) self._error_check_timer.timeout.connect(self._updateStacksHaveErrors)
def event(self, event): def event(self, event):
super().event(event) super().event(event)
if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): if event.type == Event.MousePressEvent and self._controller.getToolsEnabled():
@ -156,10 +155,12 @@ class PerObjectSettingsTool(Tool):
def _onPropertyChanged(self, key: str, property_name: str) -> None: def _onPropertyChanged(self, key: str, property_name: str) -> None:
if property_name == "validationState": if property_name == "validationState":
self._error_check_timer.start() # self._error_check_timer.start()
return
def _updateStacksHaveErrors(self) -> None: def _updateStacksHaveErrors(self) -> None:
self._checkStacksHaveErrors() return
# self._checkStacksHaveErrors()
def _checkStacksHaveErrors(self): def _checkStacksHaveErrors(self):
@ -180,6 +181,7 @@ class PerObjectSettingsTool(Tool):
def _checkStackForErrors(self, stack): def _checkStackForErrors(self, stack):
print("checking for errors")
if stack is None: if stack is None:
return False return False

View file

@ -48,6 +48,12 @@ class XmlMaterialProfile(InstanceContainer):
## Overridden from InstanceContainer ## Overridden from InstanceContainer
# set the meta data for all machine / variant combinations # set the meta data for all machine / variant combinations
#
# The "apply_to_all" flag indicates whether this piece of metadata should be applied to all material containers
# or just this specific container.
# For example, when you change the material name, you want to apply it to all its derived containers, but for
# some specific settings, they should only be applied to a machine/variant-specific container.
#
def setMetaDataEntry(self, key, value, apply_to_all = True): def setMetaDataEntry(self, key, value, apply_to_all = True):
registry = ContainerRegistry.getInstance() registry = ContainerRegistry.getInstance()
if registry.isReadOnly(self.getId()): if registry.isReadOnly(self.getId()):
@ -59,7 +65,7 @@ class XmlMaterialProfile(InstanceContainer):
return return
# Get the MaterialGroup # Get the MaterialGroup
material_manager = CuraApplication.getInstance()._material_manager material_manager = CuraApplication.getInstance().getMaterialManager()
root_material_id = self.getMetaDataEntry("base_file") #if basefile is self.getId, this is a basefile. root_material_id = self.getMetaDataEntry("base_file") #if basefile is self.getId, this is a basefile.
material_group = material_manager.getMaterialGroup(root_material_id) material_group = material_manager.getMaterialGroup(root_material_id)
@ -606,8 +612,6 @@ class XmlMaterialProfile(InstanceContainer):
if not variant_node: if not variant_node:
continue continue
# TODO: check if build plate variant exists
buildplate_compatibility = machine_compatibility buildplate_compatibility = machine_compatibility
buildplate_recommended = machine_compatibility buildplate_recommended = machine_compatibility
settings = buildplate.iterfind("./um:setting", self.__namespaces) settings = buildplate.iterfind("./um:setting", self.__namespaces)

View file

@ -6,8 +6,7 @@
"visible": true, "visible": true,
"author": "ABAX 3d Technologies", "author": "ABAX 3d Technologies",
"manufacturer": "ABAX 3d Technologies", "manufacturer": "ABAX 3d Technologies",
"file_formats": "text/x-gcode", "file_formats": "text/x-gcode"
"has_machine_quality": true
}, },
"overrides": { "overrides": {
"machine_start_gcode": { "machine_start_gcode": {

View file

@ -50,7 +50,7 @@
"default_value": 60 "default_value": 60
}, },
"speed_travel": { "speed_travel": {
"default_value": 100 "value": "100"
}, },
"retraction_amount": { "retraction_amount": {
"default_value": 3.5 "default_value": 3.5

View file

@ -42,7 +42,7 @@
"default_value": "elliptic" "default_value": "elliptic"
}, },
"machine_gcode_flavor": { "machine_gcode_flavor": {
"default_value": "RepRap" "default_value": "RepRap (RepRap)"
}, },
"machine_start_gcode": { "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\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"

View file

@ -21,10 +21,10 @@
"overrides": { "overrides": {
"machine_name": { "default_value": "FABtotum Personal Fabricator" }, "machine_name": { "default_value": "FABtotum Personal Fabricator" },
"machine_start_gcode": { "machine_start_gcode": {
"default_value": ";Layer height: {layer_height}\n;Walls: {wall_thickness}\n;Fill: {infill_sparse_density}\n;Top\\Bottom Thickness: {top_bottom_thickness}\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nG4 S1 ;1 millisecond pause to buffer the bep bep \nM728 ;FAB bep bep (start the print, go check the oozing and skirt lines adesion) \nG4 S1 ;1 second pause to reach the printer (run fast)\nG92 E0 ;zero the extruded length \nG1 F200 E35 ;slowly extrude 35mm of filament to clean the nozzle and build up extrusion pressure \nG92 E0 ;zero the extruded length again \nG1 F{speed_travel} ;Set travel speed \n;print" "default_value": ";Layer height: {layer_height}\n;Walls: {wall_thickness}\n;Fill: {infill_sparse_density}\n;Top\\Bottom Thickness: {top_bottom_thickness}\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nG4 S1 ;1 millisecond pause to buffer the bep bep \nM300 S2 ;FAB bep bep (start the print, go check the oozing and skirt lines adesion) \nG4 S1 ;1 second pause to reach the printer (run fast)\nG92 E0 ;zero the extruded length \nG1 F200 E35 ;slowly extrude 35mm of filament to clean the nozzle and build up extrusion pressure \nG92 E0 ;zero the extruded length again \n;print"
}, },
"machine_end_gcode": { "machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-3 X+5 Y+5 F5000 ;move Z up a bit and retract filament even more\n;end of the print\nM84 ;steppers off\nG90 ;absolute positioning\nM728 ;FAB bep bep (end print)" "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-3 X+5 Y+5 F5000 ;move Z up a bit and retract filament even more\n;end of the print\nM84 ;steppers off\nG90 ;absolute positioning\nM300 S2 ;FAB bep bep (end print)"
}, },
"gantry_height": { "default_value": 55 }, "gantry_height": { "default_value": 55 },
"machine_width": { "default_value": 214 }, "machine_width": { "default_value": 214 },

View file

@ -20,12 +20,10 @@
"overrides": { "overrides": {
"machine_name": { "default_value": "Ultimaker 2" }, "machine_name": { "default_value": "Ultimaker 2" },
"machine_start_gcode" : { "machine_start_gcode" : {
"default_value": "",
"value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"G21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nG28 Z0 ;move Z to bottom endstops\\nG28 X0 Y0 ;move X/Y to endstops\\nG1 X15 Y0 F4000 ;move X/Y to front of printer\\nG1 Z15.0 F9000 ;move the platform to 15mm\\nG92 E0 ;zero the extruded length\\nG1 F200 E10 ;extrude 10 mm of feed stock\\nG92 E0 ;zero the extruded length again\\nG1 F9000\\n;Put printing message on LCD screen\\nM117 Printing...\"" "value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"G21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nG28 Z0 ;move Z to bottom endstops\\nG28 X0 Y0 ;move X/Y to endstops\\nG1 X15 Y0 F4000 ;move X/Y to front of printer\\nG1 Z15.0 F9000 ;move the platform to 15mm\\nG92 E0 ;zero the extruded length\\nG1 F200 E10 ;extrude 10 mm of feed stock\\nG92 E0 ;zero the extruded length again\\nG1 F9000\\n;Put printing message on LCD screen\\nM117 Printing...\""
}, },
"machine_end_gcode" : { "machine_end_gcode" : {
"default_value": "", "value": "\";Version _2.6 of the firmware can abort the print too early if the file ends\\n;too soon. However if the file hasn't ended yet because there are comments at\\n;the end of the file, it won't abort yet. Therefore we have to put at least 512\\n;bytes at the end of the g-code so that the file is not yet finished by the\\n;time that the motion planner gets flushed. With firmware version _3.3 this\\n;should be fixed, so this comment wouldn't be necessary any more. Now we have\\n;to pad this text to make precisely 512 bytes.\" if machine_gcode_flavor == \"UltiGCode\" else \"M104 S0 ;extruder heater off\\nM140 S0 ;heated bed heater off (if you have it)\\nG91 ;relative positioning\\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning\\n;Version _2.6 of the firmware can abort the print too early if the file ends\\n;too soon. However if the file hasn't ended yet because there are comments at\\n;the end of the file, it won't abort yet. Therefore we have to put at least 512\\n;bytes at the end of the g-code so that the file is not yet finished by the\\n;time that the motion planner gets flushed. With firmware version _3.3 this\\n;should be fixed, so this comment wouldn't be necessary any more. Now we have\\n;to pad this text to make precisely 512 bytes.\""
"value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"M104 S0 ;extruder heater off\\nM140 S0 ;heated bed heater off (if you have it)\\nG91 ;relative positioning\\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning\""
}, },
"machine_width": { "machine_width": {
"default_value": 223 "default_value": 223

View file

@ -123,7 +123,6 @@
"raft_margin": { "value": "10" }, "raft_margin": { "value": "10" },
"raft_surface_layers": { "value": "1" }, "raft_surface_layers": { "value": "1" },
"retraction_amount": { "value": "2" }, "retraction_amount": { "value": "2" },
"retraction_combing": { "default_value": "noskin" },
"retraction_count_max": { "value": "10" }, "retraction_count_max": { "value": "10" },
"retraction_extrusion_window": { "value": "1" }, "retraction_extrusion_window": { "value": "1" },
"retraction_hop": { "value": "2" }, "retraction_hop": { "value": "2" },
@ -154,6 +153,7 @@
"travel_avoid_distance": { "value": "3" }, "travel_avoid_distance": { "value": "3" },
"wall_0_inset": { "value": "0" }, "wall_0_inset": { "value": "0" },
"wall_line_width_x": { "value": "round(wall_line_width * 0.3 / 0.35, 2)" }, "wall_line_width_x": { "value": "round(wall_line_width * 0.3 / 0.35, 2)" },
"wall_thickness": { "value": "1" } "wall_thickness": { "value": "1" },
"zig_zaggify_infill": { "value": "True" }
} }
} }

View file

@ -8,120 +8,71 @@ weight = 2
layer_height layer_height
layer_height_0 layer_height_0
line_width line_width
wall_line_width
wall_line_width_0
wall_line_width_x
skin_line_width
infill_line_width
initial_layer_line_width_factor
[shell] [shell]
wall_extruder_nr wall_extruder_nr
wall_0_extruder_nr
wall_x_extruder_nr
wall_thickness wall_thickness
wall_0_wipe_dist wall_line_count
roofing_extruder_nr
roofing_layer_count
top_bottom_extruder_nr top_bottom_extruder_nr
top_bottom_thickness top_bottom_thickness
top_bottom_pattern top_thickness
top_bottom_pattern_0 top_layers
skin_angles bottom_thickness
wall_0_inset bottom_layers
optimize_wall_printing_order optimize_wall_printing_order
outer_inset_first
alternate_extra_perimeter
travel_compensate_overlapping_walls_enabled
fill_perimeter_gaps fill_perimeter_gaps
filter_out_tiny_gaps
fill_outline_gaps
xy_offset xy_offset
xy_offset_layer_0
z_seam_type
z_seam_x
z_seam_y
z_seam_corner
z_seam_relative
skin_no_small_gaps_heuristic
skin_outline_count
ironing_enabled ironing_enabled
ironing_only_highest_layer
ironing_pattern
ironing_line_spacing
ironing_flow
ironing_inset
speed_ironing
acceleration_ironing
jerk_ironing
[infill] [infill]
infill_extruder_nr infill_extruder_nr
infill_sparse_density infill_sparse_density
infill_line_distance
infill_pattern infill_pattern
zig_zaggify_infill
infill_angles
infill_offset_x
infill_offset_y
sub_div_rad_add
infill_overlap infill_overlap
skin_overlap
infill_wipe_dist
infill_sparse_thickness infill_sparse_thickness
gradual_infill_steps gradual_infill_steps
gradual_infill_step_height
infill_before_walls
min_infill_area
skin_preshrink
expand_skins_expand_distance
max_skin_angle_for_expansion
[material] [material]
default_material_print_temperature
material_print_temperature material_print_temperature
material_print_temperature_layer_0 material_print_temperature_layer_0
material_initial_print_temperature material_initial_print_temperature
material_final_print_temperature material_final_print_temperature
material_extrusion_cool_down_speed
default_material_bed_temperature
material_bed_temperature material_bed_temperature
material_bed_temperature_layer_0 material_bed_temperature_layer_0
material_diameter
material_adhesion_tendency
material_surface_energy
material_flow
retraction_enable retraction_enable
retract_at_layer_change retract_at_layer_change
retraction_amount retraction_amount
retraction_speed retraction_speed
retraction_extra_prime_amount
retraction_min_travel
retraction_count_max
retraction_extrusion_window
material_standby_temperature material_standby_temperature
switch_extruder_retraction_amount
switch_extruder_retraction_speeds
[speed] [speed]
speed_print speed_print
speed_infill
speed_wall
speed_wall_0
speed_wall_x
speed_topbottom
speed_support
speed_prime_tower
speed_travel speed_travel
speed_layer_0 speed_layer_0
skirt_brim_speed skirt_brim_speed
max_feedrate_z_override
speed_slowdown_layers
speed_equalize_flow_enabled
speed_equalize_flow_max
acceleration_enabled acceleration_enabled
acceleration_print
acceleration_travel
acceleration_layer_0
acceleration_skirt_brim
jerk_enabled jerk_enabled
jerk_print
jerk_travel
jerk_layer_0
jerk_skirt_brim
[travel] [travel]
retraction_combing retraction_combing
travel_retract_before_outer_wall
travel_avoid_other_parts travel_avoid_other_parts
travel_avoid_distance travel_avoid_distance
start_layers_at_same_position
layer_start_x
layer_start_y
retraction_hop_enabled retraction_hop_enabled
retraction_hop_only_when_collides retraction_hop_only_when_collides
retraction_hop retraction_hop
@ -130,9 +81,12 @@ retraction_hop_after_extruder_switch
[cooling] [cooling]
cool_fan_enabled cool_fan_enabled
cool_fan_speed cool_fan_speed
cool_fan_speed_min
cool_fan_speed_max
cool_min_layer_time_fan_speed_max cool_min_layer_time_fan_speed_max
cool_fan_speed_0 cool_fan_speed_0
cool_fan_full_at_height cool_fan_full_at_height
cool_fan_full_layer
cool_min_layer_time cool_min_layer_time
cool_min_speed cool_min_speed
cool_lift_head cool_lift_head
@ -140,115 +94,45 @@ cool_lift_head
[support] [support]
support_enable support_enable
support_extruder_nr support_extruder_nr
support_infill_extruder_nr
support_extruder_nr_layer_0
support_interface_extruder_nr
support_type support_type
support_angle support_angle
support_pattern support_pattern
support_connect_zigzags
support_infill_rate support_infill_rate
support_z_distance
support_xy_distance
support_xy_overrides_z
support_xy_distance_overhang
support_bottom_stair_step_height
support_bottom_stair_step_width
support_join_distance
support_offset support_offset
support_infill_sparse_thickness support_infill_sparse_thickness
gradual_support_infill_steps gradual_support_infill_steps
gradual_support_infill_step_height gradual_support_infill_step_height
support_interface_enable support_interface_enable
support_interface_height support_roof_enable
support_interface_skip_height support_bottom_enable
support_interface_density
support_interface_pattern
support_use_towers
support_tower_diameter
support_minimal_diameter
support_tower_roof_angle
support_mesh_drop_down
[platform_adhesion] [platform_adhesion]
prime_blob_enable prime_blob_enable
extruder_prime_pos_x
extruder_prime_pos_y
adhesion_type adhesion_type
adhesion_extruder_nr adhesion_extruder_nr
skirt_line_count skirt_line_count
skirt_gap
skirt_brim_minimal_length
brim_width brim_width
brim_line_count
brim_outside_only brim_outside_only
raft_margin
raft_smoothing
raft_airgap
layer_0_z_overlap
raft_surface_layers
raft_surface_thickness
raft_surface_line_width
raft_surface_line_spacing
raft_interface_thickness
raft_interface_line_width
raft_interface_line_spacing
raft_base_thickness
raft_base_line_width
raft_base_line_spacing
raft_speed
raft_acceleration
raft_jerk
raft_fan_speed
[dual] [dual]
prime_tower_enable prime_tower_enable
prime_tower_size
prime_tower_min_volume
prime_tower_position_x prime_tower_position_x
prime_tower_position_y prime_tower_position_y
prime_tower_flow
prime_tower_wipe_enabled
dual_pre_wipe
prime_tower_purge_volume prime_tower_purge_volume
ooze_shield_enabled
ooze_shield_angle
ooze_shield_dist
[meshfix] [meshfix]
meshfix_union_all
meshfix_union_all_remove_holes
meshfix_extensive_stitching
meshfix_keep_open_polygons
multiple_mesh_overlap
carve_multiple_volumes
alternate_carve_order
remove_empty_first_layers
[blackmagic] [blackmagic]
print_sequence print_sequence
infill_mesh
infill_mesh_order
cutting_mesh
mold_enabled
mold_width
mold_roof_height
mold_angle
support_mesh
anti_overhang_mesh
magic_mesh_surface_mode magic_mesh_surface_mode
magic_spiralize magic_spiralize
smooth_spiralized_contours smooth_spiralized_contours
relative_extrusion
[experimental] [experimental]
infill_enable_travel_optimization conical_overhang_enabled
material_flow_dependent_temperature support_conical_enabled
material_flow_temp_graph adaptive_layer_height_enabled
meshfix_maximum_resolution
roofing_angles
roofing_pattern
slicing_tolerance
support_tree_angle
support_tree_branch_diameter
support_tree_branch_diameter_angle
support_tree_branch_distance
support_tree_collision_resolution
support_tree_enable
support_tree_wall_thickness

View file

@ -9,30 +9,28 @@ layer_height
[shell] [shell]
wall_thickness wall_thickness
wall_line_count
top_bottom_thickness top_bottom_thickness
z_seam_x top_thickness
z_seam_y top_layers
bottom_thickness
bottom_layers
xy_offset
[infill] [infill]
infill_sparse_density infill_sparse_density
gradual_infill_steps infill_pattern
[material] [material]
material_print_temperature material_print_temperature
material_bed_temperature material_bed_temperature
material_diameter
material_flow
retraction_enable retraction_enable
[speed] [speed]
speed_print speed_print
speed_travel
acceleration_print
acceleration_travel
jerk_print
jerk_travel
[travel] [travel]
retraction_hop_enabled
[cooling] [cooling]
cool_fan_enabled cool_fan_enabled
@ -41,26 +39,20 @@ cool_fan_enabled
support_enable support_enable
support_extruder_nr support_extruder_nr
support_type support_type
support_angle
[platform_adhesion] [platform_adhesion]
prime_blob_enable
adhesion_type adhesion_type
adhesion_extruder_nr adhesion_extruder_nr
brim_width
raft_airgap
layer_0_z_overlap
raft_surface_layers
[dual] [dual]
prime_tower_enable prime_tower_enable
prime_tower_size
prime_tower_position_x prime_tower_position_x
prime_tower_position_y prime_tower_position_y
[meshfix] [meshfix]
[blackmagic] [blackmagic]
print_sequence
infill_mesh
cutting_mesh
[experimental] [experimental]

View file

@ -8,15 +8,33 @@ weight = 3
layer_height layer_height
layer_height_0 layer_height_0
line_width line_width
wall_line_width
wall_line_width_0
wall_line_width_x
skin_line_width
infill_line_width
skirt_brim_line_width
support_line_width
support_interface_line_width
support_roof_line_width
support_bottom_line_width
prime_tower_line_width
initial_layer_line_width_factor
[shell] [shell]
wall_extruder_nr wall_extruder_nr
wall_0_extruder_nr
wall_x_extruder_nr
wall_thickness wall_thickness
wall_line_count
wall_0_wipe_dist wall_0_wipe_dist
roofing_extruder_nr
roofing_layer_count roofing_layer_count
top_bottom_extruder_nr top_bottom_extruder_nr
top_bottom_thickness top_bottom_thickness
top_thickness
top_layers
bottom_thickness
bottom_layers
top_bottom_pattern top_bottom_pattern
top_bottom_pattern_0 top_bottom_pattern_0
skin_angles skin_angles
@ -25,6 +43,8 @@ optimize_wall_printing_order
outer_inset_first outer_inset_first
alternate_extra_perimeter alternate_extra_perimeter
travel_compensate_overlapping_walls_enabled travel_compensate_overlapping_walls_enabled
travel_compensate_overlapping_walls_0_enabled
travel_compensate_overlapping_walls_x_enabled
fill_perimeter_gaps fill_perimeter_gaps
filter_out_tiny_gaps filter_out_tiny_gaps
fill_outline_gaps fill_outline_gaps
@ -50,6 +70,7 @@ jerk_ironing
[infill] [infill]
infill_extruder_nr infill_extruder_nr
infill_sparse_density infill_sparse_density
infill_line_distance
infill_pattern infill_pattern
zig_zaggify_infill zig_zaggify_infill
infill_angles infill_angles
@ -57,7 +78,9 @@ infill_offset_x
infill_offset_y infill_offset_y
sub_div_rad_add sub_div_rad_add
infill_overlap infill_overlap
infill_overlap_mm
skin_overlap skin_overlap
skin_overlap_mm
infill_wipe_dist infill_wipe_dist
infill_sparse_thickness infill_sparse_thickness
gradual_infill_steps gradual_infill_steps
@ -65,8 +88,13 @@ gradual_infill_step_height
infill_before_walls infill_before_walls
min_infill_area min_infill_area
skin_preshrink skin_preshrink
top_skin_preshrink
bottom_skin_preshrink
expand_skins_expand_distance expand_skins_expand_distance
top_skin_expand_distance
bottom_skin_expand_distance
max_skin_angle_for_expansion max_skin_angle_for_expansion
min_skin_width_for_expansion
[material] [material]
default_material_print_temperature default_material_print_temperature
@ -75,17 +103,19 @@ material_print_temperature_layer_0
material_initial_print_temperature material_initial_print_temperature
material_final_print_temperature material_final_print_temperature
material_extrusion_cool_down_speed material_extrusion_cool_down_speed
default_material_bed_temperature
material_bed_temperature material_bed_temperature
material_bed_temperature_layer_0 material_bed_temperature_layer_0
material_diameter material_diameter
material_adhesion_tendency material_adhesion_tendency
material_surface_energy material_surface_energy
material_flow material_flow
material_flow_layer_0
retraction_enable retraction_enable
retract_at_layer_change retract_at_layer_change
retraction_amount retraction_amount
retraction_speed retraction_speed
retraction_retract_speed
retraction_prime_speed
retraction_extra_prime_amount retraction_extra_prime_amount
retraction_min_travel retraction_min_travel
retraction_count_max retraction_count_max
@ -93,11 +123,25 @@ retraction_extrusion_window
material_standby_temperature material_standby_temperature
switch_extruder_retraction_amount switch_extruder_retraction_amount
switch_extruder_retraction_speeds switch_extruder_retraction_speeds
switch_extruder_retraction_speed
switch_extruder_prime_speed
[speed] [speed]
speed_print speed_print
speed_infill
speed_wall
speed_wall_0
speed_wall_x
speed_roofing
speed_topbottom
speed_support
speed_support_infill
speed_support_interface
speed_prime_tower
speed_travel speed_travel
speed_layer_0 speed_layer_0
speed_print_layer_0
speed_travel_layer_0
skirt_brim_speed skirt_brim_speed
max_feedrate_z_override max_feedrate_z_override
speed_slowdown_layers speed_slowdown_layers
@ -105,13 +149,37 @@ speed_equalize_flow_enabled
speed_equalize_flow_max speed_equalize_flow_max
acceleration_enabled acceleration_enabled
acceleration_print acceleration_print
acceleration_infill
acceleration_wall
acceleration_wall_0
acceleration_wall_x
acceleration_roofing
acceleration_topbottom
acceleration_support
acceleration_support_infill
acceleration_support_interface
acceleration_prime_tower
acceleration_travel acceleration_travel
acceleration_layer_0 acceleration_layer_0
acceleration_print_layer_0
acceleration_travel_layer_0
acceleration_skirt_brim acceleration_skirt_brim
jerk_enabled jerk_enabled
jerk_print jerk_print
jerk_infill
jerk_wall
jerk_wall_0
jerk_wall_x
jerk_roofing
jerk_topbottom
jerk_support
jerk_support_infill
jerk_support_interface
jerk_prime_tower
jerk_travel jerk_travel
jerk_layer_0 jerk_layer_0
jerk_print_layer_0
jerk_travel_layer_0
jerk_skirt_brim jerk_skirt_brim
[travel] [travel]
@ -130,9 +198,12 @@ retraction_hop_after_extruder_switch
[cooling] [cooling]
cool_fan_enabled cool_fan_enabled
cool_fan_speed cool_fan_speed
cool_fan_speed_min
cool_fan_speed_max
cool_min_layer_time_fan_speed_max cool_min_layer_time_fan_speed_max
cool_fan_speed_0 cool_fan_speed_0
cool_fan_full_at_height cool_fan_full_at_height
cool_fan_full_layer
cool_min_layer_time cool_min_layer_time
cool_min_speed cool_min_speed
cool_lift_head cool_lift_head
@ -140,12 +211,21 @@ cool_lift_head
[support] [support]
support_enable support_enable
support_extruder_nr support_extruder_nr
support_infill_extruder_nr
support_extruder_nr_layer_0
support_interface_extruder_nr
support_roof_extruder_nr
support_bottom_extruder_nr
support_type support_type
support_angle support_angle
support_pattern support_pattern
zig_zaggify_support
support_connect_zigzags support_connect_zigzags
support_infill_rate support_infill_rate
support_line_distance
support_z_distance support_z_distance
support_top_distance
support_bottom_distance
support_xy_distance support_xy_distance
support_xy_overrides_z support_xy_overrides_z
support_xy_distance_overhang support_xy_distance_overhang
@ -157,9 +237,15 @@ support_infill_sparse_thickness
gradual_support_infill_steps gradual_support_infill_steps
gradual_support_infill_step_height gradual_support_infill_step_height
support_interface_enable support_interface_enable
support_roof_enable
support_bottom_enable
support_interface_height support_interface_height
support_roof_height
support_bottom_height
support_interface_skip_height support_interface_skip_height
support_interface_density support_interface_density
support_roof_density
support_bottom_density
support_interface_pattern support_interface_pattern
support_use_towers support_use_towers
support_tower_diameter support_tower_diameter
@ -169,19 +255,17 @@ support_mesh_drop_down
[platform_adhesion] [platform_adhesion]
prime_blob_enable prime_blob_enable
extruder_prime_pos_x
extruder_prime_pos_y
adhesion_type adhesion_type
adhesion_extruder_nr adhesion_extruder_nr
skirt_line_count skirt_line_count
skirt_gap skirt_gap
skirt_brim_minimal_length skirt_brim_minimal_length
brim_width brim_width
brim_line_count
brim_outside_only brim_outside_only
raft_margin raft_margin
raft_smoothing raft_smoothing
raft_airgap raft_airgap
layer_0_z_overlap
raft_surface_layers raft_surface_layers
raft_surface_thickness raft_surface_thickness
raft_surface_line_width raft_surface_line_width
@ -199,8 +283,10 @@ raft_fan_speed
[dual] [dual]
prime_tower_enable prime_tower_enable
prime_tower_circular
prime_tower_size prime_tower_size
prime_tower_min_volume prime_tower_min_volume
prime_tower_wall_thickness
prime_tower_position_x prime_tower_position_x
prime_tower_position_y prime_tower_position_y
prime_tower_flow prime_tower_flow
@ -238,8 +324,25 @@ smooth_spiralized_contours
relative_extrusion relative_extrusion
[experimental] [experimental]
support_tree_enable
support_tree_angle
support_tree_branch_distance
support_tree_branch_diameter
support_tree_branch_diameter_angle
support_tree_collision_resolution
support_tree_wall_thickness
support_tree_wall_count
slicing_tolerance
roofing_line_width
roofing_pattern
roofing_angles
infill_enable_travel_optimization
material_flow_dependent_temperature
material_flow_temp_graph
meshfix_maximum_resolution
support_skip_some_zags support_skip_some_zags
support_skip_zag_per_mm support_skip_zag_per_mm
support_zag_skip_count
draft_shield_enabled draft_shield_enabled
draft_shield_dist draft_shield_dist
draft_shield_height_limitation draft_shield_height_limitation
@ -267,19 +370,34 @@ infill_hollow
magic_fuzzy_skin_enabled magic_fuzzy_skin_enabled
magic_fuzzy_skin_thickness magic_fuzzy_skin_thickness
magic_fuzzy_skin_point_density magic_fuzzy_skin_point_density
magic_fuzzy_skin_point_dist
flow_rate_max_extrusion_offset flow_rate_max_extrusion_offset
flow_rate_extrusion_offset_factor flow_rate_extrusion_offset_factor
infill_enable_travel_optimization wireframe_enabled
material_flow_dependent_temperature wireframe_height
material_flow_temp_graph wireframe_roof_inset
meshfix_maximum_resolution wireframe_printspeed
roofing_angles wireframe_printspeed_bottom
roofing_pattern wireframe_printspeed_up
slicing_tolerance wireframe_printspeed_down
support_tree_angle wireframe_printspeed_flat
support_tree_branch_diameter wireframe_flow
support_tree_branch_diameter_angle wireframe_flow_connection
support_tree_branch_distance wireframe_flow_flat
support_tree_collision_resolution wireframe_top_delay
support_tree_enable wireframe_bottom_delay
support_tree_wall_thickness wireframe_flat_delay
wireframe_up_half_speed
wireframe_top_jump
wireframe_fall_down
wireframe_drag_along
wireframe_strategy
wireframe_straight_before_down
wireframe_roof_fall_down
wireframe_roof_drag_along
wireframe_roof_outer_delay
wireframe_nozzle_clearance
adaptive_layer_height_enabled
adaptive_layer_height_variation
adaptive_layer_height_variation_step
adaptive_layer_height_threshold

View file

@ -236,6 +236,16 @@ Item
onTriggered: CuraActions.deleteSelection(); onTriggered: CuraActions.deleteSelection();
} }
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)
enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection
iconName: "edit-delete"
shortcut: StandardKey.Backspace
onTriggered: CuraActions.deleteSelection()
}
Action Action
{ {
id: centerSelectionAction; id: centerSelectionAction;

View file

@ -490,6 +490,14 @@ UM.MainWindow
collapseSidebarAnimation.start(); collapseSidebarAnimation.start();
} }
} }
MouseArea
{
visible: UM.Controller.activeStage.sidebarComponent != ""
anchors.fill: parent
acceptedButtons: Qt.AllButtons
onWheel: wheel.accepted = true
}
} }
UM.MessageStack UM.MessageStack

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
@ -12,7 +12,7 @@ Menu
id: menu id: menu
title: "Build plate" title: "Build plate"
property Cura.BuildPlateModel buildPlateModel: CuraApplication.getBuildPlateModel() property var buildPlateModel: CuraApplication.getBuildPlateModel()
Instantiator Instantiator
{ {

View file

@ -15,7 +15,7 @@ Menu
property bool shouldShowExtruders: machineExtruderCount.properties.value > 1; property bool shouldShowExtruders: machineExtruderCount.properties.value > 1;
property Cura.MultiBuildPlateModel multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel() property var multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel()
// Selection-related actions. // Selection-related actions.
MenuItem { action: Cura.Actions.centerSelection; } MenuItem { action: Cura.Actions.centerSelection; }

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
@ -13,11 +13,11 @@ Menu
Instantiator Instantiator
{ {
model: Cura.QualityProfilesModel model: Cura.QualityProfilesDropDownMenuModel
MenuItem MenuItem
{ {
text: (model.layer_height != "") ? model.name + " - " + model.layer_height : model.name text: (model.layer_height != "") ? model.name + " - " + model.layer_height + model.layer_height_unit : model.name
checkable: true checkable: true
checked: Cura.MachineManager.activeQualityOrQualityChangesName == model.name checked: Cura.MachineManager.activeQualityOrQualityChangesName == model.name
exclusiveGroup: group exclusiveGroup: group
@ -34,18 +34,18 @@ Menu
MenuSeparator MenuSeparator
{ {
id: customSeparator id: customSeparator
visible: Cura.CustomQualityProfilesModel.rowCount > 0 visible: Cura.CustomQualityProfilesDropDownMenuModel.rowCount > 0
} }
Instantiator Instantiator
{ {
id: customProfileInstantiator id: customProfileInstantiator
model: Cura.CustomQualityProfilesModel model: Cura.CustomQualityProfilesDropDownMenuModel
Connections Connections
{ {
target: Cura.CustomQualityProfilesModel target: Cura.CustomQualityProfilesDropDownMenuModel
onModelReset: customSeparator.visible = Cura.CustomQualityProfilesModel.rowCount() > 0 onModelReset: customSeparator.visible = Cura.CustomQualityProfilesDropDownMenuModel.rowCount() > 0
} }
MenuItem MenuItem

View file

@ -13,7 +13,7 @@ Menu
id: base id: base
enabled: !PrintInformation.preSliced enabled: !PrintInformation.preSliced
property Cura.MultiBuildPlateModel multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel() property var multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel()
// main views // main views
Instantiator Instantiator

View file

@ -31,9 +31,9 @@ Rectangle
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining") border.color: UM.Theme.getColor("lining")
property bool collapsed: true; property bool collapsed: true
property Cura.MultiBuildPlateModel multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel() property var multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel()
SystemPalette { id: palette } SystemPalette { id: palette }

View file

@ -1,7 +1,7 @@
// Copyright (c) 2016 Ultimaker B.V. // Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Window 2.1 import QtQuick.Window 2.1

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
@ -12,6 +12,8 @@ TabView
{ {
id: base id: base
property QtObject materialManager: CuraApplication.getMaterialManager()
property QtObject properties property QtObject properties
property var currentMaterialNode: null property var currentMaterialNode: null
@ -214,7 +216,8 @@ TabView
confirmDiameterChangeDialog.old_approximate_diameter_value = old_approximate_diameter; confirmDiameterChangeDialog.old_approximate_diameter_value = old_approximate_diameter;
confirmDiameterChangeDialog.open() confirmDiameterChangeDialog.open()
} else { }
else {
Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", value); Cura.ContainerManager.setContainerProperty(base.containerId, "material_diameter", "value", value);
base.setMetaDataEntry("approximate_diameter", old_approximate_diameter, getApproximateDiameter(value).toString()); base.setMetaDataEntry("approximate_diameter", old_approximate_diameter, getApproximateDiameter(value).toString());
base.setMetaDataEntry("properties/diameter", properties.diameter, value); base.setMetaDataEntry("properties/diameter", properties.diameter, value);
@ -396,13 +399,15 @@ TabView
onEditingFinished: materialPropertyProvider.setPropertyValue("value", value) onEditingFinished: materialPropertyProvider.setPropertyValue("value", value)
} }
UM.ContainerPropertyProvider { UM.ContainerPropertyProvider
{
id: materialPropertyProvider id: materialPropertyProvider
containerId: base.containerId containerId: base.containerId
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
key: model.key key: model.key
} }
UM.ContainerPropertyProvider { UM.ContainerPropertyProvider
{
id: machinePropertyProvider id: machinePropertyProvider
containerId: Cura.MachineManager.activeDefinitionId containerId: Cura.MachineManager.activeDefinitionId
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
@ -497,7 +502,7 @@ TabView
} }
// update the values // update the values
Cura.ContainerManager.setMaterialName(base.currentMaterialNode, new_name) base.materialManager.setMaterialName(base.currentMaterialNode, new_name)
materialProperties.name = new_name materialProperties.name = new_name
} }

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Uranium is released under the terms of the LGPLv3 or higher. // Uranium is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
@ -13,6 +13,8 @@ import Cura 1.0 as Cura
Item Item
{ {
id: base id: base
property QtObject materialManager: CuraApplication.getMaterialManager()
property var resetEnabled: false // Keep PreferencesDialog happy property var resetEnabled: false // Keep PreferencesDialog happy
UM.I18nCatalog { id: catalog; name: "cura"; } UM.I18nCatalog { id: catalog; name: "cura"; }
@ -37,12 +39,14 @@ Item
property var hasCurrentItem: materialListView.currentItem != null property var hasCurrentItem: materialListView.currentItem != null
property var currentItem: { // is soon to be overwritten property var currentItem:
{ // is soon to be overwritten
var current_index = materialListView.currentIndex; var current_index = materialListView.currentIndex;
return materialsModel.getItem(current_index); return materialsModel.getItem(current_index);
} }
property var isCurrentItemActivated: { property var isCurrentItemActivated:
{
const extruder_position = Cura.ExtruderManager.activeExtruderIndex; const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position]; const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position];
return base.currentItem.root_material_id == root_material_id; return base.currentItem.root_material_id == root_material_id;
@ -51,7 +55,8 @@ Item
Row // Button Row Row // Button Row
{ {
id: buttonRow id: buttonRow
anchors { anchors
{
left: parent.left left: parent.left
right: parent.right right: parent.right
top: titleLabel.bottom top: titleLabel.bottom
@ -59,11 +64,13 @@ Item
height: childrenRect.height height: childrenRect.height
// Activate button // Activate button
Button { Button
{
text: catalog.i18nc("@action:button", "Activate") text: catalog.i18nc("@action:button", "Activate")
iconName: "list-activate" iconName: "list-activate"
enabled: !isCurrentItemActivated enabled: !isCurrentItemActivated
onClicked: { onClicked:
{
forceActiveFocus() forceActiveFocus()
const extruder_position = Cura.ExtruderManager.activeExtruderIndex; const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
@ -72,44 +79,52 @@ Item
} }
// Create button // Create button
Button { Button
{
text: catalog.i18nc("@action:button", "Create") text: catalog.i18nc("@action:button", "Create")
iconName: "list-add" iconName: "list-add"
onClicked: { onClicked:
{
forceActiveFocus(); forceActiveFocus();
base.newRootMaterialIdToSwitchTo = Cura.ContainerManager.createMaterial(); base.newRootMaterialIdToSwitchTo = base.materialManager.createMaterial();
base.toActivateNewMaterial = true; base.toActivateNewMaterial = true;
} }
} }
// Duplicate button // Duplicate button
Button { Button
{
text: catalog.i18nc("@action:button", "Duplicate"); text: catalog.i18nc("@action:button", "Duplicate");
iconName: "list-add" iconName: "list-add"
enabled: base.hasCurrentItem enabled: base.hasCurrentItem
onClicked: { onClicked:
{
forceActiveFocus(); forceActiveFocus();
base.newRootMaterialIdToSwitchTo = Cura.ContainerManager.duplicateMaterial(base.currentItem.container_node); base.newRootMaterialIdToSwitchTo = base.materialManager.duplicateMaterial(base.currentItem.container_node);
base.toActivateNewMaterial = true; base.toActivateNewMaterial = true;
} }
} }
// Remove button // Remove button
Button { Button
{
text: catalog.i18nc("@action:button", "Remove") text: catalog.i18nc("@action:button", "Remove")
iconName: "list-remove" iconName: "list-remove"
enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated enabled: base.hasCurrentItem && !base.currentItem.is_read_only && !base.isCurrentItemActivated
onClicked: { onClicked:
{
forceActiveFocus(); forceActiveFocus();
confirmRemoveMaterialDialog.open(); confirmRemoveMaterialDialog.open();
} }
} }
// Import button // Import button
Button { Button
{
text: catalog.i18nc("@action:button", "Import") text: catalog.i18nc("@action:button", "Import")
iconName: "document-import" iconName: "document-import"
onClicked: { onClicked:
{
forceActiveFocus(); forceActiveFocus();
importMaterialDialog.open(); importMaterialDialog.open();
} }
@ -117,10 +132,12 @@ Item
} }
// Export button // Export button
Button { Button
{
text: catalog.i18nc("@action:button", "Export") text: catalog.i18nc("@action:button", "Export")
iconName: "document-export" iconName: "document-export"
onClicked: { onClicked:
{
forceActiveFocus(); forceActiveFocus();
exportMaterialDialog.open(); exportMaterialDialog.open();
} }
@ -181,7 +198,7 @@ Item
onYes: onYes:
{ {
Cura.ContainerManager.removeMaterial(base.currentItem.container_node); base.materialManager.removeMaterial(base.currentItem.container_node);
} }
} }
@ -281,7 +298,6 @@ Item
} }
visible: text != "" visible: text != ""
text: { text: {
// OLD STUFF
var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName; var caption = catalog.i18nc("@action:label", "Printer") + ": " + Cura.MachineManager.activeMachineName;
if (Cura.MachineManager.hasVariants) if (Cura.MachineManager.hasVariants)
{ {
@ -343,10 +359,19 @@ Item
Row Row
{ {
id: materialRow
spacing: (UM.Theme.getSize("default_margin").width / 2) | 0 spacing: (UM.Theme.getSize("default_margin").width / 2) | 0
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right anchors.right: parent.right
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 Rectangle
{ {
width: Math.floor(parent.height * 0.8) width: Math.floor(parent.height * 0.8)
@ -360,22 +385,14 @@ Item
width: Math.floor((parent.width * 0.3)) width: Math.floor((parent.width * 0.3))
text: model.material text: model.material
elide: Text.ElideRight elide: Text.ElideRight
font.italic: { // TODO: make it easier font.italic: materialRow.isItemActivated
const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position];
return model.root_material_id == root_material_id
}
color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text; color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text;
} }
Label Label
{ {
text: (model.name != model.material) ? model.name : "" text: (model.name != model.material) ? model.name : ""
elide: Text.ElideRight elide: Text.ElideRight
font.italic: { // TODO: make it easier font.italic: materialRow.isItemActivated
const extruder_position = Cura.ExtruderManager.activeExtruderIndex;
const root_material_id = Cura.MachineManager.currentRootMaterialId[extruder_position];
return model.root_material_id == root_material_id;
}
color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text; color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text;
} }
} }

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
@ -85,7 +85,7 @@ Tab
model: Cura.QualitySettingsModel model: Cura.QualitySettingsModel
{ {
id: qualitySettings id: qualitySettings
extruderPosition: base.extruderPosition selectedPosition: base.extruderPosition
selectedQualityItem: base.qualityItem selectedQualityItem: base.qualityItem
} }

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Uranium is released under the terms of the LGPLv3 or higher. // Uranium is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
@ -13,6 +13,8 @@ import Cura 1.0 as Cura
Item Item
{ {
id: base id: base
property QtObject qualityManager: CuraApplication.getQualityManager()
property var resetEnabled: false // Keep PreferencesDialog happy property var resetEnabled: false // Keep PreferencesDialog happy
property var extrudersModel: Cura.ExtrudersModel {} property var extrudersModel: Cura.ExtrudersModel {}
@ -173,7 +175,7 @@ Item
{ {
base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created
base.toActivateNewQuality = true; base.toActivateNewQuality = true;
Cura.ContainerManager.createQualityChanges(newName); base.qualityManager.createQualityChanges(newName);
} }
} }
@ -222,7 +224,7 @@ Item
object: "<new name>" object: "<new name>"
onAccepted: onAccepted:
{ {
Cura.ContainerManager.duplicateQualityChanges(newName, base.currentItem); base.qualityManager.duplicateQualityChanges(newName, base.currentItem);
} }
} }
@ -239,9 +241,9 @@ Item
onYes: onYes:
{ {
Cura.ContainerManager.removeQualityChangesGroup(base.currentItem.quality_changes_group); base.qualityManager.removeQualityChangesGroup(base.currentItem.quality_changes_group);
// reset current item to the first if available // reset current item to the first if available
qualityListView.currentIndex = -1; // TODO: Reset selection. qualityListView.currentIndex = -1; // Reset selection.
} }
} }
@ -253,7 +255,7 @@ Item
object: "<new name>" object: "<new name>"
onAccepted: onAccepted:
{ {
var actualNewName = Cura.ContainerManager.renameQualityChangesGroup(base.currentItem.quality_changes_group, newName); var actualNewName = base.qualityManager.renameQualityChangesGroup(base.currentItem.quality_changes_group, newName);
base.newQualityNameToSelect = actualNewName; // Select the new name after the model gets updated base.newQualityNameToSelect = actualNewName; // Select the new name after the model gets updated
} }
} }
@ -264,7 +266,7 @@ Item
id: importDialog id: importDialog
title: catalog.i18nc("@title:window", "Import Profile") title: catalog.i18nc("@title:window", "Import Profile")
selectExisting: true selectExisting: true
nameFilters: qualitiesModel.getFileNameFilters("profile_reader") // TODO: make this easier nameFilters: qualitiesModel.getFileNameFilters("profile_reader")
folder: CuraApplication.getDefaultPath("dialog_profile_path") folder: CuraApplication.getDefaultPath("dialog_profile_path")
onAccepted: onAccepted:
{ {
@ -290,11 +292,10 @@ Item
id: exportDialog id: exportDialog
title: catalog.i18nc("@title:window", "Export Profile") title: catalog.i18nc("@title:window", "Export Profile")
selectExisting: false selectExisting: false
nameFilters: qualitiesModel.getFileNameFilters("profile_writer") // TODO: make this easier nameFilters: qualitiesModel.getFileNameFilters("profile_writer")
folder: CuraApplication.getDefaultPath("dialog_profile_path") folder: CuraApplication.getDefaultPath("dialog_profile_path")
onAccepted: onAccepted:
{ {
// TODO: make this easier
var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group, var result = Cura.ContainerManager.exportQualityChangesGroup(base.currentItem.quality_changes_group,
fileUrl, selectedNameFilter); fileUrl, selectedNameFilter);

View file

@ -142,7 +142,7 @@ Item
TextField TextField
{ {
id: filter; id: filter;
height: parent.height
anchors.left: parent.left anchors.left: parent.left
anchors.right: clearFilterButton.left anchors.right: clearFilterButton.left
anchors.rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width) anchors.rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width)

View file

@ -515,15 +515,12 @@ Rectangle
weights = ["0"]; weights = ["0"];
costs = ["0.00"]; costs = ["0.00"];
} }
var result = lengths.join(" + ") + "m / ~ " + weights.join(" + ") + "g";
if(someCostsKnown) if(someCostsKnown)
{ {
return catalog.i18nc("@label Print estimates: m for meters, g for grams, %4 is currency and %3 is print cost", "%1m / ~ %2g / ~ %4 %3").arg(lengths.join(" + ")) result += " / ~ " + costs.join(" + ") + " " + UM.Preferences.getValue("cura/currency");
.arg(weights.join(" + ")).arg(costs.join(" + ")).arg(UM.Preferences.getValue("cura/currency"));
}
else
{
return catalog.i18nc("@label Print estimates: m for meters, g for grams", "%1m / ~ %2g").arg(lengths.join(" + ")).arg(weights.join(" + "));
} }
return result;
} }
MouseArea MouseArea
{ {

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import "Settings" import "Settings"

View file

@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.8 import QtQuick 2.7
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
@ -58,7 +58,7 @@ Item
running: false running: false
repeat: false repeat: false
onTriggered: { onTriggered: {
var item = Cura.QualityProfilesModel.getItem(qualitySlider.value); var item = Cura.QualityProfilesDropDownMenuModel.getItem(qualitySlider.value);
Cura.MachineManager.activeQualityGroup = item.quality_group; Cura.MachineManager.activeQualityGroup = item.quality_group;
} }
} }
@ -103,8 +103,8 @@ Item
var availableMin = -1 var availableMin = -1
var availableMax = -1 var availableMax = -1
for (var i = 0; i < Cura.QualityProfilesModel.rowCount(); i++) { for (var i = 0; i < Cura.QualityProfilesDropDownMenuModel.rowCount(); i++) {
var qualityItem = Cura.QualityProfilesModel.getItem(i) var qualityItem = Cura.QualityProfilesDropDownMenuModel.getItem(i)
// Add each quality item to the UI quality model // Add each quality item to the UI quality model
qualityModel.append(qualityItem) qualityModel.append(qualityItem)
@ -166,7 +166,7 @@ Item
qualityModel.existingQualityProfile = 0 qualityModel.existingQualityProfile = 0
// check, the ticks count cannot be less than zero // check, the ticks count cannot be less than zero
qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesModel.rowCount() - 1) qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesDropDownMenuModel.rowCount() - 1)
} }
} }
@ -192,13 +192,13 @@ Item
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 2) anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 2)
color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesDropDownMenuModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
text: text:
{ {
var result = "" var result = ""
if(Cura.MachineManager.activeMachine != null) if(Cura.MachineManager.activeMachine != null)
{ {
result = Cura.QualityProfilesModel.getItem(index).layer_height_without_unit result = Cura.QualityProfilesDropDownMenuModel.getItem(index).layer_height
if(result == undefined) if(result == undefined)
{ {
@ -263,7 +263,7 @@ Item
Rectangle Rectangle
{ {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: Cura.QualityProfilesModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") color: Cura.QualityProfilesDropDownMenuModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
width: 1 * screenScaleFactor width: 1 * screenScaleFactor
height: 6 * screenScaleFactor height: 6 * screenScaleFactor
y: 0 y: 0
@ -401,9 +401,9 @@ Item
// if the current profile is user-created, switch to a built-in quality // if the current profile is user-created, switch to a built-in quality
if (Cura.SimpleModeSettingsManager.isProfileUserCreated) if (Cura.SimpleModeSettingsManager.isProfileUserCreated)
{ {
if (Cura.QualityProfilesModel.rowCount() > 0) if (Cura.QualityProfilesDropDownMenuModel.rowCount() > 0)
{ {
var item = Cura.QualityProfilesModel.getItem(0); var item = Cura.QualityProfilesDropDownMenuModel.getItem(0);
Cura.MachineManager.activeQualityGroup = item.quality_group; Cura.MachineManager.activeQualityGroup = item.quality_group;
} }
} }

View file

@ -1,14 +0,0 @@
[general]
version = 2
name = Fast
definition = abax_pri3
[metadata]
setting_version = 4
type = quality
quality_type = fast
weight = -1
global_quality = True
[values]
layer_height = 0.2

View file

@ -1,14 +0,0 @@
[general]
version = 2
name = Extra Fine
definition = abax_pri3
[metadata]
setting_version = 4
type = quality
quality_type = high
weight = 1
global_quality = True
[values]
layer_height = 0.1

View file

@ -1,14 +0,0 @@
[general]
version = 2
name = Fine
definition = abax_pri3
[metadata]
setting_version = 4
type = quality
quality_type = normal
weight = 0
global_quality = True
[values]
layer_height = 0.2

View file

@ -1,16 +1,17 @@
[general] [general]
version = 2 version = 2
name = Fast name = Fine
definition = abax_pri3 definition = abax_pri3
[metadata] [metadata]
setting_version = 4 setting_version = 4
type = quality type = quality
quality_type = fast quality_type = normal
weight = -1 weight = -1
material = generic_pla material = generic_pla
[values] [values]
layer_height = 0.2
wall_thickness = 1.05 wall_thickness = 1.05
top_bottom_thickness = 0.8 top_bottom_thickness = 0.8
infill_sparse_density = 20 infill_sparse_density = 20

View file

@ -11,6 +11,7 @@ weight = 1
material = generic_pla material = generic_pla
[values] [values]
layer_height = 0.1
wall_thickness = 1.05 wall_thickness = 1.05
top_bottom_thickness = 0.8 top_bottom_thickness = 0.8
infill_sparse_density = 20 infill_sparse_density = 20

View file

@ -11,6 +11,7 @@ weight = 0
material = generic_pla material = generic_pla
[values] [values]
layer_height = 0.2
wall_thickness = 1.05 wall_thickness = 1.05
top_bottom_thickness = 0.8 top_bottom_thickness = 0.8
infill_sparse_density = 20 infill_sparse_density = 20

View file

@ -12,9 +12,10 @@ material = fabtotum_abs
[values] [values]
adhesion_type = raft adhesion_type = raft
speed_print = 80
layer_height = 0.2 layer_height = 0.2
layer_height_0 = 0.2 layer_height_0 = 0.2
cool_fan_enabled = True cool_fan_enabled = False
cool_fan_full_at_height = 0.4 cool_fan_full_at_height = 0.4
cool_fan_speed = 50 cool_fan_speed = 50
cool_fan_speed_max = 50 cool_fan_speed_max = 50

View file

@ -12,9 +12,10 @@ material = fabtotum_abs
[values] [values]
adhesion_type = raft adhesion_type = raft
speed_print = 45
layer_height = 0.1 layer_height = 0.1
layer_height_0 = 0.1 layer_height_0 = 0.1
cool_fan_enabled = True cool_fan_enabled = False
cool_fan_full_at_height = 0.2 cool_fan_full_at_height = 0.2
cool_fan_speed = 50 cool_fan_speed = 50
cool_fan_speed_max = 50 cool_fan_speed_max = 50

View file

@ -12,9 +12,10 @@ material = fabtotum_abs
[values] [values]
adhesion_type = raft adhesion_type = raft
speed_print = 60
layer_height = 0.15 layer_height = 0.15
layer_height_0 = 0.15 layer_height_0 = 0.15
cool_fan_enabled = True cool_fan_enabled = False
cool_fan_full_at_height = 0.3 cool_fan_full_at_height = 0.3
cool_fan_speed = 50 cool_fan_speed = 50
cool_fan_speed_max = 50 cool_fan_speed_max = 50

View file

@ -44,7 +44,7 @@ skirt_gap = 1.5
skirt_line_count = 5 skirt_line_count = 5
speed_infill = =speed_print speed_infill = =speed_print
speed_layer_0 = 25 speed_layer_0 = 25
speed_print = 50 speed_print = 30
speed_topbottom = 40 speed_topbottom = 40
speed_travel = 200 speed_travel = 200
speed_wall_0 = 40 speed_wall_0 = 40

View file

@ -44,7 +44,7 @@ skirt_gap = 1.5
skirt_line_count = 5 skirt_line_count = 5
speed_infill = =speed_print speed_infill = =speed_print
speed_layer_0 = 25 speed_layer_0 = 25
speed_print = 50 speed_print = 30
speed_topbottom = 40 speed_topbottom = 40
speed_travel = 200 speed_travel = 200
speed_wall_0 = 40 speed_wall_0 = 40

View file

@ -44,7 +44,7 @@ skirt_gap = 1.5
skirt_line_count = 5 skirt_line_count = 5
speed_infill = =speed_print speed_infill = =speed_print
speed_layer_0 = 25 speed_layer_0 = 25
speed_print = 50 speed_print = 30
speed_topbottom = 40 speed_topbottom = 40
speed_travel = 200 speed_travel = 200
speed_wall_0 = 40 speed_wall_0 = 40

View file

@ -12,6 +12,7 @@ material = fabtotum_pla
[values] [values]
adhesion_type = skirt adhesion_type = skirt
speed_print = 80
layer_height = 0.2 layer_height = 0.2
layer_height_0 = 0.2 layer_height_0 = 0.2
cool_fan_enabled = True cool_fan_enabled = True

View file

@ -12,6 +12,7 @@ material = fabtotum_pla
[values] [values]
adhesion_type = skirt adhesion_type = skirt
speed_print = 45
layer_height = 0.1 layer_height = 0.1
layer_height_0 = 0.1 layer_height_0 = 0.1
cool_fan_enabled = True cool_fan_enabled = True

View file

@ -12,6 +12,7 @@ material = fabtotum_pla
[values] [values]
adhesion_type = skirt adhesion_type = skirt
speed_print = 60
layer_height = 0.15 layer_height = 0.15
layer_height_0 = 0.15 layer_height_0 = 0.15
cool_fan_enabled = True cool_fan_enabled = True

View file

@ -0,0 +1,25 @@
[general]
version = 2
definition = fabtotum
name = Fast Quality
[metadata]
type = quality
setting_version = 4
material = fabtotum_tpu
quality_type = fast
weight = -1
[values]
adhesion_type = skirt
speed_print = 80
layer_height = 0.2
layer_height_0 = 0.2
cool_fan_enabled = True
cool_fan_full_at_height = 0.4
cool_fan_speed = 100
cool_fan_speed_max = 100
cool_fan_speed_min = 100
cool_min_layer_time = 5
cool_min_speed = 20

View file

@ -0,0 +1,24 @@
[general]
version = 2
definition = fabtotum
name = High Quality
[metadata]
type = quality
setting_version = 4
material = fabtotum_tpu
quality_type = high
weight = 1
[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_speed = 100
cool_fan_speed_max = 100
cool_fan_speed_min = 100
cool_min_layer_time = 5
cool_min_speed = 20

View file

@ -0,0 +1,25 @@
[general]
version = 2
definition = fabtotum
name = Normal Quality
[metadata]
type = quality
setting_version = 4
material = fabtotum_TPU
quality_type = normal
weight = 0
[values]
adhesion_type = skirt
speed_print = 80
layer_height = 0.15
layer_height_0 = 0.15
cool_fan_enabled = True
cool_fan_full_at_height = 0.3
cool_fan_speed = 100
cool_fan_speed_max = 100
cool_fan_speed_min = 100
cool_min_layer_time = 5
cool_min_speed = 20

View file

@ -12,6 +12,7 @@ material = generic_petg
variant = 0.4 mm variant = 0.4 mm
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_petg
variant = 0.4 mm 2-fans variant = 0.4 mm 2-fans
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_petg
variant = 0.4 mm variant = 0.4 mm
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_petg
variant = 0.4 mm 2-fans variant = 0.4 mm 2-fans
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm variant = 0.4 mm
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm 2-fans variant = 0.4 mm 2-fans
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm variant = 0.4 mm
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm 2-fans variant = 0.4 mm 2-fans
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm variant = 0.4 mm
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm 2-fans variant = 0.4 mm 2-fans
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -12,6 +12,7 @@ material = generic_pla
variant = 0.4 mm variant = 0.4 mm
[values] [values]
adhesion_type = skirt
bottom_thickness = 0.6 bottom_thickness = 0.6
coasting_enable = True coasting_enable = True
coasting_speed = 95 coasting_speed = 95

View file

@ -45,7 +45,7 @@ retraction_extrusion_window = 1
retraction_hop = 1.5 retraction_hop = 1.5
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True
retraction_min_travel = 0.8 retraction_min_travel = =line_width * 2
retraction_prime_speed = 15 retraction_prime_speed = 15
skin_overlap = 5 skin_overlap = 5
speed_equalize_flow_enabled = True speed_equalize_flow_enabled = True

View file

@ -46,7 +46,7 @@ retraction_extrusion_window = 1
retraction_hop = 1.5 retraction_hop = 1.5
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True
retraction_min_travel = 0.8 retraction_min_travel = =line_width * 2
retraction_prime_speed = 15 retraction_prime_speed = 15
skin_overlap = 5 skin_overlap = 5
speed_equalize_flow_enabled = True speed_equalize_flow_enabled = True

View file

@ -43,7 +43,7 @@ retraction_extrusion_window = 1
retraction_hop = 1.5 retraction_hop = 1.5
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True
retraction_min_travel = 0.8 retraction_min_travel = =line_width * 2
retraction_prime_speed = 15 retraction_prime_speed = 15
skin_overlap = 5 skin_overlap = 5
speed_equalize_flow_enabled = True speed_equalize_flow_enabled = True

View file

@ -41,7 +41,7 @@ retraction_count_max = 12
retraction_extra_prime_amount = 0.5 retraction_extra_prime_amount = 0.5
retraction_hop = 1.5 retraction_hop = 1.5
retraction_hop_only_when_collides = False retraction_hop_only_when_collides = False
retraction_min_travel = 0.8 retraction_min_travel = =line_width * 2
retraction_prime_speed = 15 retraction_prime_speed = 15
skin_line_width = =round(line_width * 0.78 / 0.8, 2) skin_line_width = =round(line_width * 0.78 / 0.8, 2)
speed_print = 30 speed_print = 30

View file

@ -42,7 +42,7 @@ retraction_count_max = 12
retraction_extra_prime_amount = 0.5 retraction_extra_prime_amount = 0.5
retraction_hop = 1.5 retraction_hop = 1.5
retraction_hop_only_when_collides = False retraction_hop_only_when_collides = False
retraction_min_travel = 0.8 retraction_min_travel = =line_width * 2
retraction_prime_speed = 15 retraction_prime_speed = 15
skin_line_width = =round(line_width * 0.78 / 0.8, 2) skin_line_width = =round(line_width * 0.78 / 0.8, 2)
speed_print = 30 speed_print = 30

View file

@ -41,7 +41,7 @@ retraction_count_max = 12
retraction_extra_prime_amount = 0.5 retraction_extra_prime_amount = 0.5
retraction_hop = 1.5 retraction_hop = 1.5
retraction_hop_only_when_collides = False retraction_hop_only_when_collides = False
retraction_min_travel = 0.8 retraction_min_travel = =line_width * 2
retraction_prime_speed = 15 retraction_prime_speed = 15
skin_line_width = =round(line_width * 0.78 / 0.8, 2) skin_line_width = =round(line_width * 0.78 / 0.8, 2)
speed_print = 30 speed_print = 30

View file

@ -4,6 +4,7 @@ version = 2
definition = cartesio definition = cartesio
[metadata] [metadata]
author = Cartesio
setting_version = 4 setting_version = 4
type = variant type = variant
hardware_type = nozzle hardware_type = nozzle

View file

@ -4,6 +4,7 @@ version = 2
definition = cartesio definition = cartesio
[metadata] [metadata]
author = Cartesio
setting_version = 4 setting_version = 4
type = variant type = variant
hardware_type = nozzle hardware_type = nozzle

View file

@ -4,6 +4,7 @@ version = 2
definition = cartesio definition = cartesio
[metadata] [metadata]
author = Cartesio
setting_version = 4 setting_version = 4
type = variant type = variant
hardware_type = nozzle hardware_type = nozzle

View file

@ -4,6 +4,7 @@ version = 2
definition = fabtotum definition = fabtotum
[metadata] [metadata]
author = FABtotum
setting_version = 4 setting_version = 4
type = variant type = variant
hardware_type = nozzle hardware_type = nozzle

View file

@ -4,6 +4,7 @@ version = 2
definition = fabtotum definition = fabtotum
[metadata] [metadata]
author = FABtotum
setting_version = 4 setting_version = 4
type = variant type = variant
hardware_type = nozzle hardware_type = nozzle

View file

@ -4,6 +4,7 @@ version = 2
definition = fabtotum definition = fabtotum
[metadata] [metadata]
author = FABtotum
setting_version = 4 setting_version = 4
type = variant type = variant
hardware_type = nozzle hardware_type = nozzle

Some files were not shown because too many files have changed in this diff Show more