Merge remote-tracking branch 'Ultimaker/master' into master-layerview-use-resetLayerData

This commit is contained in:
Thomas Karl Pietrowski 2016-06-10 14:05:45 +02:00
commit 7043a04e22
68 changed files with 1323 additions and 811 deletions

5
.gitignore vendored
View File

@ -16,8 +16,11 @@ resources/firmware
*~ *~
*.qm *.qm
.idea .idea
# Eclipse+PyDev
.project .project
.pydevproject .pydevproject
.settings
# Debian packaging # Debian packaging
debian/ debian*

View File

@ -5,6 +5,7 @@ from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
class ContainerSettingsModel(ListModel): class ContainerSettingsModel(ListModel):
LabelRole = Qt.UserRole + 1 LabelRole = Qt.UserRole + 1
@ -20,33 +21,12 @@ class ContainerSettingsModel(ListModel):
self.addRoleName(self.ValuesRole, "values") self.addRoleName(self.ValuesRole, "values")
self._container_ids = [] self._container_ids = []
self._container = None self._containers = []
self._global_container_stack = None def _onPropertyChanged(self, key, property_name):
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
self._update()
def _onGlobalContainerChanged(self):
if self._global_container_stack:
self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
self._global_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged)
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
if self._global_container_stack:
Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId())
self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged)
self._update()
def _onGlobalPropertyChanged(self, key, property_name):
if property_name == "value": if property_name == "value":
self._update() self._update()
def _onInstanceContainersChanged(self, container):
self._update()
def _update(self): def _update(self):
self.clear() self.clear()
@ -54,24 +34,17 @@ class ContainerSettingsModel(ListModel):
return return
keys = [] keys = []
containers = [] for container in self._containers:
for container_id in self._container_ids: keys = keys + list(container.getAllKeys())
container = ContainerRegistry.getInstance().findContainers(id = container_id)
if not container:
return
keys = keys + list(container[0].getAllKeys()) keys = list(set(keys)) # remove duplicate keys
containers.append(container[0])
keys = list(set(keys))
keys.sort() keys.sort()
for key in keys: for key in keys:
definition = None definition = None
category = None category = None
values = [] values = []
for container in containers: for container in self._containers:
instance = container.getInstance(key) instance = container.getInstance(key)
if instance: if instance:
definition = instance.definition definition = instance.definition
@ -81,7 +54,11 @@ class ContainerSettingsModel(ListModel):
while category.type != "category": while category.type != "category":
category = category.parent category = category.parent
values.append(container.getProperty(key, "value")) value = container.getProperty(key, "value")
if type(value) == SettingFunction:
values.append("=\u0192")
else:
values.append(container.getProperty(key, "value"))
else: else:
values.append("") values.append("")
@ -93,9 +70,21 @@ class ContainerSettingsModel(ListModel):
"category": category.label "category": category.label
}) })
## Set the id of the container which has the settings this model should list. ## Set the ids of the containers which have the settings this model should list.
# Also makes sure the model updates when the containers have property changes
def setContainers(self, container_ids): def setContainers(self, container_ids):
for container in self._containers:
container.propertyChanged.disconnect(self._onPropertyChanged)
self._container_ids = container_ids self._container_ids = container_ids
self._containers = []
for container_id in self._container_ids:
containers = ContainerRegistry.getInstance().findContainers(id = container_id)
if containers:
containers[0].propertyChanged.connect(self._onPropertyChanged)
self._containers.append(containers[0])
self._update() self._update()
containersChanged = pyqtSignal() containersChanged = pyqtSignal()

View File

@ -93,8 +93,11 @@ class CuraApplication(QtApplication):
self._open_file_queue = [] # Files to open when plug-ins are loaded. self._open_file_queue = [] # Files to open when plug-ins are loaded.
# Need to do this before ContainerRegistry tries to load the machines # Need to do this before ContainerRegistry tries to load the machines
SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSettingType("extruder", str, ast.literal_eval, UM.Settings.Validator) SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default = True)
SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator)
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType)
@ -291,6 +294,7 @@ class CuraApplication(QtApplication):
# \sa PluginRegistery # \sa PluginRegistery
def _loadPlugins(self): def _loadPlugins(self):
self._plugin_registry.addType("profile_reader", self._addProfileReader) self._plugin_registry.addType("profile_reader", self._addProfileReader)
self._plugin_registry.addType("profile_writer", self._addProfileWriter)
self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura"))
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins"))
@ -785,3 +789,6 @@ class CuraApplication(QtApplication):
def _addProfileReader(self, profile_reader): def _addProfileReader(self, profile_reader):
# TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles. # TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles.
pass pass
def _addProfileWriter(self, profile_writer):
pass

View File

@ -36,7 +36,7 @@ class ExtruderManager(QObject):
if not UM.Application.getInstance().getGlobalContainerStack(): if not UM.Application.getInstance().getGlobalContainerStack():
return None #No active machine, so no active extruder. return None #No active machine, so no active extruder.
try: try:
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)] return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)].getId()
except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
return None return None
@ -58,11 +58,22 @@ class ExtruderManager(QObject):
cls.__instance = ExtruderManager() cls.__instance = ExtruderManager()
return cls.__instance return cls.__instance
## Changes the active extruder by index.
#
# \param index The index of the new active extruder.
@pyqtSlot(int) @pyqtSlot(int)
def setActiveExtruderIndex(self, index): def setActiveExtruderIndex(self, index):
self._active_extruder_index = index self._active_extruder_index = index
self.activeExtruderChanged.emit() self.activeExtruderChanged.emit()
def getActiveExtruderStack(self):
try:
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)]
except AttributeError:
return None
except KeyError:
return None
## Adds all extruders of a specific machine definition to the extruder ## Adds all extruders of a specific machine definition to the extruder
# manager. # manager.
# #
@ -87,7 +98,7 @@ class ExtruderManager(QObject):
#Gets the extruder trains that we just created as well as any that still existed. #Gets the extruder trains that we just created as well as any that still existed.
extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId()) extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId())
for extruder_train in extruder_trains: for extruder_train in extruder_trains:
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
if extruder_trains: if extruder_trains:
self.extrudersChanged.emit(machine_definition) self.extrudersChanged.emit(machine_definition)
@ -188,21 +199,17 @@ class ExtruderManager(QObject):
container_registry.addContainer(container_stack) container_registry.addContainer(container_stack)
## Generates extruders for a specific machine. ## Generates extruders for a specific machine.
def getMachineExtruders(self, machine_definition): #
container_registry = UM.Settings.ContainerRegistry.getInstance() # \param machine_id The machine to get the extruders of.
machine_id = machine_definition.getId() def getMachineExtruders(self, machine_id):
if not machine_id in self._extruder_trains: if machine_id not in self._extruder_trains:
UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id) UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id)
return return
for _,extruder_train_id in self._extruder_trains[machine_id].items(): for name in self._extruder_trains[machine_id]:
extruder_train = container_registry.findContainerStacks(id = extruder_train_id) yield self._extruder_trains[machine_id][name]
if extruder_train:
yield extruder_train[0]
else:
UM.Logger.log("w", "Machine %s refers to an extruder train with ID %s, which doesn't exist.", machine_id, extruder_train_id)
## Adds the extruders of the currently active machine. ## Adds the extruders of the currently active machine.
def _addCurrentMachineExtruders(self): def _addCurrentMachineExtruders(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack() global_stack = UM.Application.getInstance().getGlobalContainerStack()
if global_stack and global_stack.getBottom(): if global_stack and global_stack.getBottom():
self.addMachineExtruders(global_stack.getBottom()) self.addMachineExtruders(global_stack.getBottom())

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 AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
import cura.ExtruderManager import cura.ExtruderManager
import UM.Qt.ListModel import UM.Qt.ListModel
@ -12,18 +12,25 @@ import UM.Qt.ListModel
# intended for drop-down lists of the current machine's extruders in place of # intended for drop-down lists of the current machine's extruders in place of
# settings. # settings.
class ExtrudersModel(UM.Qt.ListModel.ListModel): class ExtrudersModel(UM.Qt.ListModel.ListModel):
# The ID of the container stack for the extruder.
IdRole = Qt.UserRole + 1
## Human-readable name of the extruder. ## Human-readable name of the extruder.
NameRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 2
## Colour of the material loaded in the extruder. ## Colour of the material loaded in the extruder.
ColourRole = Qt.UserRole + 2 ColourRole = Qt.UserRole + 3
## Index of the extruder, which is also the value of the setting itself. ## Index of the extruder, which is also the value of the setting itself.
# #
# An index of 0 indicates the first extruder, an index of 1 the second # An index of 0 indicates the first extruder, an index of 1 the second
# one, and so on. This is the value that will be saved in instance # one, and so on. This is the value that will be saved in instance
# containers. # containers.
IndexRole = Qt.UserRole + 3 IndexRole = Qt.UserRole + 4
## Colour to display if there is no material or the material has no known
# colour.
defaultColour = "#FFFF00"
## Initialises the extruders model, defining the roles and listening for ## Initialises the extruders model, defining the roles and listening for
# changes in the data. # changes in the data.
@ -32,16 +39,30 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
self.addRoleName(self.IdRole, "id")
self.addRoleName(self.NameRole, "name") self.addRoleName(self.NameRole, "name")
self.addRoleName(self.ColourRole, "colour") self.addRoleName(self.ColourRole, "colour")
self.addRoleName(self.IndexRole, "index") self.addRoleName(self.IndexRole, "index")
self._add_global = False
#Listen to changes. #Listen to changes.
manager = cura.ExtruderManager.ExtruderManager.getInstance() manager = cura.ExtruderManager.ExtruderManager.getInstance()
manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general. manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general.
UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes. UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes.
self._updateExtruders() self._updateExtruders()
def setAddGlobal(self, add):
if add != self._add_global:
self._add_global = add
self._updateExtruders()
self.addGlobalChanged.emit()
addGlobalChanged = pyqtSignal()
@pyqtProperty(bool, fset = setAddGlobal, notify = addGlobalChanged)
def addGlobal(self):
return self._add_global
## Update the list of extruders. ## Update the list of extruders.
# #
# This should be called whenever the list of extruders changes. # This should be called whenever the list of extruders changes.
@ -51,13 +72,32 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack() global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_container_stack: if not global_container_stack:
return #There is no machine to get the extruders of. return #There is no machine to get the extruders of.
for index, extruder in enumerate(manager.getMachineExtruders(global_container_stack.getBottom())):
material = extruder.findContainer({ "type": "material" }) if self._add_global:
colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" material = global_container_stack.findContainer({ "type": "material" })
item = { #Construct an item with only the relevant information. colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
"name": extruder.getName(), item = {
"id": global_container_stack.getId(),
"name": "Global",
"colour": colour, "colour": colour,
"index": index "index": -1
} }
self.appendItem(item) self.appendItem(item)
self.sort(lambda item: item["index"])
for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()):
material = extruder.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
position = extruder.getBottom().getMetaDataEntry("position", default = "0") #Position in the definition.
try:
position = int(position)
except ValueError: #Not a proper int.
position = -1
item = { #Construct an item with only the relevant information.
"id": extruder.getId(),
"name": extruder.getName(),
"colour": colour,
"index": position
}
self.appendItem(item)
self.sort(lambda item: item["index"])

View File

@ -4,7 +4,6 @@ import re
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
from UM.Logger import Logger
import UM.Settings import UM.Settings
from UM.Settings.Validator import ValidatorState from UM.Settings.Validator import ValidatorState
@ -14,6 +13,7 @@ from . import ExtruderManager
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
class MachineManagerModel(QObject): class MachineManagerModel(QObject):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
@ -41,7 +41,6 @@ class MachineManagerModel(QObject):
self.setActiveMachine(active_machine_id) self.setActiveMachine(active_machine_id)
pass pass
globalContainerChanged = pyqtSignal() globalContainerChanged = pyqtSignal()
activeMaterialChanged = pyqtSignal() activeMaterialChanged = pyqtSignal()
activeVariantChanged = pyqtSignal() activeVariantChanged = pyqtSignal()
@ -114,8 +113,8 @@ class MachineManagerModel(QObject):
UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack)
variant_instance_container = self._updateVariantContainer(definition) variant_instance_container = self._updateVariantContainer(definition)
material_instance_container = self._updateMaterialContainer(definition) material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
quality_instance_container = self._updateQualityContainer(definition) quality_instance_container = self._updateQualityContainer(definition, material_instance_container)
current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
current_settings_instance_container.addMetaDataEntry("machine", name) current_settings_instance_container.addMetaDataEntry("machine", name)
@ -266,41 +265,21 @@ class MachineManagerModel(QObject):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
if not containers or not self._global_container_stack: if not containers or not self._global_container_stack:
return True return True
return containers[0].getMetaDataEntry("read_only", False) == "True" return containers[0].isReadOnly()
@pyqtSlot(result = str) @pyqtSlot(result = str)
def convertUserContainerToQuality(self): def newQualityContainerFromQualityAndUser(self):
if not self._global_container_stack: new_container_id = self.duplicateContainer(self.activeQualityId)
if new_container_id == "":
return return
self.setActiveQuality(new_container_id)
self.updateQualityContainerFromUserContainer()
new_quality_container = InstanceContainer("")
name = self._createUniqueName("quality", "", self.activeQualityName, catalog.i18nc("@label", "Custom profile"))
user_settings = self._global_container_stack.getTop()
## Copy all values
new_quality_container.deserialize(user_settings.serialize())
## If the currently active machine does not have quality profiles of its own,
# make the new quality profile available for all machines that don't have
# unique quality profiles (including the current machine)
if not self.filterQualityByMachine:
new_quality_container.setDefinition(UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0])
## Change type / id / name
new_quality_container.setMetaDataEntry("type", "quality")
new_quality_container.setMetaDataEntry("read_only", False)
new_quality_container.setName(name)
new_quality_container._id = name
UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container)
self.clearUserSettings() # As all users settings are now transfered to the new quality profile, remove them.
self.setActiveQuality(name)
return name
@pyqtSlot(str, result=str) @pyqtSlot(str, result=str)
def duplicateContainer(self, container_id): def duplicateContainer(self, container_id):
if not self._global_container_stack: if not self._global_container_stack:
return return ""
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
if containers: if containers:
new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile"))
@ -310,7 +289,7 @@ class MachineManagerModel(QObject):
## Copy all values ## Copy all values
new_container.deserialize(containers[0].serialize()) new_container.deserialize(containers[0].serialize())
new_container.setMetaDataEntry("read_only", False) new_container.setReadOnly(False)
new_container.setName(new_name) new_container.setName(new_name)
new_container._id = new_name new_container._id = new_name
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
@ -318,15 +297,36 @@ class MachineManagerModel(QObject):
return "" return ""
@pyqtSlot(str, str) @pyqtSlot(str, str)
def renameQualityContainer(self, container_id, new_name): def renameQualityContainer(self, container_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality")
if containers: if containers:
new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) new_name = self._createUniqueName("quality", containers[0].getName(), new_name,
containers[0].setName(new_name) catalog.i18nc("@label", "Custom profile"))
self.activeQualityChanged.emit()
if containers[0].getName() == new_name:
# Nothing to do.
return
# As we also want the id of the container to be changed (so that profile name is the name of the file
# on disk. We need to create a new instance and remove it (so the old file of the container is removed)
# If we don't do that, we might get duplicates & other weird issues.
new_container = InstanceContainer("")
new_container.deserialize(containers[0].serialize())
# Actually set the name
new_container.setName(new_name)
new_container._id = new_name # Todo: Fix proper id change function for this.
# Add the "new" container.
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
# Ensure that the renamed profile is saved -before- we remove the old profile.
Application.getInstance().saveSettings()
# Actually set & remove new / old quality.
self.setActiveQuality(new_name)
self.removeQualityContainer(containers[0].getId())
@pyqtSlot(str) @pyqtSlot(str)
def removeQualityContainer(self, container_id): def removeQualityContainer(self, container_id):
@ -348,7 +348,7 @@ class MachineManagerModel(QObject):
@pyqtSlot() @pyqtSlot()
def updateUserContainerToQuality(self): def updateQualityContainerFromUserContainer(self):
if not self._global_container_stack: if not self._global_container_stack:
return return
user_settings = self._global_container_stack.getTop() user_settings = self._global_container_stack.getTop()

25
cura/ProfileWriter.py Normal file
View File

@ -0,0 +1,25 @@
# Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
from UM.PluginObject import PluginObject
## Base class for profile writer plugins.
#
# This class defines a write() function to write profiles to files with.
class ProfileWriter(PluginObject):
## Initialises the profile writer.
#
# This currently doesn't do anything since the writer is basically static.
def __init__(self):
super().__init__()
## Writes a profile to the specified file path.
#
# The profile writer may write its own file format to the specified file.
#
# \param path \type{string} The file to output to.
# \param profile \type{Profile} The profile to write to the file.
# \return \code True \endcode if the writing was successful, or \code
# False \endcode if it wasn't.
def write(self, path, node):
raise NotImplementedError("Profile writer plugin was not correctly implemented. No write was specified.")

View File

@ -1,30 +1,40 @@
# Copyright (c) 2016 Ultimaker B.V. # Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
import copy
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from UM.Signal import Signal, signalemitter
from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
import UM.Logger
from UM.Application import Application from UM.Application import Application
import copy
## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding ## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding
# the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by # the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by
# this stack still resolve. # this stack still resolve.
@signalemitter
class SettingOverrideDecorator(SceneNodeDecorator): class SettingOverrideDecorator(SceneNodeDecorator):
## Event indicating that the user selected a different extruder.
activeExtruderChanged = Signal()
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._stack = ContainerStack(stack_id = id(self)) self._stack = ContainerStack(stack_id = id(self))
self._stack.setDirty(False) # This stack does not need to be saved. self._stack.setDirty(False) # This stack does not need to be saved.
self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer")
self._stack.addContainer(self._instance) self._stack.addContainer(self._instance)
self._extruder_stack = None #Stack upon which our stack is based.
self._stack.propertyChanged.connect(self._onSettingChanged) self._stack.propertyChanged.connect(self._onSettingChanged)
ContainerRegistry.getInstance().addContainer(self._stack) ContainerRegistry.getInstance().addContainer(self._stack)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack)
self._onGlobalContainerStackChanged() self.activeExtruderChanged.connect(self._updateNextStack)
self._updateNextStack()
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
## Create a fresh decorator object ## Create a fresh decorator object
@ -35,13 +45,34 @@ class SettingOverrideDecorator(SceneNodeDecorator):
deep_copy._stack.replaceContainer(0, deep_copy._instance) deep_copy._stack.replaceContainer(0, deep_copy._instance)
return deep_copy return deep_copy
## Gets the currently active extruder to print this object with.
#
# \return An extruder's container stack.
def getActiveExtruder(self):
return self._extruder_stack
def _onSettingChanged(self, instance, property): def _onSettingChanged(self, instance, property):
if property == "value": # Only reslice if the value has changed. if property == "value": # Only reslice if the value has changed.
Application.getInstance().getBackend().forceSlice() Application.getInstance().getBackend().forceSlice()
def _onGlobalContainerStackChanged(self): ## Makes sure that the stack upon which the container stack is placed is
## Ensure that the next stack is always the global stack. # kept up to date.
self._stack.setNextStack(Application.getInstance().getGlobalContainerStack()) def _updateNextStack(self):
if self._extruder_stack:
extruder_stack = ContainerRegistry.getInstance().findContainerStacks(id = self._extruder_stack)
if extruder_stack:
self._stack.setNextStack(extruder_stack)
else:
UM.Logger.log("e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack)
else:
self._stack.setNextStack(Application.getInstance().getGlobalContainerStack())
## Changes the extruder with which to print this node.
#
# \param extruder_stack_id The new extruder stack to print with.
def setActiveExtruder(self, extruder_stack_id):
self._extruder_stack = extruder_stack_id
self.activeExtruderChanged.emit()
def getStack(self): def getStack(self):
return self._stack return self._stack

View File

@ -36,7 +36,6 @@ import Arcus #@UnusedImport
import cura.CuraApplication import cura.CuraApplication
if sys.platform == "win32" and hasattr(sys, "frozen"): if sys.platform == "win32" and hasattr(sys, "frozen"):
import os
dirpath = os.path.expanduser("~/AppData/Local/cura/") dirpath = os.path.expanduser("~/AppData/Local/cura/")
os.makedirs(dirpath, exist_ok = True) os.makedirs(dirpath, exist_ok = True)
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w") sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")

View File

@ -5,12 +5,20 @@ package cura.proto;
message ObjectList message ObjectList
{ {
repeated Object objects = 1; repeated Object objects = 1;
repeated Setting settings = 2; repeated Setting settings = 2; // meshgroup settings (for one-at-a-time printing)
} }
message Slice message Slice
{ {
repeated ObjectList object_lists = 1; repeated ObjectList object_lists = 1; // The meshgroups to be printed one after another
SettingList global_settings = 2; // The global settings used for the whole print job
repeated Extruder extruders = 3; // The settings sent to each extruder object
}
message Extruder
{
int32 id = 1;
SettingList settings = 2;
} }
message Object message Object
@ -29,10 +37,10 @@ message Progress
message Layer { message Layer {
int32 id = 1; int32 id = 1;
float height = 2; float height = 2; // Z position
float thickness = 3; float thickness = 3; // height of a single layer
repeated Polygon polygons = 4; repeated Polygon polygons = 4; // layer data
} }
message Polygon { message Polygon {
@ -48,19 +56,19 @@ message Polygon {
MoveCombingType = 8; MoveCombingType = 8;
MoveRetractionType = 9; MoveRetractionType = 9;
} }
Type type = 1; Type type = 1; // Type of move
bytes points = 2; bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used)
float line_width = 3; float line_width = 3; // The width of the line being laid down
} }
message GCodeLayer { message GCodeLayer {
bytes data = 2; bytes data = 2;
} }
message ObjectPrintTime { message ObjectPrintTime { // The print time for the whole print and material estimates for the first extruder
int64 id = 1; int64 id = 1;
float time = 2; float time = 2; // Total time estimate
float material_amount = 3; float material_amount = 3; // material used in the first extruder
} }
message SettingList { message SettingList {
@ -68,13 +76,13 @@ message SettingList {
} }
message Setting { message Setting {
string name = 1; string name = 1; // Internal key to signify a setting
bytes value = 2; bytes value = 2; // The value of the setting
} }
message GCodePrefix { message GCodePrefix {
bytes data = 2; bytes data = 2; // Header string to be prenpended before the rest of the gcode sent from the engine
} }
message SlicingFinished { message SlicingFinished {

View File

@ -12,6 +12,8 @@ from UM.PluginRegistry import PluginRegistry
from UM.Resources import Resources from UM.Resources import Resources
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then. from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
from cura.ExtruderManager import ExtruderManager
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
from . import ProcessSlicedLayersJob from . import ProcessSlicedLayersJob
from . import ProcessGCodeJob from . import ProcessGCodeJob
@ -59,6 +61,10 @@ class CuraEngineBackend(Backend):
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
self._onGlobalStackChanged() self._onGlobalStackChanged()
self._active_extruder_stack = None
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
self._onActiveExtruderChanged()
#When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired. #When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired.
#This timer will group them up, and only slice for the last setting changed signal. #This timer will group them up, and only slice for the last setting changed signal.
#TODO: Properly group propertyChanged signals by whether they are triggered by the same user interaction. #TODO: Properly group propertyChanged signals by whether they are triggered by the same user interaction.
@ -145,8 +151,7 @@ class CuraEngineBackend(Backend):
self.slicingStarted.emit() self.slicingStarted.emit()
slice_message = self._socket.createMessage("cura.proto.Slice") slice_message = self._socket.createMessage("cura.proto.Slice")
settings_message = self._socket.createMessage("cura.proto.SettingList") self._start_slice_job = StartSliceJob.StartSliceJob(slice_message)
self._start_slice_job = StartSliceJob.StartSliceJob(slice_message, settings_message)
self._start_slice_job.start() self._start_slice_job.start()
self._start_slice_job.finished.connect(self._onStartSliceCompleted) self._start_slice_job.finished.connect(self._onStartSliceCompleted)
@ -205,7 +210,6 @@ class CuraEngineBackend(Backend):
return return
# Preparation completed, send it to the backend. # Preparation completed, send it to the backend.
self._socket.sendMessage(job.getSettingsMessage())
self._socket.sendMessage(job.getSliceMessage()) self._socket.sendMessage(job.getSliceMessage())
## Listener for when the scene has changed. ## Listener for when the scene has changed.
@ -369,4 +373,16 @@ class CuraEngineBackend(Backend):
if self._global_container_stack: if self._global_container_stack:
self._global_container_stack.propertyChanged.connect(self._onSettingChanged) #Note: Only starts slicing when the value changed. self._global_container_stack.propertyChanged.connect(self._onSettingChanged) #Note: Only starts slicing when the value changed.
self._global_container_stack.containersChanged.connect(self._onChanged) self._global_container_stack.containersChanged.connect(self._onChanged)
self._onActiveExtruderChanged()
self._onChanged() self._onChanged()
def _onActiveExtruderChanged(self):
if self._active_extruder_stack:
self._active_extruder_stack.propertyChanged.disconnect(self._onSettingChanged)
self._active_extruder_stack.containersChanged.disconnect(self._onChanged)
self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if self._active_extruder_stack:
self._active_extruder_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed.
self._active_extruder_stack.containersChanged.connect(self._onChanged)
self._onChanged()

View File

@ -15,6 +15,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Settings.Validator import ValidatorState from UM.Settings.Validator import ValidatorState
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
from cura.ExtruderManager import ExtruderManager
class StartJobResult(IntEnum): class StartJobResult(IntEnum):
Finished = 1 Finished = 1
@ -37,17 +38,13 @@ class GcodeStartEndFormatter(Formatter):
## Job class that builds up the message of scene data to send to CuraEngine. ## Job class that builds up the message of scene data to send to CuraEngine.
class StartSliceJob(Job): class StartSliceJob(Job):
def __init__(self, slice_message, settings_message): def __init__(self, slice_message):
super().__init__() super().__init__()
self._scene = Application.getInstance().getController().getScene() self._scene = Application.getInstance().getController().getScene()
self._slice_message = slice_message self._slice_message = slice_message
self._settings_message = settings_message
self._is_cancelled = False self._is_cancelled = False
def getSettingsMessage(self):
return self._settings_message
def getSliceMessage(self): def getSliceMessage(self):
return self._slice_message return self._slice_message
@ -131,6 +128,9 @@ class StartSliceJob(Job):
self._buildGlobalSettingsMessage(stack) self._buildGlobalSettingsMessage(stack)
for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()):
self._buildExtruderMessage(extruder_stack)
for group in object_groups: for group in object_groups:
group_message = self._slice_message.addRepeatedMessage("object_lists") group_message = self._slice_message.addRepeatedMessage("object_lists")
if group[0].getParent().callDecoration("isGroup"): if group[0].getParent().callDecoration("isGroup"):
@ -170,6 +170,15 @@ class StartSliceJob(Job):
Logger.logException("w", "Unable to do token replacement on start/end gcode") Logger.logException("w", "Unable to do token replacement on start/end gcode")
return str(value).encode("utf-8") return str(value).encode("utf-8")
def _buildExtruderMessage(self, stack):
message = self._slice_message.addRepeatedMessage("extruders")
message.id = int(stack.getMetaDataEntry("position"))
for key in stack.getAllKeys():
setting = message.getMessage("settings").addRepeatedMessage("settings")
setting.name = key
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()
## Sends all global settings to the engine. ## Sends all global settings to the engine.
# #
# The settings are taken from the global stack. This does not include any # The settings are taken from the global stack. This does not include any
@ -185,7 +194,7 @@ class StartSliceJob(Job):
settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode
for key, value in settings.items(): #Add all submessages for each individual setting. for key, value in settings.items(): #Add all submessages for each individual setting.
setting_message = self._settings_message.addRepeatedMessage("settings") setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
setting_message.name = key setting_message.name = key
if key == "machine_start_gcode" or key == "machine_end_gcode": #If it's a g-code message, use special formatting. if key == "machine_start_gcode" or key == "machine_end_gcode": #If it's a g-code message, use special formatting.
setting_message.value = self._expandGcodeTokens(key, value, settings) setting_message.value = self._expandGcodeTokens(key, value, settings)
@ -193,21 +202,10 @@ class StartSliceJob(Job):
setting_message.value = str(value).encode("utf-8") setting_message.value = str(value).encode("utf-8")
def _handlePerObjectSettings(self, node, message): def _handlePerObjectSettings(self, node, message):
profile = node.callDecoration("getProfile") stack = node.callDecoration("getStack")
if profile: if stack:
for key, value in profile.getAllSettingValues().items(): for key in stack.getAllKeys():
setting = message.addRepeatedMessage("settings") setting = message.addRepeatedMessage("settings")
setting.name = key setting.name = key
setting.value = str(value).encode() setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()
Job.yieldThread()
object_settings = node.callDecoration("getAllSettingValues")
if not object_settings:
return
for key, value in object_settings.items():
setting = message.addRepeatedMessage("settings")
setting.name = key
setting.value = str(value).encode()
Job.yieldThread()

View File

@ -1,11 +1,12 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
import os.path
from UM.Application import Application #To get the machine manager to create the new profile in. from UM.Application import Application #To get the machine manager to create the new profile in.
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.Profile import Profile from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make.
from UM.Settings.ProfileReader import ProfileReader from cura.ProfileReader import ProfileReader
## A plugin that reads profile data from Cura profile files. ## A plugin that reads profile data from Cura profile files.
# #
@ -25,17 +26,17 @@ class CuraProfileReader(ProfileReader):
# returned. # returned.
def read(self, file_name): def read(self, file_name):
# Create an empty profile. # Create an empty profile.
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) profile = InstanceContainer(os.path.basename(os.path.splitext(file_name)[0]))
serialised = "" profile.addMetaDataEntry("type", "quality")
try: try:
with open(file_name) as f: # Open file for reading. with open(file_name) as f: # Open file for reading.
serialised = f.read() serialized = f.read()
except IOError as e: except IOError as e:
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e)) Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
return None return None
try: try:
profile.unserialise(serialised) profile.deserialize(serialized)
except Exception as e: # Parsing error. This is not a (valid) Cura profile then. except Exception as e: # Parsing error. This is not a (valid) Cura profile then.
Logger.log("e", "Error while trying to parse profile: %s", str(e)) Logger.log("e", "Error while trying to parse profile: %s", str(e))
return None return None

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for importing Cura profiles."), "description": catalog.i18nc("@info:whatsthis", "Provides support for importing Cura profiles."),
"api": 2 "api": 3
}, },
"profile_reader": [ "profile_reader": [
{ {

View File

@ -4,7 +4,7 @@
from UM.Logger import Logger from UM.Logger import Logger
from UM.SaveFile import SaveFile from UM.SaveFile import SaveFile
from UM.Settings.ProfileWriter import ProfileWriter from cura.ProfileWriter import ProfileWriter
## Writes profiles to Cura's own profile format with config files. ## Writes profiles to Cura's own profile format with config files.
@ -16,10 +16,10 @@ class CuraProfileWriter(ProfileWriter):
# \return \code True \endcode if the writing was successful, or \code # \return \code True \endcode if the writing was successful, or \code
# False \endcode if it wasn't. # False \endcode if it wasn't.
def write(self, path, profile): def write(self, path, profile):
serialised = profile.serialise() serialized = profile.serialize()
try: try:
with SaveFile(path, "wt", -1, "utf-8") as f: # Open the specified file. with SaveFile(path, "wt", -1, "utf-8") as f: # Open the specified file.
f.write(serialised) f.write(serialized)
except Exception as e: except Exception as e:
Logger.log("e", "Failed to write profile to %s: %s", path, str(e)) Logger.log("e", "Failed to write profile to %s: %s", path, str(e))
return False return False

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."), "description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."),
"api": 2 "api": 3
}, },
"profile_writer": [ "profile_writer": [
{ {

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher. // Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -26,6 +26,99 @@ Item {
spacing: UM.Theme.getSize("default_margin").height; spacing: UM.Theme.getSize("default_margin").height;
Row
{
ComboBox
{
id: extruderSelector
model: Cura.ExtrudersModel
{
id: extruders_model
}
visible: extruders_model.rowCount() > 1
textRole: "name"
width: items.width
height: UM.Theme.getSize("section").height
MouseArea
{
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: wheel.accepted = true;
}
style: ComboBoxStyle
{
background: Rectangle
{
color:
{
if(extruderSelector.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_control_highlight");
}
else
{
return extruders_model.getItem(extruderSelector.currentIndex).colour;
}
}
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("setting_control_border")
}
label: Item
{
Label
{
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.right: downArrow.left
anchors.rightMargin: UM.Theme.getSize("default_lining").width
anchors.verticalCenter: parent.verticalCenter
text: extruderSelector.currentText
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("setting_control_disabled_text")
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
UM.RecolorImage
{
id: downArrow
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getIcon("arrow_bottom")
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width + 5
sourceSize.height: width + 5
color: UM.Theme.getColor("setting_control_text")
}
}
}
onActivated: UM.ActiveTool.setProperty("SelectedActiveExtruder", extruders_model.getItem(index).id);
onModelChanged: updateCurrentIndex();
function updateCurrentIndex()
{
for(var i = 0; i < extruders_model.rowCount(); ++i)
{
if(extruders_model.getItem(i).id == UM.ActiveTool.properties.getValue("SelectedActiveExtruder"))
{
extruderSelector.currentIndex = i;
return;
}
}
extruderSelector.currentIndex = -1;
}
}
}
Repeater Repeater
{ {
id: contents id: contents
@ -190,11 +283,11 @@ Item {
{ {
if(text != "") if(text != "")
{ {
listview.model.filter = {"global_only": false, "label": "*" + text} listview.model.filter = {"settable_per_mesh": true, "label": "*" + text}
} }
else else
{ {
listview.model.filter = {"global_only": false} listview.model.filter = {"settable_per_mesh": true}
} }
} }
} }
@ -219,7 +312,7 @@ Item {
containerId: Cura.MachineManager.activeDefinitionId containerId: Cura.MachineManager.activeDefinitionId
filter: filter:
{ {
"global_only": false "settable_per_mesh": true
} }
visibilityHandler: UM.SettingPreferenceVisibilityHandler {} visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
} }

View File

@ -1,11 +1,11 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2016 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher. # Uranium is released under the terms of the AGPLv3 or higher.
from UM.Tool import Tool from UM.Tool import Tool
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
from cura.SettingOverrideDecorator import SettingOverrideDecorator
## This tool allows the user to add & change settings per node in the scene. ## This tool allows the user to add & change settings per node in the scene.
# The settings per object are kept in a ContainerStack, which is linked to a node by decorator. # The settings per object are kept in a ContainerStack, which is linked to a node by decorator.
@ -14,7 +14,7 @@ class PerObjectSettingsTool(Tool):
super().__init__() super().__init__()
self._model = None self._model = None
self.setExposedProperties("SelectedObjectId", "ContainerID") self.setExposedProperties("SelectedObjectId", "ContainerID", "SelectedActiveExtruder")
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged) Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
Selection.selectionChanged.connect(self.propertyChanged) Selection.selectionChanged.connect(self.propertyChanged)
@ -42,6 +42,24 @@ class PerObjectSettingsTool(Tool):
except AttributeError: except AttributeError:
return "" return ""
## Gets the active extruder of the currently selected object.
#
# \return The active extruder of the currently selected object.
def getSelectedActiveExtruder(self):
selected_object = Selection.getSelectedObject(0)
selected_object.callDecoration("getActiveExtruder")
## Changes the active extruder of the currently selected object.
#
# \param extruder_stack_id The ID of the extruder to print the currently
# selected object with.
def setSelectedActiveExtruder(self, extruder_stack_id):
selected_object = Selection.getSelectedObject(0)
stack = selected_object.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway.
if not stack:
selected_object.addDecorator(SettingOverrideDecorator())
selected_object.callDecoration("setActiveExtruder", extruder_stack_id)
def _onPreferenceChanged(self, preference): def _onPreferenceChanged(self, preference):
if preference == "cura/active_mode": if preference == "cura/active_mode":
enabled = Preferences.getInstance().getValue(preference)==1 enabled = Preferences.getInstance().getValue(preference)==1

View File

@ -24,7 +24,11 @@
"description": "The extruder train used for printing. This is used in multi-extrusion.", "description": "The extruder train used for printing. This is used in multi-extrusion.",
"type": "extruder", "type": "extruder",
"default_value": 0, "default_value": 0,
"minimum_value": "0" "minimum_value": "0",
"settable_per_mesh": true,
"settable_per_extruder": false,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_nozzle_offset_x": "machine_nozzle_offset_x":
{ {
@ -33,7 +37,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_nozzle_offset_y": "machine_nozzle_offset_y":
{ {
@ -42,7 +49,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_code": "machine_extruder_start_code":
{ {
@ -50,7 +60,10 @@
"description": "Start g-code to execute whenever turning the extruder on.", "description": "Start g-code to execute whenever turning the extruder on.",
"type": "str", "type": "str",
"default_value": "", "default_value": "",
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_pos_abs": "machine_extruder_start_pos_abs":
{ {
@ -58,7 +71,10 @@
"description": "Make the extruder starting position absolute rather than relative to the last-known location of the head.", "description": "Make the extruder starting position absolute rather than relative to the last-known location of the head.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_pos_x": "machine_extruder_start_pos_x":
{ {
@ -67,7 +83,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_start_pos_y": "machine_extruder_start_pos_y":
{ {
@ -76,7 +95,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_code": "machine_extruder_end_code":
{ {
@ -84,7 +106,10 @@
"description": "End g-code to execute whenever turning the extruder off.", "description": "End g-code to execute whenever turning the extruder off.",
"type": "str", "type": "str",
"default_value": "", "default_value": "",
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_pos_abs": "machine_extruder_end_pos_abs":
{ {
@ -92,7 +117,10 @@
"description": "Make the extruder ending position absolute rather than relative to the last-known location of the head.", "description": "Make the extruder ending position absolute rather than relative to the last-known location of the head.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_pos_x": "machine_extruder_end_pos_x":
{ {
@ -101,7 +129,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
}, },
"machine_extruder_end_pos_y": "machine_extruder_end_pos_y":
{ {
@ -110,7 +141,10 @@
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0, "default_value": 0,
"global_only": "True" "settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false,
"settable_globally": false
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -111,23 +111,23 @@ Item
{ {
id: updateProfileAction; id: updateProfileAction;
enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile"); text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings");
onTriggered: Cura.MachineManager.updateUserContainerToQuality() onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer()
} }
Action Action
{ {
id: resetProfileAction; id: resetProfileAction;
enabled: Cura.MachineManager.hasUserSettings enabled: Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Reload Current Profile"); text: catalog.i18nc("@action:inmenu menubar:profile","&Discard current settings");
onTriggered: Cura.MachineManager.clearUserSettings(); onTriggered: Cura.MachineManager.clearUserSettings();
} }
Action Action
{ {
id: addProfileAction; id: addProfileAction;
enabled: Cura.MachineManager.isGlobalStackValid enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile..."); text: catalog.i18nc("@action:inmenu menubar:profile","&Create profile from current settings...");
} }
Action Action

View File

@ -258,13 +258,13 @@ UM.MainWindow
{ {
//Insert a separator between readonly and custom profiles //Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0) { if(separatorIndex < 0 && index > 0) {
if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) { if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) {
profileMenu.insertSeparator(index); profileMenu.insertSeparator(index);
separatorIndex = index; separatorIndex = index;
} }
} }
//Because of the separator, custom profiles move one index lower //Because of the separator, custom profiles move one index lower
profileMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item); profileMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item);
} }
onObjectRemoved: onObjectRemoved:
{ {
@ -297,11 +297,11 @@ UM.MainWindow
MenuSeparator { id: profileMenuSeparator } MenuSeparator { id: profileMenuSeparator }
MenuItem { action: Cura.Actions.updateProfile; } MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.resetProfile; } MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.addProfile; } MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { } MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles; } MenuItem { action: Cura.Actions.manageProfiles }
} }
Menu Menu
@ -533,13 +533,6 @@ UM.MainWindow
} }
width: UM.Theme.getSize("sidebar").width; width: UM.Theme.getSize("sidebar").width;
addMachineAction: Cura.Actions.addMachine;
configureMachinesAction: Cura.Actions.configureMachines;
addProfileAction: Cura.Actions.addProfile;
updateProfileAction: Cura.Actions.updateProfile;
resetProfileAction: Cura.Actions.resetProfile;
manageProfilesAction: Cura.Actions.manageProfiles;
} }
} }
} }
@ -589,7 +582,7 @@ UM.MainWindow
target: Cura.Actions.addProfile target: Cura.Actions.addProfile
onTriggered: onTriggered:
{ {
Cura.MachineManager.convertUserContainerToQuality(); Cura.MachineManager.newQualityContainerFromQualityAndUser();
preferences.setPage(5); preferences.setPage(5);
preferences.show(); preferences.show();

View File

@ -13,7 +13,7 @@ UM.ManagementPage
id: base; id: base;
title: catalog.i18nc("@title:tab", "Profiles"); title: catalog.i18nc("@title:tab", "Profiles");
addText: catalog.i18nc("@label", "Duplicate") addText: base.currentItem && (base.currentItem.id == Cura.MachineManager.activeQualityId) ? catalog.i18nc("@label", "Create") : catalog.i18nc("@label", "Duplicate")
model: UM.InstanceContainersModel model: UM.InstanceContainersModel
{ {
@ -36,6 +36,21 @@ UM.ManagementPage
} }
} }
section.property: "readOnly"
section.delegate: Rectangle
{
width: objectListContainer.viewport.width;
height: childrenRect.height;
Label
{
anchors.left: parent.left;
anchors.leftMargin: UM.Theme.getSize("default_lining").width;
text: section == "true" ? catalog.i18nc("@label", "Protected profiles") : catalog.i18nc("@label", "Custom profiles")
font.bold: true
}
}
activeId: Cura.MachineManager.activeQualityId activeId: Cura.MachineManager.activeQualityId
activeIndex: { activeIndex: {
for(var i = 0; i < model.rowCount(); i++) { for(var i = 0; i < model.rowCount(); i++) {
@ -49,9 +64,8 @@ UM.ManagementPage
onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id)
onAddObject: { onAddObject: {
var selectedContainer; var selectedContainer;
if (objectList.currentIndex == 0) { if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) {
// Current settings selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser();
selectedContainer = Cura.MachineManager.convertUserContainerToQuality();
} else { } else {
selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id);
} }
@ -66,8 +80,8 @@ UM.ManagementPage
activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false; activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false;
addEnabled: currentItem != null; addEnabled: currentItem != null;
removeEnabled: currentItem != null ? !currentItem.metadata.read_only : false; removeEnabled: currentItem != null ? !currentItem.readOnly : false;
renameEnabled: currentItem != null ? !currentItem.metadata.read_only : false; renameEnabled: currentItem != null ? !currentItem.readOnly : false;
scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName)
@ -102,17 +116,15 @@ UM.ManagementPage
Button Button
{ {
text: { text: {
var profileName = Cura.MachineManager.activeQualityName; return catalog.i18nc("@action:button", "Update profile with current settings");
profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName;
return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName));
} }
enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
onClicked: Cura.MachineManager.updateUserContainerToQuality() onClicked: Cura.MachineManager.updateQualityContainerFromUserContainer()
} }
Button Button
{ {
text: catalog.i18nc("@action:button", "Discard changes"); text: catalog.i18nc("@action:button", "Discard current settings");
enabled: Cura.MachineManager.hasUserSettings enabled: Cura.MachineManager.hasUserSettings
onClicked: Cura.MachineManager.clearUserSettings(); onClicked: Cura.MachineManager.clearUserSettings();
} }
@ -128,7 +140,7 @@ UM.ManagementPage
Label { Label {
id: defaultsMessage id: defaultsMessage
visible: !currentItem.hasSettings visible: !currentItem.metadata.has_settings
text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.") text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
width: parent.width width: parent.width
@ -155,7 +167,7 @@ UM.ManagementPage
model: Cura.ContainerSettingsModel{ containers: (currentItem.id == Cura.MachineManager.activeQualityId) ? [base.currentItem.id, Cura.MachineManager.activeUserProfileId] : [base.currentItem.id] } model: Cura.ContainerSettingsModel{ containers: (currentItem.id == Cura.MachineManager.activeQualityId) ? [base.currentItem.id, Cura.MachineManager.activeUserProfileId] : [base.currentItem.id] }
delegate: Row { delegate: Row {
property variant setting: model property variant setting: model
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width/2
Label { Label {
text: model.label text: model.label
elide: Text.ElideMiddle elide: Text.ElideMiddle
@ -165,7 +177,8 @@ UM.ManagementPage
model: setting.values.length model: setting.values.length
Label { Label {
text: setting.values[index].toString() text: setting.values[index].toString()
width: scrollView.width / 100 * 10 width: scrollView.width / 100 * 15
elide: Text.ElideRight
font.strikeout: index < setting.values.length - 1 && setting.values[index + 1] != "" font.strikeout: index < setting.values.length - 1 && setting.values[index + 1] != ""
opacity: font.strikeout ? 0.5 : 1 opacity: font.strikeout ? 0.5 : 1
} }
@ -174,6 +187,21 @@ UM.ManagementPage
text: model.unit text: model.unit
} }
} }
header: Row {
visible: currentItem.id == Cura.MachineManager.activeQualityId
spacing: UM.Theme.getSize("default_margin").width
Label {
text: catalog.i18nc("@action:label", "Profile:")
width: scrollView.width / 100 * 55
horizontalAlignment: Text.AlignRight
font.bold: true
}
Label {
text: catalog.i18nc("@action:label", "Current:")
visible: currentItem.id == Cura.MachineManager.activeQualityId
font.bold: true
}
}
section.property: "category" section.property: "category"
section.criteria: ViewSection.FullString section.criteria: ViewSection.FullString
section.delegate: Label { section.delegate: Label {
@ -268,7 +296,7 @@ UM.ManagementPage
folder: base.model.getDefaultPath() folder: base.model.getDefaultPath()
onAccepted: onAccepted:
{ {
var result = base.model.exportProfile(base.currentItem.id, fileUrl) var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter)
if(result && result.status == "error") if(result && result.status == "error")
{ {
messageDialog.icon = StandardIcon.Critical messageDialog.icon = StandardIcon.Critical

View File

@ -1,166 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Item{
id: base;
UM.I18nCatalog { id: catalog; name:"cura"}
property int totalHeightProfileSetup: childrenRect.height
property Action manageProfilesAction
property Action addProfileAction
property Action updateProfileAction
property Action resetProfileAction
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
Rectangle{
id: globalProfileRow
anchors.top: base.top
height: UM.Theme.getSize("sidebar_setup").height
width: base.width
Label{
id: globalProfileLabel
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width;
anchors.verticalCenter: parent.verticalCenter
text: catalog.i18nc("@label","Profile:");
width: parent.width/100*45
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
ToolButton {
property int rightMargin: customisedSettings.visible ? customisedSettings.width + UM.Theme.getSize("default_margin").width / 2 : 0
id: globalProfileSelection
text: Cura.MachineManager.activeQualityName
width: parent.width/100*55
height: UM.Theme.getSize("setting_control").height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: profileSelectionMenu
Instantiator
{
id: profileSelectionInstantiator
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "quality" };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
property int separatorIndex: -1
Loader {
property QtObject model_data: model
property int model_index: index
sourceComponent: menuItemDelegate
}
onObjectAdded:
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0) {
if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) {
profileSelectionMenu.insertSeparator(index);
separatorIndex = index;
}
}
//Because of the separator, custom profiles move one index lower
profileSelectionMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item);
}
onObjectRemoved:
{
//When adding a profile, the menu is rebuild by removing all items.
//If a separator was added, we need to remove that too.
if(separatorIndex >= 0)
{
profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex])
separatorIndex = -1;
}
profileSelectionMenu.removeItem(object.item);
}
}
ExclusiveGroup { id: profileSelectionMenuGroup; }
Component
{
id: menuItemDelegate
MenuItem
{
id: item
text: model_data ? model_data.name : ""
checkable: true
checked: Cura.MachineManager.activeQualityId == model_data.id
exclusiveGroup: profileSelectionMenuGroup;
onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
MenuSeparator { }
MenuItem {
action: base.updateProfileAction;
}
MenuItem {
action: base.resetProfileAction;
}
MenuItem {
action: base.addProfileAction;
}
MenuSeparator { }
MenuItem {
action: base.manageProfilesAction;
}
}
}
UM.SimpleButton {
id: customisedSettings
visible: Cura.MachineManager.hasUserSettings
height: parent.height * 0.6
width: parent.height * 0.6
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width
color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
iconSource: UM.Theme.getIcon("star");
onClicked: base.manageProfilesAction.trigger()
onEntered:
{
var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.")
base.showTooltip(globalProfileRow, Qt.point(0, globalProfileRow.height / 2), content)
}
onExited: base.hideTooltip()
}
}
}

View File

@ -56,9 +56,9 @@ Button {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width
visible: hiddenValuesCount > 0 visible: false //hiddenValuesCount > 0
height: parent.height / 2; height: parent.height / 2
width: height; width: height
onClicked: { onClicked: {
base.showAllHiddenInheritedSettings() base.showAllHiddenInheritedSettings()

View File

@ -174,7 +174,7 @@ Item {
break; break;
} }
} }
return state && base.showInheritButton && has_setting_function return state && base.showInheritButton && has_setting_function && typeof(propertyProvider.getPropertyValue("value", base.stackLevels[0])) != "object"
} }
height: parent.height; height: parent.height;
@ -182,22 +182,37 @@ Item {
onClicked: { onClicked: {
focus = true; focus = true;
// Get the deepest entry of this setting that we can find. TODO: This is a bit naive, in some cases
// there might be multiple profiles saying something about the same setting. There is no strategy // Get the most shallow function value (eg not a number) that we can find.
// how to handle this as of yet. var last_entry = propertyProvider.stackLevels[propertyProvider.stackLevels.length]
var last_entry = propertyProvider.stackLevels.slice(-1)[0] for (var i = 1; i < base.stackLevels.length; i++)
// Put that entry into the "top" instance container. {
// This ensures that the value in any of the deeper containers need not be removed, which is var has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object";
// needed for the reset button (which deletes the top value) to correctly go back to profile if(has_setting_function)
// defaults. {
if(last_entry == 4 && base.stackLevel == 0) last_entry = propertyProvider.stackLevels[i]
break;
}
}
if(last_entry == 4 && base.stackLevel == 0 && base.stackLevels.length == 2)
{ {
// Special case of the inherit reset. If only the definition (4th container) and the first // Special case of the inherit reset. If only the definition (4th container) and the first
// entry (user container) are set, we can simply remove the container. // entry (user container) are set, we can simply remove the container.
propertyProvider.removeFromContainer(0) propertyProvider.removeFromContainer(0)
} }
else if(last_entry - 1 == base.stackLevel)
{
// Another special case. The setting that is overriden is only 1 instance container deeper,
// so we can remove it.
propertyProvider.removeFromContainer(0)
}
else else
{ {
// Put that entry into the "top" instance container.
// This ensures that the value in any of the deeper containers need not be removed, which is
// needed for the reset button (which deletes the top value) to correctly go back to profile
// defaults.
propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry))
propertyProvider.setPropertyValue("state", "InstanceState.Calculated") propertyProvider.setPropertyValue("state", "InstanceState.Calculated")
} }

View File

@ -31,6 +31,15 @@ ScrollView
containerId: Cura.MachineManager.activeDefinitionId containerId: Cura.MachineManager.activeDefinitionId
exclude: ["machine_settings"] exclude: ["machine_settings"]
visibilityHandler: UM.SettingPreferenceVisibilityHandler { } visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
filter:
{
if(ExtruderManager.activeExtruderStackId)
{
return { "settable_per_extruder": true }
}
return { }
}
} }
delegate: Loader delegate: Loader
@ -82,7 +91,7 @@ ScrollView
id: provider id: provider
containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId
key: model.key key: model.key ? model.key : ""
watchedProperties: [ "value", "enabled", "state", "validationState" ] watchedProperties: [ "value", "enabled", "state", "validationState" ]
storeIndex: 0 storeIndex: 0
} }

View File

@ -12,13 +12,6 @@ Rectangle
{ {
id: base; id: base;
property Action addMachineAction;
property Action configureMachinesAction;
property Action addProfileAction;
property Action updateProfileAction;
property Action resetProfileAction;
property Action manageProfilesAction;
property Action configureSettingsAction;
property int currentModeIndex; property int currentModeIndex;
color: UM.Theme.getColor("sidebar"); color: UM.Theme.getColor("sidebar");
@ -52,20 +45,8 @@ Rectangle
width: parent.width width: parent.width
height: totalHeightHeader height: totalHeightHeader
addMachineAction: base.addMachineAction; anchors.top: parent.top
configureMachinesAction: base.configureMachinesAction;
}
ProfileSetup {
id: profileItem
addProfileAction: base.addProfileAction
updateProfileAction: base.updateProfileAction
resetProfileAction: base.resetProfileAction
manageProfilesAction: base.manageProfilesAction
anchors.top: header.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
height: totalHeightProfileSetup
onShowTooltip: base.showTooltip(item, location, text) onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip() onHideTooltip: base.hideTooltip()
@ -76,7 +57,7 @@ Rectangle
width: parent.width width: parent.width
height: UM.Theme.getSize("sidebar_lining").height height: UM.Theme.getSize("sidebar_lining").height
color: UM.Theme.getColor("sidebar_lining") color: UM.Theme.getColor("sidebar_lining")
anchors.top: profileItem.bottom anchors.top: header.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
} }

View File

@ -8,54 +8,54 @@ import QtQuick.Controls.Styles 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Item Column
{ {
id: base; id: base;
// Machine Setup
property Action addMachineAction;
property Action configureMachinesAction;
UM.I18nCatalog { id: catalog; name:"cura"}
property int totalHeightHeader: childrenRect.height property int totalHeightHeader: childrenRect.height
property int currentExtruderIndex; property int currentExtruderIndex;
Rectangle { spacing: UM.Theme.getSize("default_margin").height
id: sidebarTabRow
width: base.width
height: 0
anchors.top: parent.top
color: UM.Theme.getColor("sidebar_header_bar")
}
Rectangle { signal showTooltip(Item item, point location, string text)
signal hideTooltip()
Row
{
id: machineSelectionRow id: machineSelectionRow
width: base.width
height: UM.Theme.getSize("sidebar_setup").height height: UM.Theme.getSize("sidebar_setup").height
anchors.top: sidebarTabRow.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.horizontalCenter: parent.horizontalCenter
Label{ anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
}
Label
{
id: machineSelectionLabel id: machineSelectionLabel
//: Machine selection label text: catalog.i18nc("@label:listbox", "Printer:");
text: catalog.i18nc("@label:listbox","Printer:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
} }
ToolButton { ToolButton
{
id: machineSelection id: machineSelection
text: Cura.MachineManager.activeMachineName; text: Cura.MachineManager.activeMachineName;
width: parent.width/100*55
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeMachineName; tooltip: Cura.MachineManager.activeMachineName;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
menu: Menu menu: Menu
{ {
id: machineSelectionMenu id: machineSelectionMenu
@ -81,102 +81,114 @@ Item
MenuSeparator { } MenuSeparator { }
MenuItem { action: base.addMachineAction; } MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: base.configureMachinesAction; } MenuItem { action: Cura.Actions.configureMachines; }
} }
} }
} }
Rectangle { ListView
id: extruderSelection {
width: parent.width/100*55 id: extrudersList
property var index: 0
visible: machineExtruderCount.properties.value > 1 visible: machineExtruderCount.properties.value > 1
height: visible ? UM.Theme.getSize("sidebar_header_mode_toggle").height : 0 height: UM.Theme.getSize("sidebar_header_mode_toggle").height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.top: machineSelectionRow.bottom
anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0
Component{
id: wizardDelegate
Button {
height: extruderSelection.height
anchors.left: parent.left
anchors.leftMargin: model.index * (extruderSelection.width / machineExtruderCount.properties.value)
anchors.verticalCenter: parent.verticalCenter
width: parent.width / machineExtruderCount.properties.value
text: model.name
exclusiveGroup: extruderMenuGroup;
checkable: true;
checked: base.currentExtruderIndex == index
onClicked:
{
base.currentExtruderIndex = index
ExtruderManager.setActiveExtruderIndex(index)
}
style: ButtonStyle { boundsBehavior: Flickable.StopAtBounds
background: Rectangle {
border.width: UM.Theme.getSize("default_lining").width anchors
border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") :
control.pressed ? UM.Theme.getColor("toggle_active_border") :
control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border")
color: control.checked ? UM.Theme.getColor("toggle_checked") :
control.pressed ? UM.Theme.getColor("toggle_active") :
control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
Behavior on color { ColorAnimation { duration: 50; } }
Label {
anchors.centerIn: parent
color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
control.pressed ? UM.Theme.getColor("toggle_active_text") :
control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
font: UM.Theme.getFont("default")
text: control.text;
}
}
label: Item { }
}
}
}
ExclusiveGroup { id: extruderMenuGroup; }
ListView
{ {
id: extrudersList left: parent.left
property var index: 0 leftMargin: UM.Theme.getSize("default_margin").width
model: Cura.ExtrudersModel {} right: parent.right
delegate: wizardDelegate rightMargin: UM.Theme.getSize("default_margin").width
anchors.top: parent.top }
anchors.left: parent.left
width: parent.width ExclusiveGroup { id: extruderMenuGroup; }
orientation: ListView.Horizontal
model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: true }
delegate: Button
{
height: ListView.view.height
width: ListView.view.width / extrudersModel.rowCount()
text: model.name
exclusiveGroup: extruderMenuGroup;
checkable: true;
checked: base.currentExtruderIndex == index
onClicked:
{
focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values.
base.currentExtruderIndex = index;
ExtruderManager.setActiveExtruderIndex(index);
}
style: ButtonStyle
{
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") :
control.pressed ? UM.Theme.getColor("toggle_active_border") :
control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border")
color: control.checked ? UM.Theme.getColor("toggle_checked") :
control.pressed ? UM.Theme.getColor("toggle_active") :
control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
Behavior on color { ColorAnimation { duration: 50; } }
Label
{
anchors.centerIn: parent
color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
control.pressed ? UM.Theme.getColor("toggle_active_text") :
control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
font: UM.Theme.getFont("default")
text: control.text;
}
}
label: Item { }
}
} }
} }
Rectangle { Row
{
id: variantRow id: variantRow
anchors.top: extruderSelection.visible ? extruderSelection.bottom : machineSelectionRow.bottom
anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 height: UM.Theme.getSize("sidebar_setup").height
width: base.width
height: visible ? UM.Theme.getSize("sidebar_setup").height : 0
visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials
Label{ anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
}
Label
{
id: variantLabel id: variantLabel
text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & Material:"): text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & Material:"):
Cura.MachineManager.hasVariants ? catalog.i18nc("@label","Nozzle:") : catalog.i18nc("@label","Material:"); Cura.MachineManager.hasVariants ? catalog.i18nc("@label","Nozzle:") : catalog.i18nc("@label","Material:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*45 width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
} }
Rectangle Rectangle
{ {
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: parent.width/100*55 width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
ToolButton { ToolButton {
@ -213,13 +225,6 @@ Item
onTriggered: onTriggered:
{ {
Cura.MachineManager.setActiveVariant(model.id); Cura.MachineManager.setActiveVariant(model.id);
/*if (typeof(model) !== "undefined" && !model.active) {
//Selecting a variant was canceled; undo menu selection
variantSelectionInstantiator.model.setProperty(index, "active", false);
var activeMachineVariantName = UM.MachineManager.activeMachineVariant;
var activeMachineVariantIndex = variantSelectionInstantiator.model.find("name", activeMachineVariantName);
variantSelectionInstantiator.model.setProperty(activeMachineVariantIndex, "active", true);
}*/
} }
} }
onObjectAdded: variantsSelectionMenu.insertItem(index, object) onObjectAdded: variantsSelectionMenu.insertItem(index, object)
@ -276,13 +281,6 @@ Item
onTriggered: onTriggered:
{ {
Cura.MachineManager.setActiveMaterial(model.id); Cura.MachineManager.setActiveMaterial(model.id);
/*if (typeof(model) !== "undefined" && !model.active) {
//Selecting a material was canceled; undo menu selection
materialSelectionInstantiator.model.setProperty(index, "active", false);
var activeMaterialName = Cura.MachineManager.activeMaterialName
var activeMaterialIndex = materialSelectionInstantiator.model.find("name", activeMaterialName);
materialSelectionInstantiator.model.setProperty(activeMaterialIndex, "active", true);
}*/
} }
} }
onObjectAdded: materialSelectionMenu.insertItem(index, object) onObjectAdded: materialSelectionMenu.insertItem(index, object)
@ -295,6 +293,147 @@ Item
} }
} }
Row
{
id: globalProfileRow
height: UM.Theme.getSize("sidebar_setup").height
anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
}
Label
{
id: globalProfileLabel
text: catalog.i18nc("@label","Profile:");
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
ToolButton
{
id: globalProfileSelection
text: Cura.MachineManager.activeQualityName
width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button
menu: Menu
{
id: profileSelectionMenu
Instantiator
{
id: profileSelectionInstantiator
model: UM.InstanceContainersModel
{
filter:
{
var result = { "type": "quality" };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
}
}
else
{
result.definition = "fdmprinter"
}
return result
}
}
property int separatorIndex: -1
Loader {
property QtObject model_data: model
property int model_index: index
sourceComponent: menuItemDelegate
}
onObjectAdded:
{
//Insert a separator between readonly and custom profiles
if(separatorIndex < 0 && index > 0)
{
if(model.getItem(index-1).readOnly != model.getItem(index).readOnly)
{
profileSelectionMenu.insertSeparator(index);
separatorIndex = index;
}
}
//Because of the separator, custom profiles move one index lower
profileSelectionMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item);
}
onObjectRemoved:
{
//When adding a profile, the menu is rebuilt by removing all items.
//If a separator was added, we need to remove that too.
if(separatorIndex >= 0)
{
profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex])
separatorIndex = -1;
}
profileSelectionMenu.removeItem(object.item);
}
}
ExclusiveGroup { id: profileSelectionMenuGroup; }
Component
{
id: menuItemDelegate
MenuItem
{
id: item
text: model_data ? model_data.name : ""
checkable: true
checked: model_data != null ? Cura.MachineManager.activeQualityId == model_data.id : false
exclusiveGroup: profileSelectionMenuGroup;
onTriggered: Cura.MachineManager.setActiveQuality(model_data.id)
}
}
MenuSeparator { }
MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles }
}
UM.SimpleButton
{
id: customisedSettings
visible: Cura.MachineManager.hasUserSettings
height: parent.height * 0.6
width: parent.height * 0.6
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("default_margin").width
color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
iconSource: UM.Theme.getIcon("star");
onClicked: Cura.Actions.manageProfiles.trigger()
onEntered:
{
var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.")
base.showTooltip(globalProfileRow, Qt.point(0, globalProfileRow.height / 2), content)
}
onExited: base.hideTooltip()
}
}
}
UM.SettingPropertyProvider UM.SettingPropertyProvider
{ {
id: machineExtruderCount id: machineExtruderCount
@ -304,4 +443,6 @@ Item
watchedProperties: [ "value" ] watchedProperties: [ "value" ]
storeIndex: 0 storeIndex: 0
} }
UM.I18nCatalog { id: catalog; name:"cura" }
} }

View File

@ -5,7 +5,7 @@ definition = fdmprinter
[metadata] [metadata]
type = quality type = quality
read_only = True weight = -3
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -5,7 +5,7 @@ definition = fdmprinter
[metadata] [metadata]
type = quality type = quality
read_only = True weight = -1
[values] [values]
infill_sparse_density = 10 infill_sparse_density = 10

View File

@ -5,6 +5,6 @@ definition = fdmprinter
[metadata] [metadata]
type = quality type = quality
read_only = True weight = -2
[values] [values]

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_abs_ultimaker2_extended_plus_0.25_mm material = generic_abs_ultimaker2_extended_plus_0.25_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_abs_ultimaker2_extended_plus_0.4_mm material = generic_abs_ultimaker2_extended_plus_0.4_mm
weight = -1 weight = -1
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_abs_ultimaker2_extended_plus_0.4_mm material = generic_abs_ultimaker2_extended_plus_0.4_mm
weight = -3 weight = -3
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_abs_ultimaker2_extended_plus_0.4_mm material = generic_abs_ultimaker2_extended_plus_0.4_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_abs_ultimaker2_extended_plus_0.6_mm material = generic_abs_ultimaker2_extended_plus_0.6_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_abs_ultimaker2_extended_plus_0.8_mm material = generic_abs_ultimaker2_extended_plus_0.8_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_cpe_ultimaker2_extended_plus_0.25_mm material = generic_cpe_ultimaker2_extended_plus_0.25_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_cpe_ultimaker2_extended_plus_0.4_mm material = generic_cpe_ultimaker2_extended_plus_0.4_mm
weight = -1 weight = -1
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_cpe_ultimaker2_extended_plus_0.4_mm material = generic_cpe_ultimaker2_extended_plus_0.4_mm
weight = -3 weight = -3
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_cpe_ultimaker2_extended_plus_0.4_mm material = generic_cpe_ultimaker2_extended_plus_0.4_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_cpe_ultimaker2_extended_plus_0.6_mm material = generic_cpe_ultimaker2_extended_plus_0.6_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_cpe_ultimaker2_extended_plus_0.8_mm material = generic_cpe_ultimaker2_extended_plus_0.8_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_pla_ultimaker2_extended_plus_0.25_mm material = generic_pla_ultimaker2_extended_plus_0.25_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_pla_ultimaker2_extended_plus_0.4_mm material = generic_pla_ultimaker2_extended_plus_0.4_mm
weight = -1 weight = -1
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_pla_ultimaker2_extended_plus_0.4_mm material = generic_pla_ultimaker2_extended_plus_0.4_mm
weight = -3 weight = -3
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
type = quality type = quality
material = generic_pla_ultimaker2_extended_plus_0.4_mm material = generic_pla_ultimaker2_extended_plus_0.4_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
material = generic_pla_ultimaker2_extended_plus_0.6_mm material = generic_pla_ultimaker2_extended_plus_0.6_mm
type = quality type = quality
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus
material = generic_pla_ultimaker2_extended_plus_0.8_mm material = generic_pla_ultimaker2_extended_plus_0.8_mm
type = quality type = quality
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_pla_ultimaker2_plus_0.25_mm material = generic_pla_ultimaker2_plus_0.25_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_pla_ultimaker2_plus_0.4_mm material = generic_pla_ultimaker2_plus_0.4_mm
weight = -1 weight = -1
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_pla_ultimaker2_plus_0.4_mm material = generic_pla_ultimaker2_plus_0.4_mm
weight = -3 weight = -3
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_pla_ultimaker2_plus_0.4_mm material = generic_pla_ultimaker2_plus_0.4_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
material = generic_pla_ultimaker2_plus_0.6_mm material = generic_pla_ultimaker2_plus_0.6_mm
type = quality type = quality
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
material = generic_pla_ultimaker2_plus_0.8_mm material = generic_pla_ultimaker2_plus_0.8_mm
type = quality type = quality
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_abs_ultimaker2_plus_0.25_mm material = generic_abs_ultimaker2_plus_0.25_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_abs_ultimaker2_plus_0.4_mm material = generic_abs_ultimaker2_plus_0.4_mm
weight = -1 weight = -1
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_abs_ultimaker2_plus_0.4_mm material = generic_abs_ultimaker2_plus_0.4_mm
weight = -3 weight = -3
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_abs_ultimaker2_plus_0.4_mm material = generic_abs_ultimaker2_plus_0.4_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_abs_ultimaker2_plus_0.6_mm material = generic_abs_ultimaker2_plus_0.6_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_abs_ultimaker2_plus_0.8_mm material = generic_abs_ultimaker2_plus_0.8_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_cpe_ultimaker2_plus_0.25_mm material = generic_cpe_ultimaker2_plus_0.25_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_cpe_ultimaker2_plus_0.4_mm material = generic_cpe_ultimaker2_plus_0.4_mm
weight = -1 weight = -1
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_cpe_ultimaker2_plus_0.4_mm material = generic_cpe_ultimaker2_plus_0.4_mm
weight = -3 weight = -3
read_only = True
[values] [values]
layer_height = 0.06 layer_height = 0.06

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_cpe_ultimaker2_plus_0.4_mm material = generic_cpe_ultimaker2_plus_0.4_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_cpe_ultimaker2_plus_0.6_mm material = generic_cpe_ultimaker2_plus_0.6_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.15 layer_height = 0.15

View File

@ -7,7 +7,6 @@ definition = ultimaker2_plus
type = quality type = quality
material = generic_cpe_ultimaker2_plus_0.8_mm material = generic_cpe_ultimaker2_plus_0.8_mm
weight = -2 weight = -2
read_only = True
[values] [values]
layer_height = 0.2 layer_height = 0.2