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
.idea
# Eclipse+PyDev
.project
.pydevproject
.settings
# 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.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
class ContainerSettingsModel(ListModel):
LabelRole = Qt.UserRole + 1
@ -20,33 +21,12 @@ class ContainerSettingsModel(ListModel):
self.addRoleName(self.ValuesRole, "values")
self._container_ids = []
self._container = None
self._containers = []
self._global_container_stack = None
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):
def _onPropertyChanged(self, key, property_name):
if property_name == "value":
self._update()
def _onInstanceContainersChanged(self, container):
self._update()
def _update(self):
self.clear()
@ -54,24 +34,17 @@ class ContainerSettingsModel(ListModel):
return
keys = []
containers = []
for container_id in self._container_ids:
container = ContainerRegistry.getInstance().findContainers(id = container_id)
if not container:
return
for container in self._containers:
keys = keys + list(container.getAllKeys())
keys = keys + list(container[0].getAllKeys())
containers.append(container[0])
keys = list(set(keys))
keys = list(set(keys)) # remove duplicate keys
keys.sort()
for key in keys:
definition = None
category = None
values = []
for container in containers:
for container in self._containers:
instance = container.getInstance(key)
if instance:
definition = instance.definition
@ -81,7 +54,11 @@ class ContainerSettingsModel(ListModel):
while category.type != "category":
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:
values.append("")
@ -93,9 +70,21 @@ class ContainerSettingsModel(ListModel):
"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):
for container in self._containers:
container.propertyChanged.disconnect(self._onPropertyChanged)
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()
containersChanged = pyqtSignal()

View File

@ -93,8 +93,11 @@ class CuraApplication(QtApplication):
self._open_file_queue = [] # Files to open when plug-ins are loaded.
# Need to do this before ContainerRegistry tries to load the machines
SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False)
SettingDefinition.addSettingType("extruder", str, ast.literal_eval, UM.Settings.Validator)
SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True)
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)
@ -291,6 +294,7 @@ class CuraApplication(QtApplication):
# \sa PluginRegistery
def _loadPlugins(self):
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"))
if not hasattr(sys, "frozen"):
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):
# TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles.
pass
def _addProfileWriter(self, profile_writer):
pass

View File

@ -36,7 +36,7 @@ class ExtruderManager(QObject):
if not UM.Application.getInstance().getGlobalContainerStack():
return None #No active machine, so no active extruder.
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.
return None
@ -58,11 +58,22 @@ class ExtruderManager(QObject):
cls.__instance = ExtruderManager()
return cls.__instance
## Changes the active extruder by index.
#
# \param index The index of the new active extruder.
@pyqtSlot(int)
def setActiveExtruderIndex(self, index):
self._active_extruder_index = index
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
# manager.
#
@ -87,7 +98,7 @@ class ExtruderManager(QObject):
#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())
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:
self.extrudersChanged.emit(machine_definition)
@ -188,21 +199,17 @@ class ExtruderManager(QObject):
container_registry.addContainer(container_stack)
## Generates extruders for a specific machine.
def getMachineExtruders(self, machine_definition):
container_registry = UM.Settings.ContainerRegistry.getInstance()
machine_id = machine_definition.getId()
if not machine_id in self._extruder_trains:
#
# \param machine_id The machine to get the extruders of.
def getMachineExtruders(self, machine_id):
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)
return
for _,extruder_train_id in self._extruder_trains[machine_id].items():
extruder_train = container_registry.findContainerStacks(id = extruder_train_id)
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)
for name in self._extruder_trains[machine_id]:
yield self._extruder_trains[machine_id][name]
## Adds the extruders of the currently active machine.
def _addCurrentMachineExtruders(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
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.
# 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 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
# settings.
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.
NameRole = Qt.UserRole + 1
NameRole = Qt.UserRole + 2
## 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.
#
# 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
# 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
# changes in the data.
@ -32,16 +39,30 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
def __init__(self, parent = None):
super().__init__(parent)
self.addRoleName(self.IdRole, "id")
self.addRoleName(self.NameRole, "name")
self.addRoleName(self.ColourRole, "colour")
self.addRoleName(self.IndexRole, "index")
self._add_global = False
#Listen to changes.
manager = cura.ExtruderManager.ExtruderManager.getInstance()
manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general.
UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes.
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.
#
# 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()
if not global_container_stack:
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" })
colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00"
item = { #Construct an item with only the relevant information.
"name": extruder.getName(),
if self._add_global:
material = global_container_stack.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour
item = {
"id": global_container_stack.getId(),
"name": "Global",
"colour": colour,
"index": index
"index": -1
}
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 UM.Application import Application
from UM.Preferences import Preferences
from UM.Logger import Logger
import UM.Settings
from UM.Settings.Validator import ValidatorState
@ -14,6 +13,7 @@ from . import ExtruderManager
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class MachineManagerModel(QObject):
def __init__(self, parent = None):
super().__init__(parent)
@ -41,7 +41,6 @@ class MachineManagerModel(QObject):
self.setActiveMachine(active_machine_id)
pass
globalContainerChanged = pyqtSignal()
activeMaterialChanged = pyqtSignal()
activeVariantChanged = pyqtSignal()
@ -114,8 +113,8 @@ class MachineManagerModel(QObject):
UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack)
variant_instance_container = self._updateVariantContainer(definition)
material_instance_container = self._updateMaterialContainer(definition)
quality_instance_container = self._updateQualityContainer(definition)
material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
quality_instance_container = self._updateQualityContainer(definition, material_instance_container)
current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
current_settings_instance_container.addMetaDataEntry("machine", name)
@ -266,41 +265,21 @@ class MachineManagerModel(QObject):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
if not containers or not self._global_container_stack:
return True
return containers[0].getMetaDataEntry("read_only", False) == "True"
return containers[0].isReadOnly()
@pyqtSlot(result = str)
def convertUserContainerToQuality(self):
if not self._global_container_stack:
def newQualityContainerFromQualityAndUser(self):
new_container_id = self.duplicateContainer(self.activeQualityId)
if new_container_id == "":
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)
def duplicateContainer(self, container_id):
if not self._global_container_stack:
return
return ""
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id)
if containers:
new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile"))
@ -310,7 +289,7 @@ class MachineManagerModel(QObject):
## Copy all values
new_container.deserialize(containers[0].serialize())
new_container.setMetaDataEntry("read_only", False)
new_container.setReadOnly(False)
new_container.setName(new_name)
new_container._id = new_name
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
@ -318,15 +297,36 @@ class MachineManagerModel(QObject):
return ""
@pyqtSlot(str, str)
def renameQualityContainer(self, container_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality")
if containers:
new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile"))
containers[0].setName(new_name)
self.activeQualityChanged.emit()
new_name = self._createUniqueName("quality", containers[0].getName(), new_name,
catalog.i18nc("@label", "Custom profile"))
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)
def removeQualityContainer(self, container_id):
@ -348,7 +348,7 @@ class MachineManagerModel(QObject):
@pyqtSlot()
def updateUserContainerToQuality(self):
def updateQualityContainerFromUserContainer(self):
if not self._global_container_stack:
return
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.
# 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.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
import UM.Logger
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
# 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.
@signalemitter
class SettingOverrideDecorator(SceneNodeDecorator):
## Event indicating that the user selected a different extruder.
activeExtruderChanged = Signal()
def __init__(self):
super().__init__()
self._stack = ContainerStack(stack_id = id(self))
self._stack.setDirty(False) # This stack does not need to be saved.
self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer")
self._stack.addContainer(self._instance)
self._extruder_stack = None #Stack upon which our stack is based.
self._stack.propertyChanged.connect(self._onSettingChanged)
ContainerRegistry.getInstance().addContainer(self._stack)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
self._onGlobalContainerStackChanged()
Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack)
self.activeExtruderChanged.connect(self._updateNextStack)
self._updateNextStack()
def __deepcopy__(self, memo):
## Create a fresh decorator object
@ -35,13 +45,34 @@ class SettingOverrideDecorator(SceneNodeDecorator):
deep_copy._stack.replaceContainer(0, deep_copy._instance)
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):
if property == "value": # Only reslice if the value has changed.
Application.getInstance().getBackend().forceSlice()
def _onGlobalContainerStackChanged(self):
## Ensure that the next stack is always the global stack.
self._stack.setNextStack(Application.getInstance().getGlobalContainerStack())
## Makes sure that the stack upon which the container stack is placed is
# kept up to date.
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):
return self._stack

View File

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

View File

@ -5,12 +5,20 @@ package cura.proto;
message ObjectList
{
repeated Object objects = 1;
repeated Setting settings = 2;
repeated Setting settings = 2; // meshgroup settings (for one-at-a-time printing)
}
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
@ -29,10 +37,10 @@ message Progress
message Layer {
int32 id = 1;
float height = 2;
float thickness = 3;
float height = 2; // Z position
float thickness = 3; // height of a single layer
repeated Polygon polygons = 4;
repeated Polygon polygons = 4; // layer data
}
message Polygon {
@ -48,19 +56,19 @@ message Polygon {
MoveCombingType = 8;
MoveRetractionType = 9;
}
Type type = 1;
bytes points = 2;
float line_width = 3;
Type type = 1; // Type of move
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; // The width of the line being laid down
}
message GCodeLayer {
bytes data = 2;
}
message ObjectPrintTime {
message ObjectPrintTime { // The print time for the whole print and material estimates for the first extruder
int64 id = 1;
float time = 2;
float material_amount = 3;
float time = 2; // Total time estimate
float material_amount = 3; // material used in the first extruder
}
message SettingList {
@ -68,13 +76,13 @@ message SettingList {
}
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 {
bytes data = 2;
bytes data = 2; // Header string to be prenpended before the rest of the gcode sent from the engine
}
message SlicingFinished {

View File

@ -12,6 +12,8 @@ from UM.PluginRegistry import PluginRegistry
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 cura.ExtruderManager import ExtruderManager
from cura.OneAtATimeIterator import OneAtATimeIterator
from . import ProcessSlicedLayersJob
from . import ProcessGCodeJob
@ -59,6 +61,10 @@ class CuraEngineBackend(Backend):
Application.getInstance().globalContainerStackChanged.connect(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.
#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.
@ -145,8 +151,7 @@ class CuraEngineBackend(Backend):
self.slicingStarted.emit()
slice_message = self._socket.createMessage("cura.proto.Slice")
settings_message = self._socket.createMessage("cura.proto.SettingList")
self._start_slice_job = StartSliceJob.StartSliceJob(slice_message, settings_message)
self._start_slice_job = StartSliceJob.StartSliceJob(slice_message)
self._start_slice_job.start()
self._start_slice_job.finished.connect(self._onStartSliceCompleted)
@ -205,7 +210,6 @@ class CuraEngineBackend(Backend):
return
# Preparation completed, send it to the backend.
self._socket.sendMessage(job.getSettingsMessage())
self._socket.sendMessage(job.getSliceMessage())
## Listener for when the scene has changed.
@ -369,4 +373,16 @@ class CuraEngineBackend(Backend):
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.containersChanged.connect(self._onChanged)
self._onActiveExtruderChanged()
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 cura.OneAtATimeIterator import OneAtATimeIterator
from cura.ExtruderManager import ExtruderManager
class StartJobResult(IntEnum):
Finished = 1
@ -37,17 +38,13 @@ class GcodeStartEndFormatter(Formatter):
## Job class that builds up the message of scene data to send to CuraEngine.
class StartSliceJob(Job):
def __init__(self, slice_message, settings_message):
def __init__(self, slice_message):
super().__init__()
self._scene = Application.getInstance().getController().getScene()
self._slice_message = slice_message
self._settings_message = settings_message
self._is_cancelled = False
def getSettingsMessage(self):
return self._settings_message
def getSliceMessage(self):
return self._slice_message
@ -131,6 +128,9 @@ class StartSliceJob(Job):
self._buildGlobalSettingsMessage(stack)
for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()):
self._buildExtruderMessage(extruder_stack)
for group in object_groups:
group_message = self._slice_message.addRepeatedMessage("object_lists")
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")
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.
#
# 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
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
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)
@ -193,21 +202,10 @@ class StartSliceJob(Job):
setting_message.value = str(value).encode("utf-8")
def _handlePerObjectSettings(self, node, message):
profile = node.callDecoration("getProfile")
if profile:
for key, value in profile.getAllSettingValues().items():
stack = node.callDecoration("getStack")
if stack:
for key in stack.getAllKeys():
setting = message.addRepeatedMessage("settings")
setting.name = key
setting.value = str(value).encode()
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()
setting.value = str(stack.getProperty(key, "value")).encode("utf-8")
Job.yieldThread()

View File

@ -1,11 +1,12 @@
# Copyright (c) 2015 Ultimaker B.V.
# 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.Logger import Logger
from UM.Settings.Profile import Profile
from UM.Settings.ProfileReader import ProfileReader
from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make.
from cura.ProfileReader import ProfileReader
## A plugin that reads profile data from Cura profile files.
#
@ -25,17 +26,17 @@ class CuraProfileReader(ProfileReader):
# returned.
def read(self, file_name):
# Create an empty profile.
profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False)
serialised = ""
profile = InstanceContainer(os.path.basename(os.path.splitext(file_name)[0]))
profile.addMetaDataEntry("type", "quality")
try:
with open(file_name) as f: # Open file for reading.
serialised = f.read()
serialized = f.read()
except IOError as e:
Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e))
return None
try:
profile.unserialise(serialised)
profile.deserialize(serialized)
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))
return None

View File

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

View File

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

View File

@ -13,7 +13,7 @@ def getMetaData():
"author": "Ultimaker",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."),
"api": 2
"api": 3
},
"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.
import QtQuick 2.2
@ -26,6 +26,99 @@ Item {
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
{
id: contents
@ -190,11 +283,11 @@ Item {
{
if(text != "")
{
listview.model.filter = {"global_only": false, "label": "*" + text}
listview.model.filter = {"settable_per_mesh": true, "label": "*" + text}
}
else
{
listview.model.filter = {"global_only": false}
listview.model.filter = {"settable_per_mesh": true}
}
}
}
@ -219,7 +312,7 @@ Item {
containerId: Cura.MachineManager.activeDefinitionId
filter:
{
"global_only": false
"settable_per_mesh": true
}
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.
from UM.Tool import Tool
from UM.Scene.Selection import Selection
from UM.Application import Application
from UM.Preferences import Preferences
from cura.SettingOverrideDecorator import SettingOverrideDecorator
## 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.
@ -14,7 +14,7 @@ class PerObjectSettingsTool(Tool):
super().__init__()
self._model = None
self.setExposedProperties("SelectedObjectId", "ContainerID")
self.setExposedProperties("SelectedObjectId", "ContainerID", "SelectedActiveExtruder")
Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged)
Selection.selectionChanged.connect(self.propertyChanged)
@ -42,6 +42,24 @@ class PerObjectSettingsTool(Tool):
except AttributeError:
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):
if preference == "cura/active_mode":
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.",
"type": "extruder",
"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":
{
@ -33,7 +37,10 @@
"type": "float",
"unit": "mm",
"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":
{
@ -42,7 +49,10 @@
"type": "float",
"unit": "mm",
"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":
{
@ -50,7 +60,10 @@
"description": "Start g-code to execute whenever turning the extruder on.",
"type": "str",
"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":
{
@ -58,7 +71,10 @@
"description": "Make the extruder starting position absolute rather than relative to the last-known location of the head.",
"type": "bool",
"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":
{
@ -67,7 +83,10 @@
"type": "float",
"unit": "mm",
"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":
{
@ -76,7 +95,10 @@
"type": "float",
"unit": "mm",
"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":
{
@ -84,7 +106,10 @@
"description": "End g-code to execute whenever turning the extruder off.",
"type": "str",
"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":
{
@ -92,7 +117,10 @@
"description": "Make the extruder ending position absolute rather than relative to the last-known location of the head.",
"type": "bool",
"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":
{
@ -101,7 +129,10 @@
"type": "float",
"unit": "mm",
"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":
{
@ -110,7 +141,10 @@
"type": "float",
"unit": "mm",
"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;
enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile");
onTriggered: Cura.MachineManager.updateUserContainerToQuality()
text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings");
onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer()
}
Action
{
id: resetProfileAction;
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();
}
Action
{
id: addProfileAction;
enabled: Cura.MachineManager.isGlobalStackValid
text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile...");
enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Create profile from current settings...");
}
Action

View File

@ -258,13 +258,13 @@ UM.MainWindow
{
//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) {
if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) {
profileMenu.insertSeparator(index);
separatorIndex = index;
}
}
//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:
{
@ -297,11 +297,11 @@ UM.MainWindow
MenuSeparator { id: profileMenuSeparator }
MenuItem { action: Cura.Actions.updateProfile; }
MenuItem { action: Cura.Actions.resetProfile; }
MenuItem { action: Cura.Actions.addProfile; }
MenuItem { action: Cura.Actions.addProfile }
MenuItem { action: Cura.Actions.updateProfile }
MenuItem { action: Cura.Actions.resetProfile }
MenuSeparator { }
MenuItem { action: Cura.Actions.manageProfiles; }
MenuItem { action: Cura.Actions.manageProfiles }
}
Menu
@ -533,13 +533,6 @@ UM.MainWindow
}
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
onTriggered:
{
Cura.MachineManager.convertUserContainerToQuality();
Cura.MachineManager.newQualityContainerFromQualityAndUser();
preferences.setPage(5);
preferences.show();

View File

@ -13,7 +13,7 @@ UM.ManagementPage
id: base;
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
{
@ -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
activeIndex: {
for(var i = 0; i < model.rowCount(); i++) {
@ -49,9 +64,8 @@ UM.ManagementPage
onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id)
onAddObject: {
var selectedContainer;
if (objectList.currentIndex == 0) {
// Current settings
selectedContainer = Cura.MachineManager.convertUserContainerToQuality();
if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) {
selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser();
} else {
selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id);
}
@ -66,8 +80,8 @@ UM.ManagementPage
activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false;
addEnabled: currentItem != null;
removeEnabled: currentItem != null ? !currentItem.metadata.read_only : false;
renameEnabled: currentItem != null ? !currentItem.metadata.read_only : false;
removeEnabled: currentItem != null ? !currentItem.readOnly : false;
renameEnabled: currentItem != null ? !currentItem.readOnly : false;
scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName)
@ -102,17 +116,15 @@ UM.ManagementPage
Button
{
text: {
var profileName = Cura.MachineManager.activeQualityName;
profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName;
return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName));
return catalog.i18nc("@action:button", "Update profile with current settings");
}
enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
onClicked: Cura.MachineManager.updateUserContainerToQuality()
onClicked: Cura.MachineManager.updateQualityContainerFromUserContainer()
}
Button
{
text: catalog.i18nc("@action:button", "Discard changes");
text: catalog.i18nc("@action:button", "Discard current settings");
enabled: Cura.MachineManager.hasUserSettings
onClicked: Cura.MachineManager.clearUserSettings();
}
@ -128,7 +140,7 @@ UM.ManagementPage
Label {
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.")
wrapMode: Text.WordWrap
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] }
delegate: Row {
property variant setting: model
spacing: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").width/2
Label {
text: model.label
elide: Text.ElideMiddle
@ -165,7 +177,8 @@ UM.ManagementPage
model: setting.values.length
Label {
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] != ""
opacity: font.strikeout ? 0.5 : 1
}
@ -174,6 +187,21 @@ UM.ManagementPage
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.criteria: ViewSection.FullString
section.delegate: Label {
@ -268,7 +296,7 @@ UM.ManagementPage
folder: base.model.getDefaultPath()
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")
{
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.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width
visible: hiddenValuesCount > 0
height: parent.height / 2;
width: height;
visible: false //hiddenValuesCount > 0
height: parent.height / 2
width: height
onClicked: {
base.showAllHiddenInheritedSettings()

View File

@ -174,7 +174,7 @@ Item {
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;
@ -182,22 +182,37 @@ Item {
onClicked: {
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
// how to handle this as of yet.
var last_entry = propertyProvider.stackLevels.slice(-1)[0]
// 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.
if(last_entry == 4 && base.stackLevel == 0)
// Get the most shallow function value (eg not a number) that we can find.
var last_entry = propertyProvider.stackLevels[propertyProvider.stackLevels.length]
for (var i = 1; i < base.stackLevels.length; i++)
{
var has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object";
if(has_setting_function)
{
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
// entry (user container) are set, we can simply remove the container.
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
{
// 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("state", "InstanceState.Calculated")
}

View File

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

View File

@ -12,13 +12,6 @@ Rectangle
{
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;
color: UM.Theme.getColor("sidebar");
@ -52,20 +45,8 @@ Rectangle
width: parent.width
height: totalHeightHeader
addMachineAction: base.addMachineAction;
configureMachinesAction: base.configureMachinesAction;
}
ProfileSetup {
id: profileItem
addProfileAction: base.addProfileAction
updateProfileAction: base.updateProfileAction
resetProfileAction: base.resetProfileAction
manageProfilesAction: base.manageProfilesAction
anchors.top: header.bottom
anchors.top: parent.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
height: totalHeightProfileSetup
onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
@ -76,7 +57,7 @@ Rectangle
width: parent.width
height: UM.Theme.getSize("sidebar_lining").height
color: UM.Theme.getColor("sidebar_lining")
anchors.top: profileItem.bottom
anchors.top: header.bottom
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 Cura 1.0 as Cura
Item
Column
{
id: base;
// Machine Setup
property Action addMachineAction;
property Action configureMachinesAction;
UM.I18nCatalog { id: catalog; name:"cura"}
property int totalHeightHeader: childrenRect.height
property int currentExtruderIndex;
Rectangle {
id: sidebarTabRow
width: base.width
height: 0
anchors.top: parent.top
color: UM.Theme.getColor("sidebar_header_bar")
}
spacing: UM.Theme.getSize("default_margin").height
Rectangle {
signal showTooltip(Item item, point location, string text)
signal hideTooltip()
Row
{
id: machineSelectionRow
width: base.width
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
//: Machine selection label
text: catalog.i18nc("@label:listbox","Printer:");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label:listbox", "Printer:");
anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
}
ToolButton {
ToolButton
{
id: machineSelection
text: Cura.MachineManager.activeMachineName;
width: parent.width/100*55
height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeMachineName;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
style: UM.Theme.styles.sidebar_header_button
width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width
menu: Menu
{
id: machineSelectionMenu
@ -81,102 +81,114 @@ Item
MenuSeparator { }
MenuItem { action: base.addMachineAction; }
MenuItem { action: base.configureMachinesAction; }
MenuItem { action: Cura.Actions.addMachine; }
MenuItem { action: Cura.Actions.configureMachines; }
}
}
}
Rectangle {
id: extruderSelection
width: parent.width/100*55
ListView
{
id: extrudersList
property var index: 0
visible: machineExtruderCount.properties.value > 1
height: visible ? UM.Theme.getSize("sidebar_header_mode_toggle").height : 0
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)
}
height: UM.Theme.getSize("sidebar_header_mode_toggle").height
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 { }
}
}
}
ExclusiveGroup { id: extruderMenuGroup; }
ListView
boundsBehavior: Flickable.StopAtBounds
anchors
{
id: extrudersList
property var index: 0
model: Cura.ExtrudersModel {}
delegate: wizardDelegate
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").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
anchors.top: extruderSelection.visible ? extruderSelection.bottom : machineSelectionRow.bottom
anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0
width: base.width
height: visible ? UM.Theme.getSize("sidebar_setup").height : 0
height: UM.Theme.getSize("sidebar_setup").height
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
text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & 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
width: parent.width/100*45
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
Rectangle
{
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
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
ToolButton {
@ -213,13 +225,6 @@ Item
onTriggered:
{
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)
@ -276,13 +281,6 @@ Item
onTriggered:
{
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)
@ -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
{
id: machineExtruderCount
@ -304,4 +443,6 @@ Item
watchedProperties: [ "value" ]
storeIndex: 0
}
UM.I18nCatalog { id: catalog; name:"cura" }
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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