Merge branch 'master' into cura_containerstack

This commit is contained in:
Ghostkeeper 2017-05-03 15:21:01 +02:00
commit c42d092b0f
No known key found for this signature in database
GPG key ID: C5F96EE2BC0F7E75
24 changed files with 1157 additions and 472 deletions

View file

@ -108,6 +108,7 @@ class CuraApplication(QtApplication):
UserInstanceContainer = Resources.UserType + 6
MachineStack = Resources.UserType + 7
ExtruderStack = Resources.UserType + 8
DefinitionChangesContainer = Resources.UserType + 9
Q_ENUMS(ResourceTypes)
@ -153,6 +154,7 @@ class CuraApplication(QtApplication):
Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user")
Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances")
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.VariantInstanceContainer)
@ -160,6 +162,7 @@ class CuraApplication(QtApplication):
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack)
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.DefinitionChangesContainer)
## Initialise the version upgrade manager with Cura's storage paths.
import UM.VersionUpgradeManager #Needs to be here to prevent circular dependencies.
@ -415,7 +418,7 @@ class CuraApplication(QtApplication):
elif instance_type == "variant":
path = Resources.getStoragePath(self.ResourceTypes.VariantInstanceContainer, file_name)
elif instance_type == "definition_changes":
path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name)
path = Resources.getStoragePath(self.ResourceTypes.DefinitionChangesContainer, file_name)
if path:
instance.setPath(path)

View file

@ -144,6 +144,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
items.append(item)
changed = True
machine_extruder_count = global_container_stack.getProperty("machine_extruder_count", "value")
manager = ExtruderManager.getInstance()
for extruder in manager.getMachineExtruders(global_container_stack.getId()):
extruder_name = extruder.getName()
@ -154,6 +155,9 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
position = int(position)
except ValueError: #Not a proper int.
position = -1
if position >= machine_extruder_count:
continue
default_color = self.defaultColors[position] if position >= 0 and position < len(self.defaultColors) else self.defaultColors[0]
color = material.getMetaDataEntry("color_code", default = default_color) if material else default_color
item = { #Construct an item with only the relevant information.

View file

@ -495,6 +495,17 @@ class MachineManager(QObject):
return result
@pyqtProperty("QVariantList", notify = activeVariantChanged)
def activeMaterialIds(self):
result = []
if ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks() is not None:
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
variant_container = stack.findContainer({"type": "variant"})
if variant_container and variant_container != self._empty_variant_container:
result.append(variant_container.getId())
return result
@pyqtProperty("QVariantList", notify = activeMaterialChanged)
def activeMaterialNames(self):
result = []

View file

@ -13,9 +13,9 @@ from UM.Resources import Resources
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
from UM.Platform import Platform
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Qt.Duration import DurationFormat
from PyQt5.QtCore import QObject, pyqtSlot
from cura.Settings.ExtruderManager import ExtruderManager
from . import ProcessSlicedLayersJob
from . import StartSliceJob
@ -442,6 +442,15 @@ class CuraEngineBackend(QObject, Backend):
self.backendStateChange.emit(BackendState.Done)
self.processingProgress.emit(1.0)
for line in self._scene.gcode_list:
replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601)))
replaced = replaced.replace("{filament_amount}", str(Application.getInstance().getPrintInformation().materialLengths))
replaced = replaced.replace("{filament_weight}", str(Application.getInstance().getPrintInformation().materialWeights))
replaced = replaced.replace("{filament_cost}", str(Application.getInstance().getPrintInformation().materialCosts))
replaced = replaced.replace("{jobname}", str(Application.getInstance().getPrintInformation().jobName))
self._scene.gcode_list[self._scene.gcode_list.index(line)] = replaced
self._slicing = False
self._need_slicing = False
Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time )

View file

@ -4,6 +4,7 @@
import numpy
from string import Formatter
from enum import IntEnum
import time
from UM.Job import Job
from UM.Application import Application
@ -240,6 +241,13 @@ class StartSliceJob(Job):
print_temperature_settings = {"material_print_temperature", "material_print_temperature_layer_0", "default_material_print_temperature", "material_initial_print_temperature", "material_final_print_temperature", "material_standby_temperature"}
settings["material_print_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in print_temperature_settings))
settings["print_bed_temperature"] = settings["material_bed_temperature"]
settings["print_temperature"] = settings["material_print_temperature"]
settings["time"] = time.strftime('%H:%M:%S')
settings["date"] = time.strftime('%d-%m-%Y')
settings["day"] = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][int(time.strftime('%w'))]
for key, value in settings.items(): #Add all submessages for each individual setting.
setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
setting_message.name = key

247
plugins/MachineSettingsAction/MachineSettingsAction.py Normal file → Executable file
View file

@ -7,12 +7,15 @@ from UM.FlameProfiler import pyqtSlot
from cura.MachineAction import MachineAction
from UM.Application import Application
from UM.Preferences import Preferences
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Logger import Logger
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
from cura.Settings.ExtruderManager import ExtruderManager
import UM.i18n
catalog = UM.i18n.i18nCatalog("cura")
@ -25,36 +28,81 @@ class MachineSettingsAction(MachineAction):
super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
self._qml_url = "MachineSettingsAction.qml"
self._global_container_stack = None
self._container_index = 0
self._extruder_container_index = 0
self._container_registry = ContainerRegistry.getInstance()
self._container_registry.containerAdded.connect(self._onContainerAdded)
self._container_registry.containerRemoved.connect(self._onContainerRemoved)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
self._backend = Application.getInstance().getBackend()
def _onContainerAdded(self, container):
# Add this action as a supported action to all machine definitions
if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
def _onContainerRemoved(self, container):
# Remove definition_changes containers when a stack is removed
if container.getMetaDataEntry("type") in ["machine", "extruder_train"]:
definition_changes_container = container.findContainer({"type": "definition_changes"})
if not definition_changes_container:
return
self._container_registry.removeContainer(definition_changes_container.getId())
def _reset(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if not global_container_stack:
if not self._global_container_stack:
return
# Make sure there is a definition_changes container to store the machine settings
definition_changes_container = global_container_stack.findContainer({"type": "definition_changes"})
definition_changes_container = self._global_container_stack.findContainer({"type": "definition_changes"})
if not definition_changes_container:
definition_changes_container = self._createDefinitionChangesContainer(global_container_stack)
definition_changes_container = self._createDefinitionChangesContainer(self._global_container_stack, self._global_container_stack.getName() + "_settings")
# Notify the UI in which container to store the machine settings data
container_index = global_container_stack.getContainerIndex(definition_changes_container)
container_index = self._global_container_stack.getContainerIndex(definition_changes_container)
if container_index != self._container_index:
self._container_index = container_index
self.containerIndexChanged.emit()
def _createDefinitionChangesContainer(self, global_container_stack, container_index = None):
definition_changes_container = InstanceContainer(global_container_stack.getName() + "_settings")
definition = global_container_stack.getBottom()
# Disable autoslicing while the machineaction is showing
self._backend.disableTimer()
@pyqtSlot()
def onFinishAction(self):
# Restore autoslicing when the machineaction is dismissed
if self._backend.determineAutoSlicing():
self._backend.tickle()
def _onActiveExtruderStackChanged(self):
extruder_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if not self._global_container_stack or not extruder_container_stack:
return
# Make sure there is a definition_changes container to store the machine settings
definition_changes_container = extruder_container_stack.findContainer({"type": "definition_changes"})
if not definition_changes_container:
definition_changes_container = self._createDefinitionChangesContainer(extruder_container_stack, extruder_container_stack.getId() + "_settings")
# Notify the UI in which container to store the machine settings data
container_index = extruder_container_stack.getContainerIndex(definition_changes_container)
if container_index != self._extruder_container_index:
self._extruder_container_index = container_index
self.extruderContainerIndexChanged.emit()
def _createDefinitionChangesContainer(self, container_stack, container_name, container_index = None):
definition_changes_container = InstanceContainer(container_name)
definition = container_stack.getBottom()
definition_changes_container.setDefinition(definition)
definition_changes_container.addMetaDataEntry("type", "definition_changes")
self._container_registry.addContainer(definition_changes_container)
# Insert definition_changes between the definition and the variant
global_container_stack.insertContainer(-1, definition_changes_container)
container_stack.insertContainer(-1, definition_changes_container)
return definition_changes_container
@ -64,15 +112,129 @@ class MachineSettingsAction(MachineAction):
def containerIndex(self):
return self._container_index
def _onContainerAdded(self, container):
# Add this action as a supported action to all machine definitions
if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
if container.getProperty("machine_extruder_count", "value") > 1:
# Multiextruder printers are not currently supported
Logger.log("d", "Not attaching MachineSettingsAction to %s; Multi-extrusion printers are not supported", container.getId())
return
extruderContainerIndexChanged = pyqtSignal()
@pyqtProperty(int, notify = extruderContainerIndexChanged)
def extruderContainerIndex(self):
return self._extruder_container_index
def _onGlobalContainerChanged(self):
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
# This additional emit is needed because we cannot connect a UM.Signal directly to a pyqtSignal
self.globalContainerChanged.emit()
globalContainerChanged = pyqtSignal()
@pyqtProperty(int, notify = globalContainerChanged)
def definedExtruderCount(self):
if not self._global_container_stack:
return 0
return len(self._global_container_stack.getMetaDataEntry("machine_extruder_trains"))
@pyqtSlot(int)
def setMachineExtruderCount(self, extruder_count):
machine_manager = Application.getInstance().getMachineManager()
extruder_manager = ExtruderManager.getInstance()
definition_changes_container = self._global_container_stack.findContainer({"type": "definition_changes"})
if not self._global_container_stack or not definition_changes_container:
return
previous_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
if extruder_count == previous_extruder_count:
return
extruder_material_id = None
extruder_variant_id = None
if extruder_count == 1:
# Get the material and variant of the first extruder before setting the number extruders to 1
if machine_manager.hasMaterials:
extruder_material_id = machine_manager.allActiveMaterialIds[extruder_manager.extruderIds["0"]]
if machine_manager.hasVariants:
extruder_variant_id = machine_manager.activeVariantIds[0]
# Copy any settable_per_extruder setting value from the extruders to the global stack
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
extruder_stacks.reverse() # make sure the first extruder is done last, so its settings override any higher extruder settings
global_user_container = self._global_container_stack.getTop()
for extruder_stack in extruder_stacks:
extruder_index = extruder_stack.getMetaDataEntry("position")
extruder_user_container = extruder_stack.getTop()
for setting_instance in extruder_user_container.findInstances():
setting_key = setting_instance.definition.key
settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
if settable_per_extruder:
limit_to_extruder = self._global_container_stack.getProperty(setting_key, "limit_to_extruder")
if limit_to_extruder == "-1" or limit_to_extruder == extruder_index:
global_user_container.setProperty(setting_key, "value", extruder_user_container.getProperty(setting_key, "value"))
extruder_user_container.removeInstance(setting_key)
# Check to see if any features are set to print with an extruder that will no longer exist
for setting_key in ["adhesion_extruder_nr", "support_extruder_nr", "support_extruder_nr_layer_0", "support_infill_extruder_nr", "support_interface_extruder_nr"]:
if int(self._global_container_stack.getProperty(setting_key, "value")) > extruder_count -1:
Logger.log("i", "Lowering %s setting to match number of extruders", setting_key)
self._global_container_stack.getTop().setProperty(setting_key, "value", extruder_count -1)
# Check to see if any objects are set to print with an extruder that will no longer exist
root_node = Application.getInstance().getController().getScene().getRoot()
for node in DepthFirstIterator(root_node):
if node.getMeshData():
extruder_nr = node.callDecoration("getActiveExtruderPosition")
if extruder_nr is not None and int(extruder_nr) > extruder_count - 1:
node.callDecoration("setActiveExtruder", extruder_manager.getExtruderStack(extruder_count - 1).getId())
definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count)
self.forceUpdate()
if extruder_count > 1:
# Multiextrusion
# Make sure one of the extruder stacks is active
if extruder_manager.activeExtruderIndex == -1:
extruder_manager.setActiveExtruderIndex(0)
# Move settable_per_extruder values out of the global container
if previous_extruder_count == 1:
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
global_user_container = self._global_container_stack.getTop()
for setting_instance in global_user_container.findInstances():
setting_key = setting_instance.definition.key
settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
if settable_per_extruder:
limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder"))
extruder_stack = extruder_stacks[max(0, limit_to_extruder)]
extruder_stack.getTop().setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value"))
global_user_container.removeInstance(setting_key)
else:
# Single extrusion
# Make sure the machine stack is active
if extruder_manager.activeExtruderIndex > -1:
extruder_manager.setActiveExtruderIndex(-1);
# Restore material and variant on global stack
# MachineManager._onGlobalContainerChanged removes the global material and variant of multiextruder machines
if extruder_material_id or extruder_variant_id:
# Prevent the DiscardOrKeepProfileChangesDialog from popping up (twice) if there are user changes
# The dialog is not relevant here, since we're restoring the previous situation as good as possible
preferences = Preferences.getInstance()
choice_on_profile_override = preferences.getValue("cura/choice_on_profile_override")
preferences.setValue("cura/choice_on_profile_override", "always_keep")
if extruder_material_id:
machine_manager.setActiveMaterial(extruder_material_id);
if extruder_variant_id:
machine_manager.setActiveVariant(extruder_variant_id);
preferences.setValue("cura/choice_on_profile_override", choice_on_profile_override)
Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
@pyqtSlot()
def forceUpdate(self):
@ -83,34 +245,35 @@ class MachineSettingsAction(MachineAction):
@pyqtSlot()
def updateHasMaterialsMetadata(self):
# Updates the has_materials metadata flag after switching gcode flavor
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
definition = global_container_stack.getBottom()
if definition.getProperty("machine_gcode_flavor", "value") == "UltiGCode" and not definition.getMetaDataEntry("has_materials", False):
has_materials = global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
if not self._global_container_stack:
return
material_container = global_container_stack.findContainer({"type": "material"})
material_index = global_container_stack.getContainerIndex(material_container)
definition = self._global_container_stack.getBottom()
if definition.getProperty("machine_gcode_flavor", "value") == "UltiGCode" and not definition.getMetaDataEntry("has_materials", False):
has_materials = self._global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
if has_materials:
if "has_materials" in global_container_stack.getMetaData():
global_container_stack.setMetaDataEntry("has_materials", True)
else:
global_container_stack.addMetaDataEntry("has_materials", True)
material_container = self._global_container_stack.findContainer({"type": "material"})
material_index = self._global_container_stack.getContainerIndex(material_container)
# Set the material container to a sane default
if material_container.getId() == "empty_material":
search_criteria = { "type": "material", "definition": "fdmprinter", "id": "*pla*" }
containers = self._container_registry.findInstanceContainers(**search_criteria)
if containers:
global_container_stack.replaceContainer(material_index, containers[0])
if has_materials:
if "has_materials" in self._global_container_stack.getMetaData():
self._global_container_stack.setMetaDataEntry("has_materials", True)
else:
# The metadata entry is stored in an ini, and ini files are parsed as strings only.
# Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
if "has_materials" in global_container_stack.getMetaData():
global_container_stack.removeMetaDataEntry("has_materials")
self._global_container_stack.addMetaDataEntry("has_materials", True)
empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0]
global_container_stack.replaceContainer(material_index, empty_material)
# Set the material container to a sane default
if material_container.getId() == "empty_material":
search_criteria = { "type": "material", "definition": "fdmprinter", "id": "*pla*" }
containers = self._container_registry.findInstanceContainers(**search_criteria)
if containers:
self._global_container_stack.replaceContainer(material_index, containers[0])
else:
# The metadata entry is stored in an ini, and ini files are parsed as strings only.
# Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
if "has_materials" in self._global_container_stack.getMetaData():
self._global_container_stack.removeMetaDataEntry("has_materials")
Application.getInstance().globalContainerStackChanged.emit()
empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0]
self._global_container_stack.replaceContainer(material_index, empty_material)
Application.getInstance().globalContainerStackChanged.emit()

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,10 @@ _removed_settings = { #Settings that were removed in 2.5.
"start_layers_at_same_position"
}
_split_settings = { #These settings should be copied to all settings it was split into.
"support_interface_line_distance": {"support_roof_line_distance", "support_bottom_line_distance"}
}
## A collection of functions that convert the configuration of the user in Cura
# 2.4 to a configuration for Cura 2.5.
#
@ -42,8 +46,16 @@ class VersionUpgrade24to25(VersionUpgrade):
#Remove settings from the visible_settings.
if parser.has_section("general") and "visible_settings" in parser["general"]:
visible_settings = parser["general"]["visible_settings"].split(";")
visible_settings = filter(lambda setting: setting not in _removed_settings, visible_settings)
parser["general"]["visible_settings"] = ";".join(visible_settings)
new_visible_settings = []
for setting in visible_settings:
if setting in _removed_settings:
continue #Skip.
if setting in _split_settings:
for replaced_setting in _split_settings[setting]:
new_visible_settings.append(replaced_setting)
continue #Don't add the original.
new_visible_settings.append(setting) #No special handling, so just add the original visible setting back.
parser["general"]["visible_settings"] = ";".join(new_visible_settings)
#Change the version number in the file.
if parser.has_section("general"): #It better have!
@ -66,6 +78,10 @@ class VersionUpgrade24to25(VersionUpgrade):
if parser.has_section("values"):
for removed_setting in (_removed_settings & parser["values"].keys()): #Both in keys that need to be removed and in keys present in the file.
del parser["values"][removed_setting]
for replaced_setting in (_split_settings.keys() & parser["values"].keys()):
for replacement in _split_settings[replaced_setting]:
parser["values"][replacement] = parser["values"][replaced_setting] #Copy to replacement before removing the original!
del replaced_setting
#Change the version number in the file.
if parser.has_section("general"):

View file

@ -10,6 +10,17 @@
"category": "Custom",
"file_formats": "text/x-gcode",
"has_materials": true,
"machine_extruder_trains":
{
"0": "custom_extruder_1",
"1": "custom_extruder_2",
"2": "custom_extruder_3",
"3": "custom_extruder_4",
"4": "custom_extruder_5",
"5": "custom_extruder_6",
"6": "custom_extruder_7",
"7": "custom_extruder_8"
},
"first_start_actions": ["MachineSettingsAction"]
}
}

View file

@ -29,6 +29,18 @@
"settable_per_meshgroup": false,
"settable_globally": false
},
"machine_nozzle_size":
{
"label": "Nozzle Diameter",
"description": "The inner diameter of the nozzle. Change this setting when using a non-standard nozzle size.",
"unit": "mm",
"type": "float",
"default_value": 0.4,
"minimum_value": "0.001",
"maximum_value_warning": "10",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"machine_nozzle_offset_x":
{
"label": "Nozzle X Offset",

View file

@ -3235,7 +3235,7 @@
"support_bottom_stair_step_height":
{
"label": "Support Stair Step Height",
"description": "The height of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures.",
"description": "The height of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures. Set to zero to turn off the stair-like behaviour.",
"unit": "mm",
"type": "float",
"default_value": 0.3,
@ -3245,6 +3245,19 @@
"enabled": "support_enable",
"settable_per_mesh": true
},
"support_bottom_stair_step_width":
{
"label": "Support Stair Step Maximum Width",
"description": "The maximum width of the steps of the stair-like bottom of support resting on the model. A low value makes the support harder to remove, but too high values can lead to unstable support structures.",
"unit": "mm",
"type": "float",
"default_value": 5.0,
"limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr",
"minimum_value": "0",
"maximum_value_warning": "10.0",
"enabled": "support_enable",
"settable_per_mesh": true
},
"support_join_distance":
{
"label": "Support Join Distance",

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_1",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_2",
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_3",
"version": 2,
"name": "Extruder 3",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "2"
},
"overrides": {
"extruder_nr": {
"default_value": 2,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_4",
"version": 2,
"name": "Extruder 4",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "3"
},
"overrides": {
"extruder_nr": {
"default_value": 3,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_5",
"version": 2,
"name": "Extruder 5",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "4"
},
"overrides": {
"extruder_nr": {
"default_value": 4,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_6",
"version": 2,
"name": "Extruder 6",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "5"
},
"overrides": {
"extruder_nr": {
"default_value": 5,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_7",
"version": 2,
"name": "Extruder 7",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "6"
},
"overrides": {
"extruder_nr": {
"default_value": 6,
"maximum_value": "7"
}
}
}

View file

@ -0,0 +1,17 @@
{
"id": "custom_extruder_8",
"version": 2,
"name": "Extruder 8",
"inherits": "fdmextruder",
"metadata": {
"machine": "custom",
"position": "7"
},
"overrides": {
"extruder_nr": {
"default_value": 7,
"maximum_value": "7"
}
}
}

View file

@ -180,7 +180,7 @@ UM.Dialog
anchors.bottom:parent.bottom
spacing: UM.Theme.getSize("default_margin").width
Text
Label
{
text: catalog.i18nc("@label", "Printer Name:")
anchors.verticalCenter: machineName.verticalCenter

View file

@ -126,9 +126,11 @@ UM.PreferencesPage
text: catalog.i18nc("@label","Interface")
}
Row
GridLayout
{
spacing: UM.Theme.getSize("default_margin").width
id: interfaceGrid
columns: 4
Label
{
id: languageLabel
@ -189,94 +191,79 @@ UM.PreferencesPage
{
id: currencyLabel
text: catalog.i18nc("@label","Currency:")
anchors.verticalCenter: languageComboBox.verticalCenter
anchors.verticalCenter: currencyField.verticalCenter
}
TextField
{
id: currencyField
text: UM.Preferences.getValue("cura/currency")
onTextChanged: UM.Preferences.setValue("cura/currency", text)
}
Label
{
id: themeLabel
text: catalog.i18nc("@label","Theme:")
anchors.verticalCenter: themeComboBox.verticalCenter
}
ComboBox
{
id: themeComboBox
model: ListModel
{
id: themeList
Component.onCompleted: {
append({ text: catalog.i18nc("@item:inlistbox", "Ultimaker"), code: "cura" })
}
}
currentIndex:
{
var code = UM.Preferences.getValue("general/theme");
for(var i = 0; i < themeList.count; ++i)
{
if(model.get(i).code == code)
{
return i
}
}
}
onActivated: UM.Preferences.setValue("general/theme", model.get(index).code)
Component.onCompleted:
{
// Because ListModel is stupid and does not allow using qsTr() for values.
for(var i = 0; i < themeList.count; ++i)
{
themeList.setProperty(i, "text", catalog.i18n(themeList.get(i).text));
}
// Glorious hack time. ComboBox does not update the text properly after changing the
// model. So change the indices around to force it to update.
currentIndex += 1;
currentIndex -= 1;
}
}
}
Label
Label
{
id: languageCaption
//: Language change warning
text: catalog.i18nc("@label", "You will need to restart the application for language changes to have effect.")
text: catalog.i18nc("@label", "You will need to restart the application for these changes to have effect.")
wrapMode: Text.WordWrap
font.italic: true
}
Item
{
//: Spacer
height: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("default_margin").width
}
Row
{
spacing: UM.Theme.getSize("default_margin").width
Label
{
id: themeLabel
text: catalog.i18nc("@label","Theme:")
anchors.verticalCenter: themeComboBox.verticalCenter
}
ComboBox
{
id: themeComboBox
model: ListModel
{
id: themeList
Component.onCompleted: {
append({ text: catalog.i18nc("@item:inlistbox", "Ultimaker"), code: "cura" })
}
}
currentIndex:
{
var code = UM.Preferences.getValue("general/theme");
for(var i = 0; i < themeList.count; ++i)
{
if(model.get(i).code == code)
{
return i
}
}
}
onActivated: UM.Preferences.setValue("general/theme", model.get(index).code)
Component.onCompleted:
{
// Because ListModel is stupid and does not allow using qsTr() for values.
for(var i = 0; i < themeList.count; ++i)
{
themeList.setProperty(i, "text", catalog.i18n(themeList.get(i).text));
}
// Glorious hack time. ComboBox does not update the text properly after changing the
// model. So change the indices around to force it to update.
currentIndex += 1;
currentIndex -= 1;
}
}
}
Label
{
id: themeCaption
//: Theme change warning
text: catalog.i18nc("@label", "You will need to restart the application for theme changes to have effect.")
wrapMode: Text.WordWrap
font.italic: true
}
Item
{
//: Spacer

View file

@ -179,7 +179,7 @@ Item
Behavior on opacity { NumberAnimation { duration: 100 } }
enabled:
{
if(!ExtruderManager.activeExtruderStackId && ExtruderManager.extruderCount > 0)
if(!ExtruderManager.activeExtruderStackId && machineExtruderCount.properties.value > 1)
{
// disable all controls on the global tab, except categories
return model.type == "category"

View file

@ -19,7 +19,7 @@ Item
property Action configureSettings;
property variant minimumPrintTime: PrintInformation.minimumPrintTime;
property variant maximumPrintTime: PrintInformation.maximumPrintTime;
property bool settingsEnabled: ExtruderManager.activeExtruderStackId || ExtruderManager.extruderCount == 0
property bool settingsEnabled: ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1
Component.onCompleted: PrintInformation.enabled = true
Component.onDestruction: PrintInformation.enabled = false

View file

@ -247,7 +247,7 @@
},
"sizes": {
"window_minimum_size": [70, 54],
"window_minimum_size": [70, 50],
"window_margin": [1.0, 1.0],
"default_margin": [1.0, 1.0],
"default_lining": [0.08, 0.08],