mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-30 00:55:12 +08:00
Merge remote-tracking branch 'Ultimaker/master' into master-layerview-use-resetLayerData
This commit is contained in:
commit
7043a04e22
5
.gitignore
vendored
5
.gitignore
vendored
@ -16,8 +16,11 @@ resources/firmware
|
||||
*~
|
||||
*.qm
|
||||
.idea
|
||||
|
||||
# Eclipse+PyDev
|
||||
.project
|
||||
.pydevproject
|
||||
.settings
|
||||
|
||||
# Debian packaging
|
||||
debian/
|
||||
debian*
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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"])
|
||||
|
@ -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
25
cura/ProfileWriter.py
Normal 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.")
|
@ -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
|
@ -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")
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
@ -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()
|
@ -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
|
||||
|
@ -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": [
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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": [
|
||||
{
|
||||
|
@ -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 {}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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" }
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ definition = fdmprinter
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
read_only = True
|
||||
weight = -3
|
||||
|
||||
[values]
|
||||
layer_height = 0.06
|
||||
|
@ -5,7 +5,7 @@ definition = fdmprinter
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
read_only = True
|
||||
weight = -1
|
||||
|
||||
[values]
|
||||
infill_sparse_density = 10
|
||||
|
@ -5,6 +5,6 @@ definition = fdmprinter
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
read_only = True
|
||||
weight = -2
|
||||
|
||||
[values]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user