Solved merge conflict.

This commit is contained in:
Jack Ha 2016-08-23 10:35:20 +02:00
commit 090b8d4f50
98 changed files with 2002 additions and 681 deletions

View file

@ -74,10 +74,14 @@ class BuildVolume(SceneNode):
self._adhesion_type = None
self._platform = Platform(self)
self._active_container_stack = None
self._global_container_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged)
self._onGlobalContainerStackChanged()
self._active_extruder_stack = None
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
self._onActiveExtruderStackChanged()
def setWidth(self, width):
if width: self._width = width
@ -208,22 +212,22 @@ class BuildVolume(SceneNode):
"@info:status",
"The build volume height has been reduced due to the value of the"
" \"Print Sequence\" setting to prevent the gantry from colliding"
" with printed objects."), lifetime=10).show()
" with printed models."), lifetime=10).show()
def getRaftThickness(self):
return self._raft_thickness
def _updateRaftThickness(self):
old_raft_thickness = self._raft_thickness
self._adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value")
self._adhesion_type = self._global_container_stack.getProperty("adhesion_type", "value")
self._raft_thickness = 0.0
if self._adhesion_type == "raft":
self._raft_thickness = (
self._active_container_stack.getProperty("raft_base_thickness", "value") +
self._active_container_stack.getProperty("raft_interface_thickness", "value") +
self._active_container_stack.getProperty("raft_surface_layers", "value") *
self._active_container_stack.getProperty("raft_surface_thickness", "value") +
self._active_container_stack.getProperty("raft_airgap", "value"))
self._global_container_stack.getProperty("raft_base_thickness", "value") +
self._global_container_stack.getProperty("raft_interface_thickness", "value") +
self._global_container_stack.getProperty("raft_surface_layers", "value") *
self._global_container_stack.getProperty("raft_surface_thickness", "value") +
self._global_container_stack.getProperty("raft_airgap", "value"))
# Rounding errors do not matter, we check if raft_thickness has changed at all
if old_raft_thickness != self._raft_thickness:
@ -231,41 +235,52 @@ class BuildVolume(SceneNode):
self.raftThicknessChanged.emit()
def _onGlobalContainerStackChanged(self):
if self._active_container_stack:
self._active_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
if self._global_container_stack:
self._global_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
self._active_container_stack = Application.getInstance().getGlobalContainerStack()
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
if self._active_container_stack:
self._active_container_stack.propertyChanged.connect(self._onSettingPropertyChanged)
if self._global_container_stack:
self._global_container_stack.propertyChanged.connect(self._onSettingPropertyChanged)
self._width = self._active_container_stack.getProperty("machine_width", "value")
if self._active_container_stack.getProperty("print_sequence", "value") == "one_at_a_time":
self._height = self._active_container_stack.getProperty("gantry_height", "value")
self._width = self._global_container_stack.getProperty("machine_width", "value")
machine_height = self._global_container_stack.getProperty("machine_height", "value")
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time":
self._height = min(self._global_container_stack.getProperty("gantry_height", "value"), machine_height)
if self._height < machine_height:
self._buildVolumeMessage()
else:
self._height = self._active_container_stack.getProperty("machine_height", "value")
self._depth = self._active_container_stack.getProperty("machine_depth", "value")
self._height = self._global_container_stack.getProperty("machine_height", "value")
self._depth = self._global_container_stack.getProperty("machine_depth", "value")
self._updateDisallowedAreas()
self._updateRaftThickness()
self.rebuild()
def _onActiveExtruderStackChanged(self):
if self._active_extruder_stack:
self._active_extruder_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if self._active_extruder_stack:
self._active_extruder_stack.propertyChanged.connect(self._onSettingPropertyChanged)
def _onSettingPropertyChanged(self, setting_key, property_name):
if property_name != "value":
return
rebuild_me = False
if setting_key == "print_sequence":
machine_height = self._global_container_stack.getProperty("machine_height", "value")
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time":
self._height = self._active_container_stack.getProperty("gantry_height", "value")
self._height = min(self._global_container_stack.getProperty("gantry_height", "value"), machine_height)
if self._height < machine_height:
self._buildVolumeMessage()
else:
self._height = self._active_container_stack.getProperty("machine_height", "value")
self._height = self._global_container_stack.getProperty("machine_height", "value")
rebuild_me = True
if setting_key in self._skirt_settings:
if setting_key in self._skirt_settings or setting_key in self._prime_settings or setting_key in self._tower_settings:
self._updateDisallowedAreas()
rebuild_me = True
@ -277,19 +292,33 @@ class BuildVolume(SceneNode):
self.rebuild()
def _updateDisallowedAreas(self):
if not self._active_container_stack:
if not self._global_container_stack:
return
disallowed_areas = copy.deepcopy(
self._active_container_stack.getProperty("machine_disallowed_areas", "value"))
self._global_container_stack.getProperty("machine_disallowed_areas", "value"))
areas = []
machine_width = self._global_container_stack.getProperty("machine_width", "value")
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
# Add prima tower location as disallowed area.
if self._global_container_stack.getProperty("prime_tower_enable", "value"):
half_prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value") / 2
prime_tower_x = self._global_container_stack.getProperty("prime_tower_position_x", "value") - machine_width / 2
prime_tower_y = - self._global_container_stack.getProperty("prime_tower_position_y", "value") + machine_depth / 2
disallowed_areas.append([
[prime_tower_x - half_prime_tower_size, prime_tower_y - half_prime_tower_size],
[prime_tower_x + half_prime_tower_size, prime_tower_y - half_prime_tower_size],
[prime_tower_x + half_prime_tower_size, prime_tower_y + half_prime_tower_size],
[prime_tower_x - half_prime_tower_size, prime_tower_y + half_prime_tower_size],
])
# Add extruder prime locations as disallowed areas.
# Probably needs some rework after coordinate system change.
extruder_manager = ExtruderManager.getInstance()
extruders = extruder_manager.getMachineExtruders(self._active_container_stack.getId())
machine_width = self._active_container_stack.getProperty("machine_width", "value")
machine_depth = self._active_container_stack.getProperty("machine_depth", "value")
extruders = extruder_manager.getMachineExtruders(self._global_container_stack.getId())
for single_extruder in extruders:
extruder_prime_pos_x = single_extruder.getProperty("extruder_prime_pos_x", "value")
extruder_prime_pos_y = single_extruder.getProperty("extruder_prime_pos_y", "value")
@ -305,7 +334,7 @@ class BuildVolume(SceneNode):
[prime_x - PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE],
])
bed_adhesion_size = self._getBedAdhesionSize(self._active_container_stack)
bed_adhesion_size = self._getBedAdhesionSize(self._global_container_stack)
if disallowed_areas:
# Extend every area already in the disallowed_areas with the skirt size.
@ -317,8 +346,8 @@ class BuildVolume(SceneNode):
# Add the skirt areas around the borders of the build plate.
if bed_adhesion_size > 0:
half_machine_width = self._active_container_stack.getProperty("machine_width", "value") / 2
half_machine_depth = self._active_container_stack.getProperty("machine_depth", "value") / 2
half_machine_width = self._global_container_stack.getProperty("machine_width", "value") / 2
half_machine_depth = self._global_container_stack.getProperty("machine_depth", "value") / 2
areas.append(Polygon(numpy.array([
[-half_machine_width, -half_machine_depth],
@ -377,3 +406,5 @@ class BuildVolume(SceneNode):
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
_raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"]
_prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "extruder_prime_pos_z"]
_tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"]

View file

@ -242,11 +242,17 @@ class CuraApplication(QtApplication):
raft_airgap
layer_0_z_overlap
raft_surface_layers
dual
adhesion_extruder_nr
support_extruder_nr
prime_tower_enable
prime_tower_size
prime_tower_position_x
prime_tower_position_y
meshfix
blackmagic
print_sequence
infill_mesh
dual
experimental
""".replace("\n", ";").replace(" ", ""))
@ -475,6 +481,7 @@ class CuraApplication(QtApplication):
qmlRegisterType(cura.Settings.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel")
qmlRegisterType(cura.Settings.MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterType(cura.Settings.QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
qmlRegisterSingletonType(cura.Settings.ContainerManager, "Cura", 1, 0, "ContainerManager", cura.Settings.ContainerManager.createContainerManager)

View file

@ -41,6 +41,10 @@ class PlatformPhysics:
root = self._controller.getScene().getRoot()
# Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
# same direction.
transformed_nodes = []
for node in BreadthFirstIterator(root):
if node is root or type(node) is not SceneNode or node.getBoundingBox() is None:
continue
@ -91,6 +95,9 @@ class PlatformPhysics:
if not other_node.callDecoration("getConvexHull") or not other_node.getBoundingBox():
continue
if other_node in transformed_nodes:
continue # Other node is already moving, wait for next pass.
# Get the overlap distance for both convex hulls. If this returns None, there is no intersection.
head_hull = node.callDecoration("getConvexHullHead")
if head_hull:
@ -125,6 +132,7 @@ class PlatformPhysics:
node._outside_buildarea = True
if not Vector.Null.equals(move_vector, epsilon=1e-5):
transformed_nodes.append(node)
op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
op.push()

View file

@ -1,10 +1,15 @@
from UM.i18n import i18nCatalog
from UM.OutputDevice.OutputDevice import OutputDevice
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtWidgets import QMessageBox
from enum import IntEnum # For the connection state tracking.
from UM.Logger import Logger
from UM.Application import Application
from UM.Signal import signalemitter
i18n_catalog = i18nCatalog("cura")
## Printer output device adds extra interface options on top of output device.
#
# The assumption is made the printer is a FDM printer.
@ -276,6 +281,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._hotend_ids[index] = hotend_id
self.hotendIdChanged.emit(index, hotend_id)
## Let the user decide if the hotends and/or material should be synced with the printer
# NB: the UX needs to be implemented by the plugin
def materialHotendChangedMessage(self, callback):
Logger.log("w", "materialHotendChangedMessage needs to be implemented, returning 'Yes'")
callback(QMessageBox.Yes)
## Attempt to establish connection
def connect(self):
@ -329,7 +339,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
return self._head_z
## Update the saved position of the head
# This function should be called when a new position for the head is recieved.
# This function should be called when a new position for the head is received.
def _updateHeadPosition(self, x, y ,z):
position_changed = False
if self._head_x != x:

View file

@ -351,47 +351,49 @@ class ContainerManager(QObject):
return { "status": "success", "message": "Successfully imported container {0}".format(container.getName()) }
## Update the current active quality changes container with the settings from the user container.
#
# This will go through the active global stack and all active extruder stacks and merge the changes from the user
# container into the quality_changes container. After that, the user container is cleared.
#
# \return \type{bool} True if successful, False if not.
@pyqtSlot(result = bool)
def updateQualityChanges(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
containers_to_merge = []
global_quality_changes = global_stack.findContainer(type = "quality_changes")
if not global_quality_changes or global_quality_changes.isReadOnly():
UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile")
if not global_stack:
return False
UM.Application.getInstance().getMachineManager().blurSettings.emit()
containers_to_merge.append((global_quality_changes, global_stack.getTop()))
for extruder in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
quality_changes = extruder.findContainer(type = "quality_changes")
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
# Find the quality_changes container for this stack and merge the contents of the top container into it.
quality_changes = stack.findContainer(type = "quality_changes")
if not quality_changes or quality_changes.isReadOnly():
UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile")
return False
UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile in stack %s", stack.getId())
continue
containers_to_merge.append((quality_changes, extruder.getTop()))
for merge_into, merge in containers_to_merge:
self._performMerge(merge_into, merge)
self._performMerge(quality_changes, stack.getTop())
UM.Application.getInstance().getMachineManager().activeQualityChanged.emit()
return True
## Clear the top-most (user) containers of the active stacks.
@pyqtSlot()
def clearUserContainers(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
UM.Application.getInstance().getMachineManager().blurSettings.emit()
for extruder in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
extruder.getTop().clear()
global_stack.getTop().clear()
# Go through global and extruder stacks and clear their topmost container (the user settings).
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
stack.getTop().clear()
## Create quality changes containers from the user containers in the active stacks.
#
# This will go through the global and extruder stacks and create quality_changes containers from
# the user containers in each stack. These then replace the quality_changes containers in the
# stack and clear the user settings.
#
# \return \type{bool} True if the operation was successfully, False if not.
@pyqtSlot(result = bool)
def createQualityChanges(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
@ -406,39 +408,115 @@ class ContainerManager(QObject):
UM.Application.getInstance().getMachineManager().blurSettings.emit()
unique_name = UM.Settings.ContainerRegistry.getInstance().uniqueName(quality_container.getName())
unique_id = unique_name.lower()
unique_id.replace(" ", "_")
stacks = [ s for s in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()) ]
stacks.insert(0, global_stack)
for stack in stacks:
# Go through the active stacks and create quality_changes containers from the user containers.
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
user_container = stack.getTop()
quality_container = stack.findContainer(type = "quality")
quality_changes_container = stack.findContainer(type = "quality_changes")
if not quality_container or not quality_changes_container:
UM.Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId())
return False
continue
new_quality_changes = user_container.duplicate(stack.getId() + "_" + unique_id, unique_name)
new_quality_changes.setMetaDataEntry("type", "quality_changes")
new_quality_changes.addMetaDataEntry("quality", quality_container.getId())
new_changes = self._createQualityChanges(quality_container, unique_name, stack.getId())
self._performMerge(new_changes, user_container)
if not global_stack.getMetaDataEntry("has_machine_quality"):
new_quality_changes.setDefinition(UM.Settings.ContainerRegistry.getInstance().findContainers(id = "fdmprinter")[0])
if global_stack.getMetaDataEntry("has_materials"):
material = stack.findContainer(type = "material")
new_quality_changes.addMetaDataEntry("material", material.getId())
UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_changes)
stack.replaceContainer(stack.getContainerIndex(quality_changes_container), new_quality_changes)
stack.getTop().clear()
UM.Settings.ContainerRegistry.getInstance().addContainer(new_changes)
stack.replaceContainer(stack.getContainerIndex(quality_changes_container), new_changes)
UM.Application.getInstance().getMachineManager().activeQualityChanged.emit()
return True
## Remove all quality changes containers matching a specified name.
#
# This will search for quality_changes containers matching the supplied name and remove them.
# Note that if the machine specifies that qualities should be filtered by machine and/or material
# only the containers related to the active machine/material are removed.
#
# \param quality_name The name of the quality changes to remove.
#
# \return \type{bool} True if successful, False if not.
@pyqtSlot(str, result = bool)
def removeQualityChanges(self, quality_name):
if not quality_name:
return False
for container in self._getFilteredContainers(name = quality_name, type = "quality_changes"):
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
return True
## Rename a set of quality changes containers.
#
# This will search for quality_changes containers matching the supplied name and rename them.
# Note that if the machine specifies that qualities should be filtered by machine and/or material
# only the containers related to the active machine/material are renamed.
#
# \param quality_name The name of the quality changes containers to rename.
# \param new_name The new name of the quality changes.
#
# \return True if successful, False if not.
@pyqtSlot(str, str, result = bool)
def renameQualityChanges(self, quality_name, new_name):
if not quality_name or not new_name:
return False
if quality_name == new_name:
return True
global_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_stack:
return False
UM.Application.getInstance().getMachineManager().blurSettings.emit()
new_name = UM.Settings.ContainerRegistry.getInstance().uniqueName(new_name)
container_registry = UM.Settings.ContainerRegistry.getInstance()
for container in self._getFilteredContainers(name = quality_name, type = "quality_changes"):
stack_id = container.getMetaDataEntry("extruder", global_stack.getId())
container_registry.renameContainer(container.getId(), new_name, self._createUniqueId(stack_id, new_name))
UM.Application.getInstance().getMachineManager().activeQualityChanged.emit()
return True
## Duplicate a specified set of quality or quality_changes containers.
#
# This will search for containers matching the specified name. If the container is a "quality" type container, a new
# quality_changes container will be created with the specified quality as base. If the container is a "quality_changes"
# container, it is simply duplicated and renamed.
#
# \param quality_name The name of the quality to duplicate.
#
# \return A string containing the name of the duplicated containers, or an empty string if it failed.
@pyqtSlot(str, result = str)
def duplicateQualityOrQualityChanges(self, quality_name):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_stack or not quality_name:
return ""
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = quality_name)
if not containers:
return ""
new_name = UM.Settings.ContainerRegistry.getInstance().uniqueName(quality_name)
container_type = containers[0].getMetaDataEntry("type")
if container_type == "quality":
for container in self._getFilteredContainers(name = quality_name, type = "quality"):
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
new_changes = self._createQualityChanges(container, new_name, stack.getId())
UM.Settings.ContainerRegistry.getInstance().addContainer(new_changes)
elif container_type == "quality_changes":
for container in self._getFilteredContainers(name = quality_name, type = "quality_changes"):
stack_id = container.getMetaDataEntry("extruder", global_stack.getId())
new_container = container.duplicate(self._createUniqueId(stack_id, new_name), new_name)
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
else:
return ""
return new_name
# Factory function, used by QML
@staticmethod
def createContainerManager(engine, js_engine):
@ -498,3 +576,84 @@ class ContainerManager(QObject):
name_filter = "{0} ({1})".format(mime_type.comment, suffix_list)
self._container_name_filters[name_filter] = entry
## Return a generator that iterates over a set of containers that are filtered by machine and material when needed.
#
# \param kwargs Initial search criteria that the containers need to match.
#
# \return A generator that iterates over the list of containers matching the search criteria.
def _getFilteredContainers(self, **kwargs):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_stack:
return False
criteria = kwargs
filter_by_material = False
if global_stack.getMetaDataEntry("has_machine_quality"):
criteria["definition"] = global_stack.getBottom().getId()
filter_by_material = global_stack.getMetaDataEntry("has_materials")
material_ids = []
if filter_by_material:
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
material_ids.append(stack.findContainer(type = "material").getId())
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
for container in containers:
# If the machine specifies we should filter by material, exclude containers that do not match any active material.
if filter_by_material and container.getMetaDataEntry("material") not in material_ids:
continue
yield container
## Creates a unique ID for a container by prefixing the name with the stack ID.
#
# This method creates a unique ID for a container by prefixing it with a specified stack ID.
# This is done to ensure we have an easily identified ID for quality changes, which have the
# same name across several stacks.
#
# \param stack_id The ID of the stack to prepend.
# \param container_name The name of the container that we are creating a unique ID for.
#
# \return Container name prefixed with stack ID, in lower case with spaces replaced by underscores.
def _createUniqueId(self, stack_id, container_name):
result = stack_id + "_" + container_name
result = result.lower()
result.replace(" ", "_")
return result
## Create a quality changes container for a specified quality container.
#
# \param quality_container The quality container to create a changes container for.
# \param new_name The name of the new quality_changes container.
# \param stack_id The ID of the container stack the new container "belongs to". It is used primarily to ensure a unique ID.
#
# \return A new quality_changes container with the specified container as base.
def _createQualityChanges(self, quality_container, new_name, stack_id):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
assert global_stack is not None
# Create a new quality_changes container for the quality.
quality_changes = UM.Settings.InstanceContainer(self._createUniqueId(stack_id, new_name))
quality_changes.setName(new_name)
quality_changes.addMetaDataEntry("type", "quality_changes")
quality_changes.addMetaDataEntry("quality", quality_container.getMetaDataEntry("quality_type"))
# If we are creating a container for an extruder, ensure we add that to the container
if stack_id != global_stack.getId():
quality_changes.addMetaDataEntry("extruder", stack_id)
# If the machine specifies qualities should be filtered, ensure we match the current criteria.
if not global_stack.getMetaDataEntry("has_machine_quality"):
quality_changes.setDefinition(UM.Settings.ContainerRegistry.getInstance().findContainers(id = "fdmprinter")[0])
else:
quality_changes.setDefinition(global_stack.getBottom())
if global_stack.getMetaDataEntry("has_materials"):
material = quality_container.getMetaDataEntry("material")
quality_changes.addMetaDataEntry("material", material)
return quality_changes

View file

@ -41,7 +41,6 @@ class ContainerSettingsModel(ListModel):
keys = keys + list(container.getAllKeys())
keys = list(set(keys)) # remove duplicate keys
keys.sort()
for key in keys:
definition = None
@ -72,6 +71,7 @@ class ContainerSettingsModel(ListModel):
"unit": definition.unit,
"category": category.label
})
self.sort(lambda k: (k["category"], k["key"]))
## 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

View file

@ -170,6 +170,7 @@ class CuraContainerRegistry(ContainerRegistry):
profile.addMetaDataEntry("material", self._activeMaterialId())
else:
profile.setDefinition(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0])
ContainerRegistry.getInstance().addContainer(profile)
## Gets a list of profile writer plugins

View file

@ -131,9 +131,9 @@ class ExtruderManager(QObject):
# Make sure the next stack is a stack that contains only the machine definition
if not extruder_train.getNextStack():
shallowStack = UM.Settings.ContainerStack(machine_id + "_shallow")
shallowStack.addContainer(machine_definition)
extruder_train.setNextStack(shallowStack)
shallow_stack = UM.Settings.ContainerStack(machine_id + "_shallow")
shallow_stack.addContainer(machine_definition)
extruder_train.setNextStack(shallow_stack)
changed = True
if changed:
self.extrudersChanged.emit(machine_id)
@ -251,9 +251,9 @@ class ExtruderManager(QObject):
# Make sure the next stack is a stack that contains only the machine definition
if not container_stack.getNextStack():
shallowStack = UM.Settings.ContainerStack(machine_id + "_shallow")
shallowStack.addContainer(machine_definition)
container_stack.setNextStack(shallowStack)
shallow_stack = UM.Settings.ContainerStack(machine_id + "_shallow")
shallow_stack.addContainer(machine_definition)
container_stack.setNextStack(shallow_stack)
container_registry.addContainer(container_stack)
@ -277,6 +277,20 @@ class ExtruderManager(QObject):
for name in self._extruder_trains[machine_id]:
yield self._extruder_trains[machine_id][name]
## Returns a generator that will iterate over the global stack and per-extruder stacks.
#
# The first generated element is the global container stack. After that any extruder stacks are generated.
def getActiveGlobalAndExtruderStacks(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
if not global_stack:
return
yield global_stack
global_id = global_stack.getId()
for name in self._extruder_trains[global_id]:
yield self._extruder_trains[global_id][name]
def __globalContainerStackChanged(self):
self._addCurrentMachineExtruders()
self.activeExtruderChanged.emit()

View file

@ -26,6 +26,7 @@ class MachineManager(QObject):
self._global_container_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
## When the global container is changed, active material probably needs to be updated.
self.globalContainerChanged.connect(self.activeMaterialChanged)
self.globalContainerChanged.connect(self.activeVariantChanged)
self.globalContainerChanged.connect(self.activeQualityChanged)
@ -36,8 +37,6 @@ class MachineManager(QObject):
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
self._onActiveExtruderStackChanged()
## When the global container is changed, active material probably needs to be updated.
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeMaterialChanged)
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeVariantChanged)
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeQualityChanged)
@ -118,16 +117,7 @@ class MachineManager(QObject):
if matching_extruder and matching_extruder.findContainer({"type": "variant"}).getName() != hotend_id:
# Save the material that needs to be changed. Multiple changes will be handled by the callback.
self._auto_hotends_changed[str(index)] = containers[0].getId()
Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"),
catalog.i18nc("@label",
"Do you want to change the materials and hotends to match the material in your printer?"),
catalog.i18nc("@label",
"The materials and / or hotends on your printer were changed. For best results always slice for the materials . hotends that are inserted in your printer."),
buttons=QMessageBox.Yes + QMessageBox.No,
icon=QMessageBox.Question,
callback=self._materialHotendChangedCallback)
self._printer_output_devices[0].materialHotendChangedMessage(self._materialHotendChangedCallback)
else:
Logger.log("w", "No variant found for printer definition %s with id %s" % (self._global_container_stack.getBottom().getId(), hotend_id))
@ -167,10 +157,7 @@ class MachineManager(QObject):
if matching_extruder and matching_extruder.findContainer({"type":"material"}).getMetaDataEntry("GUID") != material_id:
# Save the material that needs to be changed. Multiple changes will be handled by the callback.
self._auto_materials_changed[str(index)] = containers[0].getId()
Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the materials and hotends to match the material in your printer?"),
catalog.i18nc("@label", "The materials and / or hotends on your printer were changed. For best results always slice for the materials and hotends that are inserted in your printer."),
buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._materialHotendChangedCallback)
self._printer_output_devices[0].materialHotendChangedMessage(self._materialHotendChangedCallback)
else:
Logger.log("w", "No material definition found for printer definition %s and GUID %s" % (definition_id, material_id))
@ -199,14 +186,6 @@ class MachineManager(QObject):
if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index)
def _onGlobalContainerChanged(self):
if self._global_container_stack:
self._global_container_stack.nameChanged.disconnect(self._onMachineNameChanged)
@ -260,6 +239,20 @@ class MachineManager(QObject):
self.activeQualityChanged.emit()
def _onPropertyChanged(self, key, property_name):
if property_name == "validationState":
if self._active_stack_valid:
if self._active_container_stack.getProperty(key, "settable_per_extruder"):
changed_validation_state = self._active_container_stack.getProperty(key, property_name)
else:
changed_validation_state = self._global_container_stack.getProperty(key, property_name)
if changed_validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError):
self._active_stack_valid = False
self.activeValidationChanged.emit()
else:
if not self._checkStackForErrors(self._active_container_stack) and not self._checkStackForErrors(self._global_container_stack):
self._active_stack_valid = True
self.activeValidationChanged.emit()
self.activeStackChanged.emit()
@pyqtSlot(str)
@ -281,7 +274,7 @@ class MachineManager(QObject):
variant_instance_container = self._updateVariantContainer(definition)
material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
quality_instance_container = self._updateQualityContainer(definition, material_instance_container)
quality_instance_container = self._updateQualityContainer(definition, variant_instance_container, material_instance_container)
current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
current_settings_instance_container.addMetaDataEntry("machine", name)
@ -403,6 +396,31 @@ class MachineManager(QObject):
return ""
@pyqtProperty("QVariantMap", notify = activeMaterialChanged)
def allActiveMaterialIds(self):
if not self._global_container_stack:
return {}
result = {}
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
material_container = stack.findContainer(type = "material")
if not material_container:
continue
result[stack.getId()] = material_container.getId()
return result
@pyqtProperty(str, notify=activeQualityChanged)
def activeQualityMaterialId(self):
if self._active_container_stack:
quality = self._active_container_stack.findContainer({"type": "quality"})
if quality:
return quality.getMetaDataEntry("material")
return ""
@pyqtProperty(str, notify=activeQualityChanged)
def activeQualityName(self):
if self._active_container_stack:
@ -425,6 +443,22 @@ class MachineManager(QObject):
return quality.getId()
return ""
@pyqtProperty(str, notify = activeQualityChanged)
def activeQualityType(self):
if self._global_container_stack:
quality = self._global_container_stack.findContainer(type = "quality")
if quality:
return quality.getMetaDataEntry("quality_type")
return ""
@pyqtProperty(str, notify = activeQualityChanged)
def activeQualityChangesId(self):
if self._global_container_stack:
changes = self._global_container_stack.findContainer(type = "quality_changes")
if changes:
return changes.getId()
return ""
## Check if a container is read_only
@pyqtSlot(str, result = bool)
def isReadOnly(self, container_id):
@ -446,77 +480,13 @@ class MachineManager(QObject):
if extruder_stack != self._active_container_stack and extruder_stack.getProperty(key, "value") != new_value:
extruder_stack.getTop().setProperty(key, "value", new_value)
@pyqtSlot(str, result=str)
def duplicateContainer(self, container_id):
if not self._active_container_stack:
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"))
new_container = containers[0].duplicate(new_name, new_name)
UM.Settings.ContainerRegistry.getInstance().addContainer(new_container)
return new_name
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"))
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 = UM.Settings.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):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
if not containers or not self._active_container_stack:
return
# If the container that is being removed is the currently active container, set another machine as the active container
activate_new_container = container_id == self.activeQualityId
UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id)
if activate_new_container:
definition_id = "fdmprinter" if not self.filterQualityByMachine else self.activeDefinitionId
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition_id)
if containers:
self.setActiveQuality(containers[0].getId())
self.activeQualityChanged.emit()
@pyqtSlot(str)
def setActiveMaterial(self, material_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = material_id)
if not containers or not self._active_container_stack:
return
old_variant = self._active_container_stack.findContainer({"type":"variant"})
old_material = self._active_container_stack.findContainer({"type":"material"})
old_quality = self._active_container_stack.findContainer({"type": "quality"})
if old_material:
@ -531,7 +501,7 @@ class MachineManager(QObject):
if old_quality:
preferred_quality_name = old_quality.getName()
self.setActiveQuality(self._updateQualityContainer(self._global_container_stack.getBottom(), containers[0], preferred_quality_name).id)
self.setActiveQuality(self._updateQualityContainer(self._global_container_stack.getBottom(), old_variant, containers[0], preferred_quality_name).id)
else:
Logger.log("w", "While trying to set the active material, no material was found to replace.")
@ -568,7 +538,8 @@ class MachineManager(QObject):
quality_container = containers[0]
elif container_type == "quality_changes":
quality_changes_container = containers[0]
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_changes_container.getMetaDataEntry("quality"))
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(
quality_type = quality_changes_container.getMetaDataEntry("quality"))
if not containers:
Logger.log("e", "Could not find quality %s for changes %s, not changing quality", quality_changes_container.getMetaDataEntry("quality"), quality_changes_container.getId())
return
@ -577,16 +548,29 @@ class MachineManager(QObject):
Logger.log("e", "Tried to set quality to a container that is not of the right type")
return
stacks = [ s for s in ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()) ]
stacks.insert(0, self._global_container_stack)
quality_type = quality_container.getMetaDataEntry("quality_type")
if not quality_type:
quality_type = quality_changes_container.getName()
for stack in stacks:
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
extruder_id = stack.getId() if stack != self._global_container_stack else None
stack_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = quality_container.getName(), extruder = extruder_id)
criteria = { "quality_type": quality_type, "extruder": extruder_id }
if self._global_container_stack.getMetaDataEntry("has_machine_quality"):
material = stack.findContainer(type = "material")
criteria["material"] = material.getId()
stack_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if not stack_quality:
criteria.pop("extruder")
stack_quality = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if not stack_quality:
stack_quality = quality_container
else:
stack_quality = stack_quality[0]
else:
stack_quality = stack_quality[0]
if quality_changes_container != self._empty_quality_changes_container:
stack_quality_changes = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = quality_changes_container.getName(), extruder = extruder_id)[0]
@ -624,7 +608,11 @@ class MachineManager(QObject):
pass
elif button == QMessageBox.No:
# No, discard the settings in the user profile
self.clearUserSettings()
global_stack = Application.getInstance().getGlobalContainerStack()
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
extruder.getTop().clear()
global_stack.getTop().clear()
@pyqtProperty(str, notify = activeVariantChanged)
def activeVariantName(self):
@ -653,6 +641,16 @@ class MachineManager(QObject):
return ""
## Gets how the active definition calls variants
# Caveat: per-definition-variant-title is currently not translated (though the fallback is)
@pyqtProperty(str, notify = globalContainerChanged)
def activeDefinitionVariantsName(self):
fallback_title = catalog.i18nc("@label", "Nozzle")
if self._global_container_stack:
return self._global_container_stack.getBottom().getMetaDataEntry("variants_name", fallback_title)
return fallback_title
@pyqtSlot(str, str)
def renameMachine(self, machine_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
@ -776,7 +774,8 @@ class MachineManager(QObject):
return self._empty_material_container
def _updateQualityContainer(self, definition, material_container = None, preferred_quality_name = None):
def _updateQualityContainer(self, definition, variant_container, material_container = None, preferred_quality_name = None):
container_registry = UM.Settings.ContainerRegistry.getInstance()
search_criteria = { "type": "quality" }
if definition.getMetaDataEntry("has_machine_quality"):
@ -787,14 +786,33 @@ class MachineManager(QObject):
else:
search_criteria["definition"] = "fdmprinter"
if preferred_quality_name:
if preferred_quality_name and preferred_quality_name != "empty":
search_criteria["name"] = preferred_quality_name
else:
preferred_quality = definition.getMetaDataEntry("preferred_quality")
if preferred_quality:
search_criteria["id"] = preferred_quality
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
containers = container_registry.findInstanceContainers(**search_criteria)
if containers:
return containers[0]
if "material" in search_criteria:
# If a quality for this specific material cannot be found, try finding qualities for a generic version of the material
material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic" }
if definition.getMetaDataEntry("has_machine_quality"):
material_search_criteria["definition"] = definition.id
if definition.getMetaDataEntry("has_variants") and variant_container:
material_search_criteria["variant"] = variant_container.id
else:
material_search_criteria["definition"] = "fdmprinter"
material_containers = container_registry.findInstanceContainers(**material_search_criteria)
if material_containers:
search_criteria["material"] = material_containers[0].getId()
containers = container_registry.findInstanceContainers(**search_criteria)
if containers:
return containers[0]
@ -803,7 +821,7 @@ class MachineManager(QObject):
search_criteria.pop("name", None)
search_criteria.pop("id", None)
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
containers = container_registry.findInstanceContainers(**search_criteria)
if containers:
return containers[0]

View file

@ -0,0 +1,173 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import collections
from PyQt5.QtCore import pyqtProperty, pyqtSignal, Qt
import UM.Application
import UM.Logger
import UM.Qt
import UM.Settings
class QualitySettingsModel(UM.Qt.ListModel.ListModel):
KeyRole = Qt.UserRole + 1
LabelRole = Qt.UserRole + 2
UnitRole = Qt.UserRole + 3
ProfileValueRole = Qt.UserRole + 4
UserValueRole = Qt.UserRole + 5
CategoryRole = Qt.UserRole + 6
def __init__(self, parent = None):
super().__init__(parent = parent)
self._extruder_id = None
self._quality = None
self._material = None
self.addRoleName(self.KeyRole, "key")
self.addRoleName(self.LabelRole, "label")
self.addRoleName(self.UnitRole, "unit")
self.addRoleName(self.ProfileValueRole, "profile_value")
self.addRoleName(self.UserValueRole, "user_value")
self.addRoleName(self.CategoryRole, "category")
def setExtruderId(self, extruder_id):
if extruder_id != self._extruder_id:
self._extruder_id = extruder_id
self._update()
self.extruderIdChanged.emit()
extruderIdChanged = pyqtSignal()
@pyqtProperty(str, fset = setExtruderId, notify = extruderIdChanged)
def extruderId(self):
return self._extruder_id
def setQuality(self, quality):
if quality != self._quality:
self._quality = quality
self._update()
self.qualityChanged.emit()
qualityChanged = pyqtSignal()
@pyqtProperty(str, fset = setQuality, notify = qualityChanged)
def quality(self):
return self._quality
def setMaterial(self, material):
if material != self._material:
self._material = material
self._update()
self.materialChanged.emit()
materialChanged = pyqtSignal()
@pyqtProperty(str, fset = setMaterial, notify = materialChanged)
def material(self):
return self._material
def _update(self):
if not self._quality:
return
self.clear()
settings = collections.OrderedDict()
definition_container = UM.Application.getInstance().getGlobalContainerStack().getBottom()
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = self._quality)
if not containers:
UM.Logger.log("w", "Could not find a quality container with id %s", self._quality)
return
quality_container = None
quality_changes_container = None
if containers[0].getMetaDataEntry("type") == "quality":
quality_container = containers[0]
else:
quality_changes_container = containers[0]
criteria = {
"type": "quality",
"quality_type": quality_changes_container.getMetaDataEntry("quality"),
"definition": quality_changes_container.getDefinition().getId()
}
if self._material:
criteria["material"] = self._material
quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if not quality_container:
UM.Logger.log("w", "Could not find a quality container matching quality changes %s", quality_changes_container.getId())
return
quality_container = quality_container[0]
quality_type = quality_container.getMetaDataEntry("quality_type")
definition_id = quality_container.getDefinition().getId()
criteria = { "type": "quality", "quality_type": quality_type, "definition": definition_id }
if self._material:
criteria["material"] = self._material
criteria["extruder"] = self._extruder_id
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if not containers:
# Try again, this time without extruder
new_criteria = criteria.copy()
new_criteria.pop("extruder")
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**new_criteria)
if not containers:
# Try again, this time without material
criteria.pop("material")
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if not containers:
# Try again, this time without material or extruder
criteria.pop("extruder") # "material" has already been popped
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if not containers:
UM.Logger.log("Could not find any quality containers matching the search criteria %s" % str(criteria))
return
if quality_changes_container:
criteria = {"type": "quality_changes", "quality": quality_type, "extruder": self._extruder_id, "definition": definition_id }
changes = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
if changes:
containers.extend(changes)
current_category = ""
for definition in definition_container.findDefinitions():
if definition.type == "category":
current_category = definition.label
continue
profile_value = None
for container in containers:
new_value = container.getProperty(definition.key, "value")
if new_value:
profile_value = new_value
user_value = None
if not self._extruder_id:
user_value = UM.Application.getInstance().getGlobalContainerStack().getTop().getProperty(definition.key, "value")
else:
extruder_stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = self._extruder_id)
if extruder_stack:
user_value = extruder_stack[0].getTop().getProperty(definition.key, "value")
if not profile_value and not user_value:
continue
self.appendItem({
"key": definition.key,
"label": definition.label,
"unit": definition.unit,
"profile_value": "" if profile_value is None else str(profile_value), # it is for display only
"user_value": "" if user_value is None else str(user_value),
"category": current_category
})

View file

@ -10,3 +10,4 @@ from .ExtrudersModel import ExtrudersModel
from .MachineManager import MachineManager
from .MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from .SettingOverrideDecorator import SettingOverrideDecorator
from .QualitySettingsModel import QualitySettingsModel

View file

@ -195,9 +195,8 @@ class CuraEngineBackend(Backend):
self.slicingCancelled.emit()
self.processingProgress.emit(0)
Logger.log("d", "Attempting to kill the engine process")
self._createSocket() # Ensure that we have a fresh socket.
if Application.getInstance().getCommandLineOption("external-backend", False):
self._createSocket()
return
if self._process is not None:
@ -206,6 +205,7 @@ class CuraEngineBackend(Backend):
self._process.terminate()
Logger.log("d", "Engine process is killed. Received return code %s", self._process.wait())
self._process = None
except Exception as e: # terminating a process that is already terminating causes an exception, silently ignore this.
Logger.log("d", "Exception occurred while trying to kill the engine %s", str(e))
@ -236,7 +236,7 @@ class CuraEngineBackend(Backend):
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable objects found."))
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable models found."))
self._error_message.show()
self.backendStateChange.emit(BackendState.Error)
else:

View file

@ -1,6 +1,6 @@
{
"source_version": "15.04",
"target_version": 1,
"target_version": 2,
"translation": {
"machine_nozzle_size": "nozzle_size",
@ -21,7 +21,7 @@
"retraction_amount": "retraction_amount",
"retraction_speed": "retraction_speed",
"retraction_min_travel": "retraction_min_travel",
"retraction_hop": "retraction_hop",
"retraction_hop_enabled": "retraction_hop != 0",
"speed_print": "print_speed",
"speed_infill": "infill_speed if (float(infill_speed) != 0) else print_speed",
"speed_wall_0": "inset0_speed if (float(inset0_speed) != 0) else print_speed",
@ -29,7 +29,7 @@
"speed_topbottom": "solidarea_speed if (float(solidarea_speed) != 0) else print_speed",
"speed_travel": "travel_speed if (float(travel_speed) != 0) else travel_speed",
"speed_layer_0": "bottom_layer_speed",
"retraction_combing": "True if (retraction_combing == \"All\" or retraction_combing == \"No Skin\") else False",
"retraction_combing": "\"all\" if retraction_combing == \"All\" else \"noskin\" if retraction_combing == \"No Skin\" else \"off\"",
"cool_fan_enabled": "fan_enabled",
"cool_fan_speed_min": "fan_speed",
"cool_fan_speed_max": "fan_speed_max",
@ -66,7 +66,7 @@
"meshfix_union_all_remove_holes": "fix_horrible_union_all_type_b",
"meshfix_extensive_stitching": "fix_horrible_extensive_stitching",
"meshfix_keep_open_polygons": "fix_horrible_use_open_bits",
"magic_mesh_surface_mode": "simple_mode",
"magic_mesh_surface_mode": "\"surface\" if simple_mode else \"normal\"",
"magic_spiralize": "spiralize",
"prime_tower_enable": "wipe_tower",
"prime_tower_size": "math.sqrt(float(wipe_tower_volume) / float(layer_height))",

View file

@ -111,7 +111,8 @@ class LegacyProfileReader(ProfileReader):
if "translation" not in dict_of_doom:
Logger.log("e", "Dictionary of Doom has no translation. Is it the correct JSON file?")
return None
current_printer = Application.getInstance().getGlobalContainerStack().findContainer({ }, DefinitionContainer)
current_printer_definition = Application.getInstance().getGlobalContainerStack().getBottom()
profile.setDefinition(current_printer_definition)
for new_setting in dict_of_doom["translation"]: #Evaluate all new settings that would get a value from the translations.
old_setting_expression = dict_of_doom["translation"][new_setting]
compiled = compile(old_setting_expression, new_setting, "eval")
@ -121,10 +122,13 @@ class LegacyProfileReader(ProfileReader):
except Exception: #Probably some setting name that was missing or something else that went wrong in the ini file.
Logger.log("w", "Setting " + new_setting + " could not be set because the evaluation failed. Something is probably missing from the imported legacy profile.")
continue
if new_value != value_using_defaults and current_printer.findDefinitions(key = new_setting).default_value != new_value: #Not equal to the default in the new Cura OR the default in the legacy Cura.
profile.setSettingValue(new_setting, new_value) #Store the setting in the profile!
definitions = current_printer_definition.findDefinitions(key = new_setting)
if definitions:
if new_value != value_using_defaults and definitions[0].default_value != new_value: # Not equal to the default in the new Cura OR the default in the legacy Cura.
profile.setProperty(new_setting, "value", new_value) # Store the setting in the profile!
if len(profile.getChangedSettings()) == 0:
if len(profile.getAllKeys()) == 0:
Logger.log("i", "A legacy profile was imported but everything evaluates to the defaults, creating an empty profile.")
profile.setDirty(True)
profile.addMetaDataEntry("type", "quality")
return profile

View file

@ -0,0 +1,93 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import pyqtSlot
from cura.MachineAction import MachineAction
import cura.Settings.CuraContainerRegistry
import UM.Application
import UM.Settings.InstanceContainer
import UM.Settings.DefinitionContainer
import UM.Logger
import UM.i18n
catalog = UM.i18n.i18nCatalog("cura")
class MachineSettingsAction(MachineAction):
def __init__(self, parent = None):
super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
self._qml_url = "MachineSettingsAction.qml"
cura.Settings.CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded)
def _reset(self):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
if global_container_stack:
variant = global_container_stack.findContainer({"type": "variant"})
if variant and variant.getId() == "empty_variant":
variant_index = global_container_stack.getContainerIndex(variant)
self._createVariant(global_container_stack, variant_index)
def _createVariant(self, global_container_stack, variant_index):
# Create and switch to a variant to store the settings in
new_variant = UM.Settings.InstanceContainer(global_container_stack.getName() + "_variant")
new_variant.addMetaDataEntry("type", "variant")
new_variant.setDefinition(global_container_stack.getBottom())
UM.Settings.ContainerRegistry.getInstance().addContainer(new_variant)
global_container_stack.replaceContainer(variant_index, new_variant)
def _onContainerAdded(self, container):
# Add this action as a supported action to all machine definitions
if isinstance(container, UM.Settings.DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
if container.getProperty("machine_extruder_count", "value") > 1:
# Multiextruder printers are not currently supported
UM.Logger.log("d", "Not attaching MachineSettingsAction to %s; Multi-extrusion printers are not supported", container.getId())
return
if container.getMetaDataEntry("has_variants", False):
# Machines that use variants are not currently supported
UM.Logger.log("d", "Not attaching MachineSettingsAction to %s; Machines that use variants are not supported", container.getId())
return
UM.Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
@pyqtSlot()
def forceUpdate(self):
# Force rebuilding the build volume by reloading the global container stack.
# This is a bit of a hack, but it seems quick enough.
UM.Application.getInstance().globalContainerStackChanged.emit()
@pyqtSlot()
def updateHasMaterialsMetadata(self):
# Updates the has_materials metadata flag after switching gcode flavor
global_container_stack = UM.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"
material_container = global_container_stack.findContainer({"type": "material"})
material_index = global_container_stack.getContainerIndex(material_container)
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)
# Set the material container to a sane default
if material_container.getId() == "empty_material":
search_criteria = { "type": "material", "definition": "fdmprinter", "id": "*pla*" }
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
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 global_container_stack.getMetaData():
global_container_stack.removeMetaDataEntry("has_materials")
empty_material = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0]
global_container_stack.replaceContainer(material_index, empty_material)
UM.Application.getInstance().globalContainerStackChanged.emit()

View file

@ -0,0 +1,476 @@
// Copyright (c) 2016 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.Layouts 1.1
import QtQuick.Window 2.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Cura.MachineAction
{
anchors.fill: parent;
Item
{
id: bedLevelMachineAction
anchors.fill: parent;
UM.I18nCatalog { id: catalog; name: "cura"; }
Label
{
id: pageTitle
width: parent.width
text: catalog.i18nc("@title", "Machine Settings")
wrapMode: Text.WordWrap
font.pointSize: 18;
}
Label
{
id: pageDescription
anchors.top: pageTitle.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Please enter the correct settings for your printer below:")
}
Column
{
height: parent.height - y
width: parent.width - UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").height
anchors.left: parent.left
anchors.top: pageDescription.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
Row
{
width: parent.width
spacing: UM.Theme.getSize("default_margin").height
Column
{
width: parent.width / 2
spacing: UM.Theme.getSize("default_margin").height
Label
{
text: catalog.i18nc("@label", "Printer Settings")
font.bold: true
}
Grid
{
columns: 3
columnSpacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "X (Width)")
}
TextField
{
id: buildAreaWidthField
text: machineWidthProvider.properties.value
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: { machineWidthProvider.setPropertyValue("value", text); manager.forceUpdate() }
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Label
{
text: catalog.i18nc("@label", "Y (Depth)")
}
TextField
{
id: buildAreaDepthField
text: machineDepthProvider.properties.value
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: { machineDepthProvider.setPropertyValue("value", text); manager.forceUpdate() }
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Label
{
text: catalog.i18nc("@label", "Z (Height)")
}
TextField
{
id: buildAreaHeightField
text: machineHeightProvider.properties.value
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: { machineHeightProvider.setPropertyValue("value", text); manager.forceUpdate() }
}
Label
{
text: catalog.i18nc("@label", "mm")
}
}
Column
{
CheckBox
{
id: heatedBedCheckBox
text: catalog.i18nc("@option:check", "Heated Bed")
checked: String(machineHeatedBedProvider.properties.value).toLowerCase() != 'false'
onClicked: machineHeatedBedProvider.setPropertyValue("value", checked)
}
CheckBox
{
id: centerIsZeroCheckBox
text: catalog.i18nc("@option:check", "Machine Center is Zero")
checked: String(machineCenterIsZeroProvider.properties.value).toLowerCase() != 'false'
onClicked: machineCenterIsZeroProvider.setPropertyValue("value", checked)
}
}
Row
{
spacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "GCode Flavor")
}
ComboBox
{
model: ["RepRap (Marlin/Sprinter)", "UltiGCode"]
currentIndex: machineGCodeFlavorProvider.properties.value != model[1] ? 0 : 1
onActivated:
{
machineGCodeFlavorProvider.setPropertyValue("value", model[index]);
manager.updateHasMaterialsMetadata();
}
}
}
}
Column
{
width: parent.width / 2
spacing: UM.Theme.getSize("default_margin").height
Label
{
text: catalog.i18nc("@label", "Printhead Settings")
font.bold: true
}
Grid
{
columns: 3
columnSpacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "X min")
}
TextField
{
id: printheadXMinField
text: getHeadPolygonCoord("x", "min")
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: setHeadPolygon()
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Label
{
text: catalog.i18nc("@label", "Y min")
}
TextField
{
id: printheadYMinField
text: getHeadPolygonCoord("y", "min")
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: setHeadPolygon()
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Label
{
text: catalog.i18nc("@label", "X max")
}
TextField
{
id: printheadXMaxField
text: getHeadPolygonCoord("x", "max")
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: setHeadPolygon()
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Label
{
text: catalog.i18nc("@label", "Y max")
}
TextField
{
id: printheadYMaxField
text: getHeadPolygonCoord("y", "max")
validator: RegExpValidator { regExp: /[0-9]{0,6}/ }
onEditingFinished: setHeadPolygon()
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
Label
{
text: catalog.i18nc("@label", "Gantry height")
}
TextField
{
id: gantryHeightField
text: gantryHeightProvider.properties.value
validator: RegExpValidator { regExp: /[0-9\.]{0,6}/ }
onEditingFinished: { gantryHeightProvider.setPropertyValue("value", text) }
}
Label
{
text: catalog.i18nc("@label", "mm")
}
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
Label
{
text: catalog.i18nc("@label", "Nozzle size")
}
TextField
{
id: nozzleSizeField
text: machineNozzleSizeProvider.properties.value
validator: RegExpValidator { regExp: /[0-9\.]{0,6}/ }
onEditingFinished: { machineNozzleSizeProvider.setPropertyValue("value", text) }
}
Label
{
text: catalog.i18nc("@label", "mm")
}
}
}
}
Row
{
spacing: UM.Theme.getSize("default_margin").width
anchors.left: parent.left
anchors.right: parent.right
height: parent.height - y
Column
{
height: parent.height
width: parent.width / 2
Label
{
text: catalog.i18nc("@label", "Start Gcode")
}
TextArea
{
id: machineStartGcodeField
width: parent.width
height: parent.height - y
text: machineStartGcodeProvider.properties.value
onActiveFocusChanged:
{
if(!activeFocus)
{
machineStartGcodeProvider.setPropertyValue("value", machineStartGcodeField.text)
}
}
}
}
Column {
height: parent.height
width: parent.width / 2
Label
{
text: catalog.i18nc("@label", "End Gcode")
}
TextArea
{
id: machineEndGcodeField
width: parent.width
height: parent.height - y
text: machineEndGcodeProvider.properties.value
onActiveFocusChanged:
{
if(!activeFocus)
{
machineEndGcodeProvider.setPropertyValue("value", machineEndGcodeField.text)
}
}
}
}
}
}
}
function getHeadPolygonCoord(axis, minMax)
{
var polygon = JSON.parse(machineHeadPolygonProvider.properties.value);
var item = (axis == "x") ? 0 : 1
var result = polygon[0][item];
for(var i = 1; i < polygon.length; i++) {
if (minMax == "min") {
result = Math.min(result, polygon[i][item]);
} else {
result = Math.max(result, polygon[i][item]);
}
}
return Math.abs(result);
}
function setHeadPolygon()
{
var polygon = [];
polygon.push([-parseFloat(printheadXMinField.text), parseFloat(printheadYMaxField.text)]);
polygon.push([-parseFloat(printheadXMinField.text),-parseFloat(printheadYMinField.text)]);
polygon.push([ parseFloat(printheadXMaxField.text), parseFloat(printheadYMaxField.text)]);
polygon.push([ parseFloat(printheadXMaxField.text),-parseFloat(printheadYMinField.text)]);
machineHeadPolygonProvider.setPropertyValue("value", JSON.stringify(polygon));
manager.forceUpdate();
}
UM.SettingPropertyProvider
{
id: machineWidthProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_width"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineDepthProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_depth"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineHeightProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_height"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineHeatedBedProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_heated_bed"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineCenterIsZeroProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_center_is_zero"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineGCodeFlavorProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_gcode_flavor"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineNozzleSizeProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_nozzle_size"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: gantryHeightProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "gantry_height"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineHeadPolygonProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_head_with_fans_polygon"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineStartGcodeProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_start_gcode"
watchedProperties: [ "value" ]
storeIndex: 4
}
UM.SettingPropertyProvider
{
id: machineEndGcodeProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_end_gcode"
watchedProperties: [ "value" ]
storeIndex: 4
}
}

View file

@ -0,0 +1,21 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import MachineSettingsAction
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": catalog.i18nc("@label", "Machine Settings action"),
"author": "fieldOfView",
"version": "1.0",
"description": catalog.i18nc("@info:whatsthis", "Provides a way to change machine settings (such as build volume, nozzle size, etc)"),
"api": 3
}
}
def register(app):
return { "machine_action": MachineSettingsAction.MachineSettingsAction() }

View file

@ -31,7 +31,7 @@ Item {
spacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "Print object with")
text: catalog.i18nc("@label", "Print model with")
anchors.verticalCenter: extruderSelector.verticalCenter
color: UM.Theme.getColor("setting_control_text")
@ -154,11 +154,17 @@ Item {
Column
{
spacing: UM.Theme.getSize("default_lining").height
Repeater
// This is to ensure that the panel is first increasing in size up to 200 and then shows a scrollbar.
// It kinda looks ugly otherwise (big panel, no content on it)
height: contents.count * UM.Theme.getSize("section").height < 200 ? contents.count * UM.Theme.getSize("section").height : 200
ScrollView
{
height: parent.height
width: UM.Theme.getSize("setting").width + UM.Theme.getSize("setting").height
style: UM.Theme.styles.scrollview
ListView
{
id: contents
height: childrenRect.height;
model: UM.SettingDefinitionsModel
{
@ -259,6 +265,7 @@ Item {
}
}
}
}
Button
{
@ -306,7 +313,7 @@ Item {
UM.Dialog {
id: settingPickDialog
title: catalog.i18nc("@title:window", "Select Settings to Customize for this object")
title: catalog.i18nc("@title:window", "Select Settings to Customize for this model")
width: screenScaleFactor * 360;
property string labelFilter: ""

View file

@ -11,15 +11,15 @@ i18n_catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": i18n_catalog.i18nc("@label", "Per Object Settings Tool"),
"name": i18n_catalog.i18nc("@label", "Per Model Settings Tool"),
"author": "Ultimaker",
"version": "1.0",
"description": i18n_catalog.i18nc("@info:whatsthis", "Provides the Per Object Settings."),
"description": i18n_catalog.i18nc("@info:whatsthis", "Provides the Per Model Settings."),
"api": 3
},
"tool": {
"name": i18n_catalog.i18nc("@label", "Per Object Settings"),
"description": i18n_catalog.i18nc("@info:tooltip", "Configure Per Object Settings"),
"name": i18n_catalog.i18nc("@label", "Per Model Settings"),
"description": i18n_catalog.i18nc("@info:tooltip", "Configure Per Model Settings"),
"icon": "setting_per_object",
"tool_panel": "PerObjectSettingsPanel.qml",
"weight": 3

View file

@ -32,6 +32,8 @@ UM.Dialog
}
text: {
if (manager.errorCode == 0)
{
if (manager.firmwareUpdateCompleteStatus)
{
//: Firmware update status label
@ -48,6 +50,28 @@ UM.Dialog
return catalog.i18nc("@label","Updating firmware.")
}
}
else
{
switch (manager.errorCode)
{
case 1:
//: Firmware update status label
return catalog.i18nc("@label","Firmware update failed due to an unknown error.")
case 2:
//: Firmware update status label
return catalog.i18nc("@label","Firmware update failed due to an communication error.")
case 3:
//: Firmware update status label
return catalog.i18nc("@label","Firmware update failed due to an input/output error.")
case 4:
//: Firmware update status label
return catalog.i18nc("@label","Firmware update failed due to missing firmware.")
default:
//: Firmware update status label
return catalog.i18nc("@label", "Unknown error code: %1").arg(manager.errorCode)
}
}
}
wrapMode: Text.Wrap;
}

View file

@ -14,7 +14,7 @@ from UM.Logger import Logger
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
from UM.Message import Message
from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal
from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal, pyqtProperty
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -90,6 +90,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._firmware_update_finished = False
self._error_message = None
self._error_code = 0
onError = pyqtSignal()
@ -173,6 +174,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
## Private function (threaded) that actually uploads the firmware.
def _updateFirmware(self):
self._error_code = 0
self.setProgress(0, 100)
self._firmware_update_finished = False
@ -182,6 +184,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if len(hex_file) == 0:
Logger.log("e", "Unable to read provided hex file. Could not update firmware")
self._updateFirmwareFailedMissingFirmware()
return
programmer = stk500v2.Stk500v2()
@ -197,6 +200,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if not programmer.isConnected():
Logger.log("e", "Unable to connect with serial. Could not update firmware")
self._updateFirmwareFailedCommunicationError()
return
self._updating_firmware = True
@ -204,17 +208,57 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
try:
programmer.programChip(hex_file)
self._updating_firmware = False
except serial.SerialException as e:
Logger.log("e", "SerialException while trying to update firmware: <%s>" %(repr(e)))
self._updateFirmwareFailedIOError()
return
except Exception as e:
Logger.log("e", "Exception while trying to update firmware %s" %e)
self._updating_firmware = False
Logger.log("e", "Exception while trying to update firmware: <%s>" %(repr(e)))
self._updateFirmwareFailedUnknown()
return
programmer.close()
self._updateFirmwareCompletedSucessfully()
return
## Private function which makes sure that firmware update process has failed by missing firmware
def _updateFirmwareFailedMissingFirmware(self):
return self._updateFirmwareFailedCommon(4)
## Private function which makes sure that firmware update process has failed by an IO error
def _updateFirmwareFailedIOError(self):
return self._updateFirmwareFailedCommon(3)
## Private function which makes sure that firmware update process has failed by a communication problem
def _updateFirmwareFailedCommunicationError(self):
return self._updateFirmwareFailedCommon(2)
## Private function which makes sure that firmware update process has failed by an unknown error
def _updateFirmwareFailedUnknown(self):
return self._updateFirmwareFailedCommon(1)
## Private common function which makes sure that firmware update process has completed/ended with a set progress state
def _updateFirmwareFailedCommon(self, code):
if not code:
raise Exception("Error code not set!")
self._error_code = code
self._firmware_update_finished = True
self.resetFirmwareUpdate(update_has_finished = True)
self.progressChanged.emit()
self.firmwareUpdateComplete.emit()
return
## Private function which makes sure that firmware update process has successfully completed
def _updateFirmwareCompletedSucessfully(self):
self.setProgress(100, 100)
self._firmware_update_finished = True
self.resetFirmwareUpdate(update_has_finished = True)
self.firmwareUpdateComplete.emit()
self.firmwareUpdateChange.emit()
return
## Upload new firmware to machine
# \param filename full path of firmware file to be uploaded
@ -227,8 +271,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
def firmwareUpdateFinished(self):
return self._firmware_update_finished
def resetFirmwareUpdateFinished(self):
self._firmware_update_finished = False
def resetFirmwareUpdate(self, update_has_finished = False):
self._firmware_update_finished = update_has_finished
self.firmwareUpdateChange.emit()
@pyqtSlot()

View file

@ -57,6 +57,13 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
progress += device.progress
return progress / len(self._usb_output_devices)
@pyqtProperty(int, notify = progressChanged)
def errorCode(self):
for printer_name, device in self._usb_output_devices.items(): # TODO: @UnusedVariable "printer_name"
if device._error_code:
return device._error_code
return 0
## Return True if all printers finished firmware update
@pyqtProperty(float, notify = firmwareUpdateChange)
def firmwareUpdateCompleteStatus(self):
@ -103,7 +110,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
return
for printer_connection in self._usb_output_devices:
self._usb_output_devices[printer_connection].resetFirmwareUpdateFinished()
self._usb_output_devices[printer_connection].resetFirmwareUpdate()
self.spawnFirmwareInterface("")
for printer_connection in self._usb_output_devices:
try:
@ -111,7 +118,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
except FileNotFoundError:
# Should only happen in dev environments where the resources/firmware folder is absent.
self._usb_output_devices[printer_connection].setProgress(100, 100)
Logger.log("w", "No firmware found for printer %s", printer_connection)
Logger.log("w", "No firmware found for printer %s called '%s'" %(printer_connection, self._getDefaultFirmwareName()))
Message(i18n_catalog.i18nc("@info",
"Could not find firmware required for the printer at %s.") % printer_connection).show()
self._firmware_view.close()
@ -126,7 +133,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
self._usb_output_devices[serial_port].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
except FileNotFoundError:
self._firmware_view.close()
Logger.log("e", "Could not find firmware required for this machine")
Logger.log("e", "Could not find firmware required for this machine called '%s'" %(self._getDefaultFirmwareName()))
return False
return True
return False
@ -166,6 +173,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
"bq_hephestos_2" : "MarlinHephestos2.hex",
"ultimaker_original" : "MarlinUltimaker-{baudrate}.hex",
"ultimaker_original_plus" : "MarlinUltimaker-UMOP-{baudrate}.hex",
"ultimaker_original_dual" : "MarlinUltimaker-{baudrate}-dual.hex",
"ultimaker2" : "MarlinUltimaker2.hex",
"ultimaker2_go" : "MarlinUltimaker2go.hex",
"ultimaker2_plus" : "MarlinUltimaker2plus.hex",
@ -173,6 +181,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
"ultimaker2_extended_plus" : "MarlinUltimaker2extended-plus.hex",
}
machine_with_heated_bed = {"ultimaker_original" : "MarlinUltimaker-HBK-{baudrate}.hex",
"ultimaker_original_dual" : "MarlinUltimaker-HBK-{baudrate}-dual.hex",
}
##TODO: Add check for multiple extruders
hex_file = None

View file

@ -10,7 +10,7 @@ catalog = i18nCatalog("cura")
class BedLevelMachineAction(MachineAction):
def __init__(self):
super().__init__("BedLevel", catalog.i18nc("@action", "Level bed"))
super().__init__("BedLevel", catalog.i18nc("@action", "Level build plate"))
self._qml_url = "BedLevelMachineAction.qml"
self._bed_level_position = 0

View file

@ -24,7 +24,7 @@ Cura.MachineAction
{
id: pageTitle
width: parent.width
text: catalog.i18nc("@title", "Bed Leveling")
text: catalog.i18nc("@title", "Build Plate Leveling")
wrapMode: Text.WordWrap
font.pointSize: 18;
}
@ -44,7 +44,7 @@ Cura.MachineAction
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "For every position; insert a piece of paper under the nozzle and adjust the print bed height. The print bed height is right when the paper is slightly gripped by the tip of the nozzle.")
text: catalog.i18nc("@label", "For every position; insert a piece of paper under the nozzle and adjust the print build plate height. The print build plate height is right when the paper is slightly gripped by the tip of the nozzle.")
}
Row
@ -59,7 +59,7 @@ Cura.MachineAction
Button
{
id: startBedLevelingButton
text: catalog.i18nc("@action:button","Start Bed Leveling")
text: catalog.i18nc("@action:button","Start Build Plate Leveling")
onClicked:
{
startBedLevelingButton.visible = false;

View file

@ -220,7 +220,7 @@ Cura.MachineAction
anchors.left: parent.left
anchors.top: nozzleTempLabel.bottom
wrapMode: Text.WordWrap
text: catalog.i18nc("@label","Bed temperature check:")
text: catalog.i18nc("@label","Build plate temperature check:")
visible: checkupMachineAction.usbConnected && manager.hasHeatedBed
}

View file

@ -20,31 +20,25 @@ class UMOUpgradeSelection(MachineAction):
@pyqtProperty(bool, notify = heatedBedChanged)
def hasHeatedBed(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
return global_container_stack.getProperty("machine_heated_bed", "value")
@pyqtSlot()
def addHeatedBed(self):
@pyqtSlot(bool)
def setHeatedBed(self, heated_bed = True):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
variant = global_container_stack.findContainer({"type": "variant"})
if variant:
if variant.getId() == "empty_variant":
variant_index = global_container_stack.getContainerIndex(variant)
stack_name = global_container_stack.getName()
new_variant = UM.Settings.InstanceContainer(stack_name + "_variant")
self._createVariant(global_container_stack, variant_index)
variant.setProperty("machine_heated_bed", "value", heated_bed)
self.heatedBedChanged.emit()
def _createVariant(self, global_container_stack, variant_index):
# Create and switch to a variant to store the settings in
new_variant = UM.Settings.InstanceContainer(global_container_stack.getName() + "_variant")
new_variant.addMetaDataEntry("type", "variant")
new_variant.setDefinition(global_container_stack.getBottom())
UM.Settings.ContainerRegistry.getInstance().addContainer(new_variant)
global_container_stack.replaceContainer(variant_index, new_variant)
variant = new_variant
variant.setProperty("machine_heated_bed", "value", True)
self.heatedBedChanged.emit()
@pyqtSlot()
def removeHeatedBed(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
variant = global_container_stack.findContainer({"type": "variant"})
if variant:
variant.setProperty("machine_heated_bed", "value", False)
self.heatedBedChanged.emit()

View file

@ -42,9 +42,9 @@ Cura.MachineAction
anchors.top: pageDescription.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
text: catalog.i18nc("@label", "Heated bed (official kit or self-built)")
text: catalog.i18nc("@label", "Heated Build Plate (official kit or self-built)")
checked: manager.hasHeatedBed
onClicked: checked ? manager.addHeatedBed() : manager.removeHeatedBed()
onClicked: manager.setHeatedBed(checked)
}
UM.I18nCatalog { id: catalog; name: "cura"; }

View file

@ -21,13 +21,11 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
## Overridden from InstanceContainer
def duplicate(self, new_id, new_name = None):
base_file = self.getMetaDataEntry("base_file", None)
new_uuid = str(uuid.uuid4())
if base_file:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = base_file)
if containers:
new_basefile = containers[0].duplicate(self.getMetaDataEntry("brand") + "_" + new_id, new_name)
new_basefile.setMetaDataEntry("GUID", new_uuid)
base_file = new_basefile.id
UM.Settings.ContainerRegistry.getInstance().addContainer(new_basefile)
@ -38,8 +36,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
if variant_containers:
new_id += "_" + variant_containers[0].getName().replace(" ", "_")
new_id = UM.Settings.ContainerRegistry.getInstance().createUniqueName("material", self._id, new_id, "")
result = super().duplicate(new_id, new_name)
result.setMetaDataEntry("GUID", new_uuid)
if result.getMetaDataEntry("base_file", None):
result.setMetaDataEntry("base_file", base_file)
return result
@ -58,13 +56,14 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
super().setMetaDataEntry(key, value)
if key == "material":
self.setName(value)
for container in UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(GUID = self.getMetaDataEntry("GUID")):
if key == "material" or key == "color_name":
self.setName(self._profile_name(self.getMetaDataEntry("material"), self.getMetaDataEntry("color_name")))
basefile = self.getMetaDataEntry("base_file", self._id) #if basefile is none, this is a basefile.
# Update all containers that share GUID and basefile
for container in UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(GUID = self.getMetaDataEntry("GUID"), base_file = basefile):
container.setMetaData(copy.deepcopy(self._metadata))
if key == "material":
container.setName(value)
if key == "material" or key == "color_name":
container.setName(self.getName())
## Overridden from InstanceContainer
def setProperty(self, key, property_name, property_value, container = None):
@ -237,7 +236,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
material = entry.find("./um:material", self.__namespaces)
color = entry.find("./um:color", self.__namespaces)
self.setName(material.text)
self.setName(self._profile_name(material.text, color.text))
self.addMetaDataEntry("brand", brand.text)
self.addMetaDataEntry("material", material.text)
@ -293,7 +292,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
for identifier in identifiers:
machine_id = self.__product_id_map.get(identifier.get("product"), None)
if machine_id is None:
Logger.log("w", "Cannot create material for unknown machine %s", machine_id)
Logger.log("w", "Cannot create material for unknown machine %s", identifier.get("product"))
continue
definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = machine_id)
@ -369,11 +368,18 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
builder.data(str(instance.value))
builder.end("setting")
def _profile_name(self, material_name, color_name):
if color_name != "Generic":
return "%s %s" % (color_name, material_name)
else:
return material_name
# Map XML file setting names to internal names
__material_property_setting_map = {
"print temperature": "material_print_temperature",
"heated bed temperature": "material_bed_temperature",
"standby temperature": "material_standby_temperature",
"processing temperature graph": "material_flow_temp_graph",
"print cooling": "cool_fan_speed",
"retraction amount": "retraction_amount",
"retraction speed": "retraction_speed",
@ -382,11 +388,11 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
# Map XML file product names to internal ids
# TODO: Move this to definition's metadata
__product_id_map = {
"Ultimaker2": "ultimaker2",
"Ultimaker2+": "ultimaker2_plus",
"Ultimaker2go": "ultimaker2_go",
"Ultimaker2extended": "ultimaker2_extended",
"Ultimaker2extended+": "ultimaker2_extended_plus",
"Ultimaker 2": "ultimaker2",
"Ultimaker 2+": "ultimaker2_plus",
"Ultimaker 2 Go": "ultimaker2_go",
"Ultimaker 2 Extended": "ultimaker2_extended",
"Ultimaker 2 Extended+": "ultimaker2_extended_plus",
"Ultimaker Original": "ultimaker_original",
"Ultimaker Original+": "ultimaker_original_plus"
}

View file

@ -0,0 +1,15 @@
{
"id": "custom",
"version": 2,
"name": "Custom FDM printer",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Custom",
"category": "Custom",
"file_formats": "text/x-gcode",
"has_materials": true,
"first_start_actions": ["MachineSettingsAction"]
}
}

View file

@ -161,7 +161,7 @@
},
"platform_adhesion":
{
"label": "Platform Adhesion",
"label": "Build Plate Adhesion",
"type": "category",
"icon": "category_adhesion",
"description": "Adhesion",
@ -177,8 +177,7 @@
"minimum_value_warning": "machine_nozzle_offset_x",
"maximum_value": "machine_width",
"settable_per_mesh": false,
"settable_per_extruder": true,
"enabled": false
"settable_per_extruder": true
},
"extruder_prime_pos_y":
{
@ -190,8 +189,7 @@
"minimum_value_warning": "machine_nozzle_offset_y",
"maximum_value_warning": "machine_depth",
"settable_per_mesh": false,
"settable_per_extruder": true,
"enabled": false
"settable_per_extruder": true
}
}
}

View file

@ -10,8 +10,8 @@
"manufacturer": "Ultimaker",
"file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g",
"visible": false,
"preferred_material": "pla",
"preferred_quality": "normal",
"preferred_material": "*generic_pla*",
"preferred_quality": "*normal*",
"machine_extruder_trains":
{
"0": "fdmextruder"
@ -67,8 +67,8 @@
},
"material_bed_temp_wait":
{
"label": "Wait for bed heatup",
"description": "Whether to insert a command to wait until the bed temperature is reached at the start.",
"label": "Wait for build plate heatup",
"description": "Whether to insert a command to wait until the build plate temperature is reached at the start.",
"default_value": true,
"type": "bool",
"settable_per_mesh": false,
@ -95,6 +95,16 @@
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"material_bed_temp_prepend":
{
"label": "Include build plate temperature",
"description": "Whether to include build plate temperature commands at the start of the gcode. When the start_gcode already contains build plate temperature commands Cura frontend will automatically disable this setting.",
"default_value": true,
"type": "bool",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"machine_width":
{
"label": "Machine width",
@ -127,8 +137,8 @@
},
"machine_heated_bed":
{
"label": "Has heated bed",
"description": "Whether the machine has a heated bed present.",
"label": "Has heated build plate",
"description": "Whether the machine has a heated build plate present.",
"default_value": false,
"type": "bool",
"settable_per_mesh": false,
@ -784,7 +794,7 @@
"wall_0_inset":
{
"label": "Outer Wall Inset",
"description": "Inset applied to the path of the outer wall. If the outer wall is smaller than the nozzle, and printed after the inner walls, use this offset to get the hole in the nozzle to overlap with the inner walls instead of the outside of the object.",
"description": "Inset applied to the path of the outer wall. If the outer wall is smaller than the nozzle, and printed after the inner walls, use this offset to get the hole in the nozzle to overlap with the inner walls instead of the outside of the model.",
"unit": "mm",
"type": "float",
"default_value": 0.0,
@ -1085,8 +1095,8 @@
"settable_per_extruder": true
},
"material_bed_temperature": {
"label": "Bed Temperature",
"description": "The temperature used for the heated bed. Set at 0 to pre-heat the printer manually.",
"label": "Build Plate Temperature",
"description": "The temperature used for the heated build plate. Set at 0 to pre-heat the printer manually.",
"unit": "°C",
"type": "float",
"resolve": "sum(extruderValues('material_bed_temperature')) / len(extruderValues('material_bed_temperature'))",
@ -1570,7 +1580,7 @@
"max_feedrate_z_override":
{
"label": "Maximum Z Speed",
"description": "The maximum speed with which the bed is moved. Setting this to zero causes the print to use the firmware defaults for the maximum z speed.",
"description": "The maximum speed with which the build plate is moved. Setting this to zero causes the print to use the firmware defaults for the maximum z speed.",
"unit": "mm/s",
"type": "float",
"default_value": 0,
@ -1583,7 +1593,7 @@
"speed_slowdown_layers":
{
"label": "Number of Slower Layers",
"description": "The first few layers are printed slower than the rest of the object, to get better adhesion to the build plate and improve the overall success rate of prints. The speed is gradually increased over these layers.",
"description": "The first few layers are printed slower than the rest of the model, to get better adhesion to the build plate and improve the overall success rate of prints. The speed is gradually increased over these layers.",
"type": "int",
"default_value": 2,
"minimum_value": "0",
@ -2111,8 +2121,8 @@
{
"cool_fan_enabled":
{
"label": "Enable Cooling Fans",
"description": "Enables the cooling fans while printing. The fans improve print quality on layers with short layer times and bridging / overhangs.",
"label": "Enable Print Cooling",
"description": "Enables the print cooling fans while printing. The fans improve print quality on layers with short layer times and bridging / overhangs.",
"type": "bool",
"default_value": true,
"settable_per_mesh": false,
@ -2121,7 +2131,7 @@
"cool_fan_speed":
{
"label": "Fan Speed",
"description": "The speed at which the cooling fans spin.",
"description": "The speed at which the print cooling fans spin.",
"unit": "%",
"type": "float",
"minimum_value": "0",
@ -2634,7 +2644,7 @@
},
"platform_adhesion":
{
"label": "Platform Adhesion",
"label": "Build Plate Adhesion",
"type": "category",
"icon": "category_adhesion",
"description": "Adhesion",
@ -2668,8 +2678,8 @@
},
"adhesion_type":
{
"label": "Platform Adhesion Type",
"description": "Different options that help to improve both priming your extrusion and adhesion to the build plate. Brim adds a single layer flat area around the base of your object to prevent warping. Raft adds a thick grid with a roof below the object. Skirt is a line printed around the object, but not connected to the model.",
"label": "Build Plate Adhesion Type",
"description": "Different options that help to improve both priming your extrusion and adhesion to the build plate. Brim adds a single layer flat area around the base of your model to prevent warping. Raft adds a thick grid with a roof below the model. Skirt is a line printed around the model, but not connected to the model.",
"type": "enum",
"options":
{
@ -2684,7 +2694,7 @@
"skirt_line_count":
{
"label": "Skirt Line Count",
"description": "Multiple skirt lines help to prime your extrusion better for small objects. Setting this to 0 will disable the skirt.",
"description": "Multiple skirt lines help to prime your extrusion better for small models. Setting this to 0 will disable the skirt.",
"type": "int",
"default_value": 1,
"minimum_value": "0",
@ -2762,7 +2772,7 @@
"raft_margin":
{
"label": "Raft Extra Margin",
"description": "If the raft is enabled, this is the extra raft area around the object which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.",
"description": "If the raft is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.",
"unit": "mm",
"type": "float",
"default_value": 15,
@ -2773,7 +2783,7 @@
"raft_airgap":
{
"label": "Raft Air Gap",
"description": "The gap between the final raft layer and the first layer of the object. Only the first layer is raised by this amount to lower the bonding between the raft layer and the object. Makes it easier to peel off the raft.",
"description": "The gap between the final raft layer and the first layer of the model. Only the first layer is raised by this amount to lower the bonding between the raft layer and the model. Makes it easier to peel off the raft.",
"unit": "mm",
"type": "float",
"default_value": 0.3,
@ -2785,7 +2795,7 @@
},
"layer_0_z_overlap": {
"label": "Initial Layer Z Overlap",
"description": "Make the first and second layer of the object overlap in the Z direction to compensate for the filament lost in the airgap. All models above the first model layer will be shifted down by this amount.",
"description": "Make the first and second layer of the model overlap in the Z direction to compensate for the filament lost in the airgap. All models above the first model layer will be shifted down by this amount.",
"unit": "mm",
"type": "float",
"default_value": 0.22,
@ -2799,7 +2809,7 @@
"raft_surface_layers":
{
"label": "Raft Top Layers",
"description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the object sits on. 2 layers result in a smoother top surface than 1.",
"description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the model sits on. 2 layers result in a smoother top surface than 1.",
"type": "int",
"default_value": 2,
"minimum_value": "0",
@ -2867,7 +2877,7 @@
"raft_interface_line_width":
{
"label": "Raft Middle Line Width",
"description": "Width of the lines in the middle raft layer. Making the second layer extrude more causes the lines to stick to the bed.",
"description": "Width of the lines in the middle raft layer. Making the second layer extrude more causes the lines to stick to the build plate.",
"unit": "mm",
"type": "float",
"default_value": 0.7,
@ -2895,7 +2905,7 @@
"raft_base_thickness":
{
"label": "Raft Base Thickness",
"description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer bed.",
"description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer build plate.",
"unit": "mm",
"type": "float",
"default_value": 0.3,
@ -2909,7 +2919,7 @@
"raft_base_line_width":
{
"label": "Raft Base Line Width",
"description": "Width of the lines in the base raft layer. These should be thick lines to assist in bed adhesion.",
"description": "Width of the lines in the base raft layer. These should be thick lines to assist in build plate adhesion.",
"unit": "mm",
"type": "float",
"default_value": 0.8,
@ -3182,7 +3192,7 @@
{
"adhesion_extruder_nr":
{
"label": "Platform Adhesion Extruder",
"label": "Build Plate Adhesion Extruder",
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
"type": "extruder",
"default_value": "0",
@ -3240,6 +3250,7 @@
"label": "Enable Prime Tower",
"description": "Print a tower next to the print which serves to prime the material after each nozzle switch.",
"type": "bool",
"enabled": "machine_extruder_count > 1",
"default_value": false,
"settable_per_mesh": false,
"settable_per_extruder": false
@ -3311,7 +3322,7 @@
"multiple_mesh_overlap":
{
"label": "Dual Extrusion Overlap",
"description": "Make the objects printed with different extruder trains overlap a bit. This makes the different materials bond together better.",
"description": "Make the models printed with different extruder trains overlap a bit. This makes the different materials bond together better.",
"type": "float",
"unit": "mm",
"default_value": 0.15,
@ -3322,7 +3333,7 @@
"ooze_shield_enabled":
{
"label": "Enable Ooze Shield",
"description": "Enable exterior ooze shield. This will create a shell around the object which is likely to wipe a second nozzle if it's at the same height as the first nozzle.",
"description": "Enable exterior ooze shield. This will create a shell around the model which is likely to wipe a second nozzle if it's at the same height as the first nozzle.",
"type": "bool",
"default_value": false,
"settable_per_mesh": false,
@ -3409,7 +3420,7 @@
"print_sequence":
{
"label": "Print Sequence",
"description": "Whether to print all objects one layer at a time or to wait for one object to finish, before moving on to the next. One at a time mode is only possible if all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes.",
"description": "Whether to print all models one layer at a time or to wait for one model to finish, before moving on to the next. One at a time mode is only possible if all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes.",
"type": "enum",
"options":
{
@ -3463,7 +3474,7 @@
"magic_spiralize":
{
"label": "Spiralize Outer Contour",
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid object into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid model into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
"type": "bool",
"default_value": false,
"settable_per_mesh": true
@ -3481,7 +3492,7 @@
"draft_shield_enabled":
{
"label": "Enable Draft Shield",
"description": "This will create a wall around the object, which traps (hot) air and shields against exterior airflow. Especially useful for materials which warp easily.",
"description": "This will create a wall around the model, which traps (hot) air and shields against exterior airflow. Especially useful for materials which warp easily.",
"type": "bool",
"default_value": false,
"settable_per_mesh": false,
@ -3503,7 +3514,7 @@
"draft_shield_height_limitation":
{
"label": "Draft Shield Limitation",
"description": "Set the height of the draft shield. Choose to print the draft shield at the full height of the object or at a limited height.",
"description": "Set the height of the draft shield. Choose to print the draft shield at the full height of the model or at a limited height.",
"type": "enum",
"options":
{
@ -3807,7 +3818,7 @@
"wireframe_printspeed_flat":
{
"label": "WP Horizontal Printing Speed",
"description": "Speed of printing the horizontal contours of the object. Only applies to Wire Printing.",
"description": "Speed of printing the horizontal contours of the model. Only applies to Wire Printing.",
"unit": "mm/s",
"type": "float",
"default_value": 5,

View file

@ -27,7 +27,7 @@
"default_value": true
},
"machine_center_is_zero": {
"default_value": false
"default_value": true
},
"machine_nozzle_size": {
"default_value": 0.4
@ -56,7 +56,7 @@
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\n{IF_BED}M190 S{BED}\n{IF_EXT0}M104 T0 S{TEMP0}\n{IF_EXT0}M109 T0 S{TEMP0}\n{IF_EXT1}M104 T1 S{TEMP1}\n{IF_EXT1}M109 T1 S{TEMP1}\nG32 S3 ; auto level\nG92 E0 ; Reset extruder position"
},
"machine_end_gcode": {
"default_value": "M104 S0\nG91 ; relative positioning\nG1 E-2 F5000; retract 2mm\nG28 Z; move bed down\nG90 ; absolute positioning\nM84 ; disable motors"
"default_value": "M104 S0\nM140 S0 ; heated bed heater off\nG91 ; relative positioning\nG1 E-2 F5000; retract 2mm\nG28 Z; move bed down\nG90 ; absolute positioning\nM84 ; disable motors"
},
"layer_height": {
"default_value": 0.15
@ -65,7 +65,7 @@
"default_value": 0.8
},
"top_bottom_thickness": {
"default_value": 0.3
"default_value": 1.2
},
"material_print_temperature": {
"default_value": 215

View file

@ -18,10 +18,12 @@
},
"overrides": {
"machine_start_gcode" : {
"default_value": ""
"default_value": "",
"value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"G21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nG1 X10 Y0 F4000;move X/Y to min endstops\\nG28 Z0 ;move Z to bottom endstops\\nG1 Z15.0 F9000 ;move the platform to 15mm\\nG92 E0 ;zero the extruded length\\nG1 F200 E10 ;extrude 10 mm of feed stock\\nG92 E0 ;zero the extruded length again\\nG1 F9000\\n;Put printing message on LCD screen\\nM117 Printing...\""
},
"machine_end_gcode" : {
"default_value": ""
"default_value": "",
"value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"M104 S0 ;extruder heater off\\nM140 S0 ;heated bed heater off (if you have it)\\nG91 ;relative positioning\\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning\""
},
"machine_width": {
"default_value": 223

View file

@ -11,9 +11,7 @@
"file_formats": "text/x-gcode",
"platform": "ultimaker2_platform.obj",
"platform_texture": "Ultimaker2Plusbackplate.png",
"preferred_variant": "ultimaker2_plus_0.4",
"preferred_material": "*pla*",
"preferred_quality": "*normal*",
"preferred_variant": "*0.4*",
"has_variants": true,
"has_materials": true,
"has_machine_materials": true,

View file

@ -13,8 +13,6 @@
"icon": "icon_ultimaker.png",
"platform": "ultimaker_platform.stl",
"has_materials": true,
"preferred_material": "*pla*",
"preferred_quality": "*normal*",
"first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"],
"supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"]
},

View file

@ -13,12 +13,10 @@
"icon": "icon_ultimaker.png",
"platform": "ultimaker_platform.stl",
"has_materials": true,
"preferred_material": "*pla*",
"preferred_quality": "*normal*",
"machine_extruder_trains":
{
"0": "ultimaker_original_dual_left",
"1": "ultimaker_original_dual_right"
"0": "ultimaker_original_dual_1st",
"1": "ultimaker_original_dual_2nd"
},
"first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"],
"supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"]
@ -65,12 +63,22 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nT1 ;Switch to the 2nd extruder\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F200 E-{switch_extruder_retraction_amount}\nT0 ;Switch to the 1st extruder\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
"default_value": "M104 T0 S0 ;1st extruder heater off\nM104 T1 S0 ;2nd extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
},
"machine_extruder_count": { "default_value": 2 },
"print_sequence": {"enabled": false}
"machine_extruder_count": {
"default_value": 2
},
"print_sequence": {
"enabled": false
},
"prime_tower_position_x": {
"default_value": 185
},
"prime_tower_position_y": {
"default_value": 175
}
}
}

View file

@ -0,0 +1,26 @@
{
"id": "ultimaker_original_dual_1st",
"version": 2,
"name": "1st Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }
}
}

View file

@ -0,0 +1,26 @@
{
"id": "ultimaker_original_dual_2nd",
"version": 2,
"name": "2nd Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 21.6 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }
}
}

View file

@ -1,19 +0,0 @@
{
"id": "ultimaker_original_dual_left",
"version": 2,
"name": "Left Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 }
}
}

View file

@ -1,19 +0,0 @@
{
"id": "ultimaker_original_dual_right",
"version": 2,
"name": "Right Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 21.6 }
}
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generic PLA profile. Serves as an example file, data in this file is not correct.
Generic ABS profile. Serves as an example file, data in this file is not correct.
-->
<fdmmaterial xmlns="http://www.ultimaker.com/material">
<metadata>
@ -10,20 +10,21 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
<color>Generic</color>
</name>
<GUID>60636bb4-518f-42e7-8237-fe77b194ebe0</GUID>
<version>0</version>
<version>1</version>
<color_code>#8cb219</color_code>
</metadata>
<properties>
<density>1.07</density>
<density>1.10</density>
<diameter>2.85</diameter>
</properties>
<settings>
<setting key="print temperature">250</setting>
<setting key="print temperature">240</setting>
<setting key="heated bed temperature">80</setting>
<setting key="standby temperature">200</setting>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2 Extended+"/>
<hotend id="0.25 mm" />
<hotend id="0.4 mm" />

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generic PLA profile. Serves as an example file, data in this file is not correct.
Generic CPE profile. Serves as an example file, data in this file is not correct.
-->
<fdmmaterial xmlns="http://www.ultimaker.com/material">
<metadata>
@ -10,20 +10,21 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
<color>Generic</color>
</name>
<GUID>12f41353-1a33-415e-8b4f-a775a6c70cc6</GUID>
<version>0</version>
<version>1</version>
<color_code>#159499</color_code>
</metadata>
<properties>
<density>0.94</density>
<density>1.27</density>
<diameter>2.85</diameter>
</properties>
<settings>
<setting key="print temperature">250</setting>
<setting key="heated bed temperature">70</setting>
<setting key="standby temperature">175</setting>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2 Extended+"/>
<hotend id="0.25 mm" />
<hotend id="0.4 mm" />

View file

@ -10,25 +10,42 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
<color>Generic</color>
</name>
<GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID>
<version>0</version>
<version>1</version>
<color_code>#ffc924</color_code>
</metadata>
<properties>
<density>1.3</density>
<density>1.24</density>
<diameter>2.85</diameter>
</properties>
<settings>
<setting key="print temperature">210</setting>
<setting key="print temperature">200</setting>
<setting key="heated bed temperature">60</setting>
<setting key="standby temperature">175</setting>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker2extended+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2+"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2 Extended+"/>
<hotend id="0.25 mm" />
<hotend id="0.4 mm" />
<hotend id="0.6 mm" />
<hotend id="0.8 mm" />
</machine>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2 Go"/>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker 2 Extended"/>
<setting key="standby temperature">150</setting>
<setting key="processing temperature graph">
<point flow="2" temperature="180"/>
<point flow="10" temperature="230"/>
</setting>
</machine>
<machine>
<machine_identifier manufacturer="Ultimaker" product="Ultimaker Original"/>
<setting key="standby temperature">150</setting>
</machine>
</settings>
</fdmmaterial>

View file

@ -183,7 +183,7 @@ Item
Action
{
id: deleteObjectAction;
text: catalog.i18nc("@action:inmenu","Delete Object");
text: catalog.i18nc("@action:inmenu","Delete Model");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
}
@ -191,13 +191,13 @@ Item
Action
{
id: centerObjectAction;
text: catalog.i18nc("@action:inmenu","Ce&nter Object on Platform");
text: catalog.i18nc("@action:inmenu","Ce&nter Model on Platform");
}
Action
{
id: groupObjectsAction
text: catalog.i18nc("@action:inmenu menubar:edit","&Group Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","&Group Models");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "object-group"
shortcut: "Ctrl+G";
@ -207,7 +207,7 @@ Item
Action
{
id: unGroupObjectsAction
text: catalog.i18nc("@action:inmenu menubar:edit","Ungroup Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","Ungroup Models");
enabled: UM.Scene.isGroupSelected
iconName: "object-ungroup"
shortcut: "Ctrl+Shift+G";
@ -217,7 +217,7 @@ Item
Action
{
id: mergeObjectsAction
text: catalog.i18nc("@action:inmenu menubar:edit","&Merge Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","&Merge Models");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "merge";
shortcut: "Ctrl+Alt+G";
@ -227,14 +227,14 @@ Item
Action
{
id: multiplyObjectAction;
text: catalog.i18nc("@action:inmenu","&Duplicate Object");
text: catalog.i18nc("@action:inmenu","&Duplicate Model");
iconName: "edit-duplicate"
}
Action
{
id: selectAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","&Select All Objects");
text: catalog.i18nc("@action:inmenu menubar:edit","&Select All Models");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-select-all";
shortcut: "Ctrl+A";
@ -244,7 +244,7 @@ Item
Action
{
id: deleteAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Platform");
text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Plate");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
shortcut: "Ctrl+D";
@ -254,7 +254,7 @@ Item
Action
{
id: reloadAllAction;
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Objects");
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
iconName: "document-revert";
onTriggered: Printer.reloadAll();
}
@ -262,14 +262,14 @@ Item
Action
{
id: resetAllTranslationAction;
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Object Positions");
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model Positions");
onTriggered: Printer.resetAllTranslation();
}
Action
{
id: resetAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Object &Transformations");
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model &Transformations");
onTriggered: Printer.resetAll();
}

View file

@ -143,20 +143,21 @@ UM.MainWindow
model: Cura.ExtrudersModel { }
Menu {
title: model.name
visible: machineExtruderCount.properties.value > 1
NozzleMenu { title: catalog.i18nc("@title:menu", "&Nozzle"); visible: Cura.MachineManager.hasVariants }
NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants }
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials }
ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); }
MenuSeparator { }
MenuItem { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder"); onTriggered: Cura.ExtruderManager.setActiveExtruderIndex(model.index) }
MenuItem { text: catalog.i18nc("@action:inmenu", "Set as Active Extruder"); onTriggered: ExtruderManager.setActiveExtruderIndex(model.index) }
}
onObjectAdded: settingsMenu.insertItem(index, object)
onObjectRemoved: settingsMenu.removeItem(object)
}
NozzleMenu { title: catalog.i18nc("@title:menu", "&Nozzle"); visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasVariants }
NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasVariants }
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: machineExtruderCount.properties.value <= 1 && Cura.MachineManager.hasMaterials }
ProfileMenu { title: catalog.i18nc("@title:menu", "&Profile"); visible: machineExtruderCount.properties.value <= 1 }
@ -459,7 +460,6 @@ UM.MainWindow
target: Cura.Actions.addProfile
onTriggered:
{
// Cura.MachineManager.newQualityContainerFromQualityAndUser();
Cura.ContainerManager.createQualityChanges();
preferences.setPage(4);
preferences.show();
@ -765,10 +765,6 @@ UM.MainWindow
addMachineDialog.visible = true
addMachineDialog.firstRun = false
}
onClearAllFocus:
{
contentItem.focus = true
}
}
Timer

View file

@ -36,22 +36,7 @@ Menu
}
MenuItem
{
text:
{
var result = model.name
if(model.metadata.brand != undefined && model.metadata.brand != "Generic")
{
result = model.metadata.brand + " " + result
}
if(model.metadata.color_name != undefined && model.metadata.color_name != "Generic")
{
result = result + " (%1)".arg(model.metadata.color_name)
}
return result
}
text: model.name
checkable: true;
checked: model.id == Cura.MachineManager.activeMaterialId;
exclusiveGroup: group;

View file

@ -22,7 +22,7 @@ Menu
{
text: model.name
checkable: true
checked: Cura.MachineManager.activeQualityId == model.id
checked: Cura.MachineManager.activeQualityChangesId == "empty_quality_changes" && Cura.MachineManager.activeQualityType == model.metadata.quality_type
exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveQuality(model.id)
}
@ -38,7 +38,7 @@ Menu
id: customProfileInstantiator
model: UM.InstanceContainersModel
{
filter: menu.getFilter({ "type": "quality_changes", "extruder": null });
filter: { "type": "quality_changes", "extruder": null, "definition": Cura.MachineManager.filterQualityByMachine ? Cura.MachineManager.activeDefinitionId : "fdmprinter" };
onModelReset: customSeparator.visible = rowCount() > 0
}
@ -82,7 +82,7 @@ Menu
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
result.material = Cura.MachineManager.activeQualityMaterialId;
}
}
else

View file

@ -29,14 +29,14 @@ Rectangle
switch(Cura.MachineManager.printerOutputDevices[0].jobState)
{
case "printing":
case "pre_print": // heating, etc.
case "paused":
return true;
case "pre_print": // heating, etc.
case "wait_cleanup":
case "ready": // nut sure if this occurs, "" seems to be the ready state.
case "offline":
case "abort": // note sure if this jobState actually occurs in the wild
case "error": // after clicking abort you apparently get "error"
case "ready": // ready to print or getting ready
case "": // ready to print or getting ready
default:
return false;
@ -235,12 +235,12 @@ Rectangle
text: {
var result = "";
var jobState = Cura.MachineManager.printerOutputDevices[0].jobState;
if (!printerConnected) {
return "";
}
if (lastJobState !== jobState) {
var jobState = Cura.MachineManager.printerOutputDevices[0].jobState;
if (lastJobState != jobState) {
// the userClicked message must disappear when an "automated" jobState comes by
userClicked = false;
lastJobState = jobState;

View file

@ -46,11 +46,11 @@ UM.PreferencesPage
UM.Preferences.resetPreference("view/top_layer_count");
topLayerCountCheckbox.checked = boolCheck(UM.Preferences.getValue("view/top_layer_count"))
if (plugins.model.find("id", "SliceInfoPlugin") > -1) {
if (plugins.find("id", "SliceInfoPlugin") > -1) {
UM.Preferences.resetPreference("info/send_slice_info")
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
}
if (plugins.model.find("id", "UpdateChecker") > -1) {
if (plugins.find("id", "UpdateChecker") > -1) {
UM.Preferences.resetPreference("info/automatic_update_check")
checkUpdatesCheckbox.checked = boolCheck(UM.Preferences.getValue("info/automatic_update_check"))
}
@ -58,6 +58,9 @@ UM.PreferencesPage
Column
{
//: Model used to check if a plugin exists
UM.PluginsModel { id: plugins }
//: Language selection label
UM.I18nCatalog{id: catalog; name:"cura"}
@ -168,7 +171,7 @@ UM.PreferencesPage
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Moves the camera so the object is in the center of the view when an object is selected")
text: catalog.i18nc("@info:tooltip","Moves the camera so the model is in the center of the view when an model is selected")
CheckBox
{
@ -182,12 +185,12 @@ UM.PreferencesPage
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should objects on the platform be moved so that they no longer intersect?")
text: catalog.i18nc("@info:tooltip", "Should models on the platform be moved so that they no longer intersect?")
CheckBox
{
id: pushFreeCheckbox
text: catalog.i18nc("@option:check", "Ensure objects are kept apart")
text: catalog.i18nc("@option:check", "Ensure models are kept apart")
checked: boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked)
}
@ -247,12 +250,12 @@ UM.PreferencesPage
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","Should objects be scaled to the build volume if they are too large?")
text: catalog.i18nc("@info:tooltip","Should models be scaled to the build volume if they are too large?")
CheckBox
{
id: scaleToFitCheckbox
text: catalog.i18nc("@option:check","Scale large objects")
text: catalog.i18nc("@option:check","Scale large models")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked)
}
@ -261,12 +264,12 @@ UM.PreferencesPage
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip","An object may appear extremely small if its unit is for example in meters rather than millimeters. Should these objects be scaled up?")
text: catalog.i18nc("@info:tooltip","An model may appear extremely small if its unit is for example in meters rather than millimeters. Should these models be scaled up?")
CheckBox
{
id: scaleTinyCheckbox
text: catalog.i18nc("@option:check","Scale extremely small objects")
text: catalog.i18nc("@option:check","Scale extremely small models")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_tiny_meshes", checked)
}
@ -301,7 +304,7 @@ UM.PreferencesPage
}
UM.TooltipArea {
visible: plugins.model.find("id", "UpdateChecker") > -1
visible: plugins.find("id", "UpdateChecker") > -1
width: childrenRect.width
height: visible ? childrenRect.height : 0
text: catalog.i18nc("@info:tooltip","Should Cura check for updates when the program is started?")
@ -316,7 +319,7 @@ UM.PreferencesPage
}
UM.TooltipArea {
visible: plugins.model.find("id", "SliceInfoPlugin") > -1
visible: plugins.find("id", "SliceInfoPlugin") > -1
width: childrenRect.width
height: visible ? childrenRect.height : 0
text: catalog.i18nc("@info:tooltip","Should anonymous data about your print be sent to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.")
@ -329,13 +332,5 @@ UM.PreferencesPage
onCheckedChanged: UM.Preferences.setValue("info/send_slice_info", checked)
}
}
//: Invisible list used to check if a plugin exists
ListView
{
id: plugins
model: UM.PluginsModel { }
visible: false
}
}
}

View file

@ -18,7 +18,10 @@ UM.ManagementPage
}
activeId: Cura.MachineManager.activeMachineId
activeIndex: {
activeIndex: activeMachineIndex()
function activeMachineIndex()
{
for(var i = 0; i < model.rowCount(); i++) {
if (model.getItem(i).id == Cura.MachineManager.activeMachineId) {
return i;
@ -142,7 +145,16 @@ UM.ManagementPage
{
id: confirmDialog;
object: base.currentItem && base.currentItem.name ? base.currentItem.name : "";
onYes: Cura.MachineManager.removeMachine(base.currentItem.id);
onYes:
{
Cura.MachineManager.removeMachine(base.currentItem.id);
if(!base.currentItem)
{
objectList.currentIndex = activeMachineIndex()
}
//Force updating currentItem and the details panel
objectList.onCurrentIndexChanged()
}
}
UM.RenameDialog
@ -152,11 +164,20 @@ UM.ManagementPage
onAccepted:
{
Cura.MachineManager.renameMachine(base.currentItem.id, newName.trim());
//Reselect current item to update details panel
var index = objectList.currentIndex
objectList.currentIndex = -1
objectList.currentIndex = index
//Force updating currentItem and the details panel
objectList.onCurrentIndexChanged()
}
}
Connections
{
target: Cura.MachineManager
onGlobalContainerChanged:
{
objectList.currentIndex = activeMachineIndex()
objectList.onCurrentIndexChanged()
}
}
}
}

View file

@ -47,7 +47,17 @@ UM.ManagementPage
return -1;
}
scrollviewCaption: "Printer: %1, Nozzle: %2".arg(Cura.MachineManager.activeMachineName).arg(Cura.MachineManager.activeVariantName)
scrollviewCaption:
{
if (Cura.MachineManager.hasVariants)
{
catalog.i18nc("@action:label %1 is printer name, %2 is how this printer names variants, %3 is variant name", "Printer: %1, %2: %3").arg(Cura.MachineManager.activeMachineName).arg(Cura.MachineManager.activeDefinitionVariantsName).arg(Cura.MachineManager.activeVariantName)
}
else
{
catalog.i18nc("@action:label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName)
}
}
detailsVisible: true
section.property: "section"
@ -67,8 +77,6 @@ UM.ManagementPage
enabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMaterialId
onClicked: Cura.MachineManager.setActiveMaterial(base.currentItem.id)
},
/*
// disabled because it has a lot of issues
Button
{
text: catalog.i18nc("@action:button", "Duplicate");
@ -91,7 +99,7 @@ UM.ManagementPage
Cura.MachineManager.setActiveMaterial(material_id)
}
}, */
},
Button
{
text: catalog.i18nc("@action:button", "Remove");
@ -188,7 +196,7 @@ UM.ManagementPage
object: base.currentItem != null ? base.currentItem.name : ""
onYes:
{
var containers = Cura.ContainerManager.findInstanceContainers({"GUID": base.currentItem.metadata.GUID})
var containers = Cura.ContainerManager.findInstanceContainers({"id": base.currentItem.id})
for(var i in containers)
{
Cura.ContainerManager.removeContainer(containers[i])

View file

@ -0,0 +1,62 @@
// Copyright (c) 2016 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Tab
{
id: base
property string extruderId: "";
property string quality: "";
property string material: "";
TableView
{
anchors.fill: parent
anchors.margins: UM.Theme.getSize("default_margin").width
TableViewColumn
{
role: "label"
title: catalog.i18nc("@title:column", "Setting")
width: parent.width * 0.4
}
TableViewColumn
{
role: "profile_value"
title: catalog.i18nc("@title:column", "Profile")
width: parent.width * 0.18
}
TableViewColumn
{
role: "user_value"
title: catalog.i18nc("@title:column", "Current"); visible: quality == Cura.MachineManager.activeQualityId
width: parent.width * 0.18
}
TableViewColumn
{
role: "unit"
title: catalog.i18nc("@title:column", "Unit")
width: parent.width * 0.14
}
section.property: "category"
section.delegate: Label
{
text: section
font.bold: true
}
model: Cura.QualitySettingsModel
{
extruderId: base.extruderId != "" ? base.extruderId : ""
quality: base.quality != null ? base.quality : ""
material: base.material != null ? base.material : ""
}
}
}

View file

@ -18,13 +18,13 @@ UM.ManagementPage
{
filter:
{
var result = { "type": "quality" };
var result = { "type": "quality*", "extruder": null };
if(Cura.MachineManager.filterQualityByMachine)
{
result.definition = Cura.MachineManager.activeDefinitionId;
if(Cura.MachineManager.hasMaterials)
{
result.material = Cura.MachineManager.activeMaterialId;
result.material = Cura.MachineManager.allActiveMaterialIds[Cura.MachineManager.activeMachineId];
}
}
else
@ -76,9 +76,9 @@ UM.ManagementPage
{
var selectedContainer;
if (base.currentItem.id == Cura.MachineManager.activeQualityId) {
selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser();
selectedContainer = Cura.ContainerManager.createQualityChanges();
} else {
selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id);
selectedContainer = Cura.ContainerManager.duplicateQualityOrQualityChanges(base.currentItem.name);
}
base.selectContainer(selectedContainer);
@ -106,13 +106,15 @@ UM.ManagementPage
text: catalog.i18nc("@action:button", "Import");
iconName: "document-import";
onClicked: importDialog.open();
enabled: false
},
Button
{
text: catalog.i18nc("@action:button", "Export")
iconName: "document-export"
onClicked: exportDialog.open()
enabled: currentItem != null
// enabled: currentItem != null
enabled: false
}
]
@ -152,14 +154,14 @@ UM.ManagementPage
return catalog.i18nc("@action:button", "Update profile with current settings");
}
enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
onClicked: Cura.MachineManager.updateQualityContainerFromUserContainer()
onClicked: Cura.ContainerManager.updateQualityChanges()
}
Button
{
text: catalog.i18nc("@action:button", "Discard current settings");
enabled: Cura.MachineManager.hasUserSettings
onClicked: Cura.MachineManager.clearUserSettings();
onClicked: Cura.ContainerManager.clearUserContainers();
}
}
@ -173,7 +175,7 @@ UM.ManagementPage
Label {
id: defaultsMessage
visible: currentItem && !currentItem.metadata.has_settings
visible: false
text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.")
wrapMode: Text.WordWrap
width: parent.width
@ -187,69 +189,31 @@ UM.ManagementPage
}
}
ScrollView {
id: scrollView
TabView
{
anchors.left: parent.left
anchors.top: profileNotices.visible ? profileNotices.bottom : profileNotices.anchors.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.right: parent.right
anchors.bottom: parent.bottom
ListView {
model: Cura.ContainerSettingsModel{ containers:
ProfileTab
{
if (!currentItem) {
return []
} else if (currentItem.id == Cura.MachineManager.activeQualityId) {
return [base.currentItem.id, Cura.MachineManager.activeUserProfileId]
} else {
return [base.currentItem.id]
title: catalog.i18nc("@title:tab", "Global Settings");
quality: base.currentItem != null ? base.currentItem.id : "";
material: Cura.MachineManager.allActiveMaterialIds.global ? Cura.MachineManager.allActiveMaterialIds.global : ""
}
}
}
delegate: Row {
property variant setting: model
spacing: UM.Theme.getSize("default_margin").width/2
Label {
text: model.label
elide: Text.ElideMiddle
width: scrollView.width / 100 * 40
}
Repeater {
model: setting.values.length
Label {
text: setting.values[index].toString()
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
}
}
Label {
text: model.unit
}
}
header: Row {
visible: currentItem && 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 && currentItem.id == Cura.MachineManager.activeQualityId
font.bold: true
}
}
section.property: "category"
section.criteria: ViewSection.FullString
section.delegate: Label {
text: section
font.bold: true
Repeater
{
model: Cura.ExtrudersModel { }
ProfileTab
{
title: model.name;
extruderId: model.id;
quality: base.currentItem != null ? base.currentItem.id : "";
material: Cura.MachineManager.allActiveMaterialIds[model.id]
}
}
}
@ -263,17 +227,25 @@ UM.ManagementPage
{
id: confirmDialog
object: base.currentItem != null ? base.currentItem.name : ""
onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id)
onYes:
{
var name = base.currentItem.name;
Cura.ContainerManager.removeQualityChanges(name)
if(Cura.MachineManager.activeQualityName == name)
{
Cura.MachineManager.setActiveQuality(base.model.getItem(0).name)
}
}
}
UM.RenameDialog
{
id: renameDialog;
object: base.currentItem != null ? base.currentItem.name : ""
property bool removeWhenRejected: false
onAccepted: Cura.MachineManager.renameQualityContainer(base.currentItem.id, newName)
onAccepted: Cura.ContainerManager.renameQualityChanges(base.currentItem.name, newName)
onRejected: {
if(removeWhenRejected) {
Cura.MachineManager.removeQualityContainer(base.currentItem.id)
Cura.ContainerManager.removeQualityChanges(base.currentItem.name)
}
}
}

View file

@ -14,6 +14,8 @@ Column
id: printMonitor
property var connectedPrinter: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null
Cura.ExtrudersModel { id: extrudersModel }
Label
{
text: printerConnected ? connectedPrinter.connectionText : catalog.i18nc("@label", "The printer is not connected.")
@ -34,7 +36,7 @@ Column
delegate: Loader
{
sourceComponent: monitorItem
property string label: machineExtruderCount.properties.value > 1 ? catalog.i18nc("@label", "Hotend Temperature %1").arg(index + 1) : catalog.i18nc("@label", "Hotend Temperature")
property string label: machineExtruderCount.properties.value > 1 ? extrudersModel.getItem(index).name : catalog.i18nc("@label", "Hotend")
property string value: printerConnected ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : ""
}
}
@ -44,7 +46,7 @@ Column
delegate: Loader
{
sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Bed Temperature")
property string label: catalog.i18nc("@label", "Build plate")
property string value: printerConnected ? Math.round(connectedPrinter.bedTemperature) + "°C" : ""
}
}
@ -80,21 +82,24 @@ Column
Row
{
height: UM.Theme.getSize("setting_control").height
width: base.width - 2 * UM.Theme.getSize("default_margin").width
Label
{
width: parent.width * 0.4
anchors.verticalCenter: parent.verticalCenter
text: label
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
width: base.width * 0.4
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
}
Label
{
width: parent.width * 0.6
anchors.verticalCenter: parent.verticalCenter
text: value
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
}
}
}

View file

@ -14,9 +14,7 @@ Rectangle {
property real progress: UM.Backend.progress;
property int backendState: UM.Backend.state;
property bool activity: Printer.getPlatformActivity;
//Behavior on progress { NumberAnimation { duration: 250; } }
property int totalHeight: childrenRect.height + UM.Theme.getSize("default_margin").height
property string fileBaseName
property string statusText:
@ -26,21 +24,18 @@ Rectangle {
return catalog.i18nc("@label:PrintjobStatus", "Please load a 3d model");
}
if(base.backendState == 1)
switch(base.backendState)
{
case 1:
return catalog.i18nc("@label:PrintjobStatus", "Preparing to slice...");
}
else if(base.backendState == 2)
{
case 2:
return catalog.i18nc("@label:PrintjobStatus", "Slicing...");
}
else if(base.backendState == 3)
{
case 3:
return catalog.i18nc("@label:PrintjobStatus %1 is target operation","Ready to %1").arg(UM.OutputDeviceManager.activeDeviceShortDescription);
}
else if(base.backendState == 4)
{
return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice")
case 4:
return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice");
default:
return "";
}
}
@ -126,12 +121,29 @@ Rectangle {
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") :
control.pressed ? UM.Theme.getColor("action_button_active_border") :
control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border")
color: !control.enabled ? UM.Theme.getColor("action_button_disabled") :
control.pressed ? UM.Theme.getColor("action_button_active") :
control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
border.color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_border");
else if(control.pressed)
return UM.Theme.getColor("action_button_active_border");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_border");
else
return UM.Theme.getColor("action_button_border");
}
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled");
else if(control.pressed)
return UM.Theme.getColor("action_button_active");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered");
else
return UM.Theme.getColor("action_button");
}
Behavior on color { ColorAnimation { duration: 50; } }
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2)
@ -139,9 +151,17 @@ Rectangle {
Label {
id: actualLabel
anchors.centerIn: parent
color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") :
control.pressed ? UM.Theme.getColor("action_button_active_text") :
control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text")
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_text");
else if(control.pressed)
return UM.Theme.getColor("action_button_active_text");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_text");
else
return UM.Theme.getColor("action_button_text");
}
font: UM.Theme.getFont("action_button")
text: control.text;
}
@ -167,12 +187,28 @@ Rectangle {
background: Rectangle {
id: deviceSelectionIcon
border.width: UM.Theme.getSize("default_lining").width
border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") :
control.pressed ? UM.Theme.getColor("action_button_active_border") :
control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border")
color: !control.enabled ? UM.Theme.getColor("action_button_disabled") :
control.pressed ? UM.Theme.getColor("action_button_active") :
control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
border.color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_border");
else if(control.pressed)
return UM.Theme.getColor("action_button_active_border");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_border");
else
return UM.Theme.getColor("action_button_border");
}
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled");
else if(control.pressed)
return UM.Theme.getColor("action_button_active");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered");
else
return UM.Theme.getColor("action_button");
}
Behavior on color { ColorAnimation { duration: 50; } }
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("save_button_text_margin").width / 2;
@ -186,9 +222,17 @@ Rectangle {
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width
sourceSize.height: height
color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") :
control.pressed ? UM.Theme.getColor("action_button_active_text") :
control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text");
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_text");
else if(control.pressed)
return UM.Theme.getColor("action_button_active_text");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_text");
else
return UM.Theme.getColor("action_button_text");
}
source: UM.Theme.getIcon("arrow_bottom");
}
}

View file

@ -95,26 +95,31 @@ ScrollView
{
target: provider
property: "containerStackId"
when: model.settable_per_extruder || (inheritStackProvider.properties.global_inherits_stack != -1 && inheritStackProvider.properties.global_inherits_stack != null)
when: model.settable_per_extruder || model.settable_per_mesh || (inheritStackProvider.properties.global_inherits_stack != null && inheritStackProvider.properties.global_inherits_stack >= 0);
value:
{
if(inheritStackProvider.properties.global_inherits_stack == -1 || inheritStackProvider.properties.global_inherits_stack == null)
if(!model.settable_per_extruder && !model.settable_per_mesh)
{
if( ExtruderManager.activeExtruderStackId)
//Not settable per extruder, so we must pick global.
return Cura.MachineManager.activeMachineId;
}
if(inheritStackProvider.properties.global_inherits_stack != null && inheritStackProvider.properties.global_inherits_stack >= 0)
{
return ExtruderManager.activeExtruderStackId
//We have global_inherits_stack, so pick that stack.
return ExtruderManager.extruderIds[String(inheritStackProvider.properties.global_inherits_stack)];
}
else
if(ExtruderManager.activeExtruderStackId)
{
return Cura.MachineManager.activeMachineId
//We're on an extruder tab. Pick the current extruder.
return ExtruderManager.activeExtruderStackId;
}
}
return ExtruderManager.extruderIds[String(inheritStackProvider.properties.global_inherits_stack)]
//No extruder tab is selected. Pick the global stack. Shouldn't happen any more since we removed the global tab.
return Cura.MachineManager.activeMachineId;
}
}
// Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
// so we bypass that to make a dedicated provider.
// so we bypass that to make a dedicated provider).
UM.SettingPropertyProvider
{
id: inheritStackProvider

View file

@ -183,8 +183,23 @@ Column
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:");
text:
{
var label;
if(Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials)
{
label = "%1 & %2".arg(Cura.MachineManager.activeDefinitionVariantsName).arg(catalog.i18nc("@label","Material"));
}
else if(Cura.MachineManager.hasVariants)
{
label = Cura.MachineManager.activeDefinitionVariantsName;
}
else
{
label = catalog.i18nc("@label","Material");
}
return "%1:".arg(label);
}
anchors.verticalCenter: parent.verticalCenter
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width

View file

@ -213,42 +213,54 @@ Item
id: adhesionHelperLabel
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: brimCheckBox.verticalCenter
anchors.verticalCenter: adhesionCheckBox.verticalCenter
width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width
//: Bed adhesion label
text: catalog.i18nc("@label:listbox", "Bed Adhesion:");
text: catalog.i18nc("@label", "Helper Parts:");
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
CheckBox{
id: brimCheckBox
property alias _hovered: brimMouseArea.containsMouse
id: adhesionCheckBox
property alias _hovered: adhesionMouseArea.containsMouse
anchors.top: parent.top
anchors.left: adhesionHelperLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
//: Setting enable skirt adhesion checkbox
text: catalog.i18nc("@option:check", "Print Brim");
//: Setting enable printing build-plate adhesion helper checkbox
text: catalog.i18nc("@option:check", "Print Build Plate Adhesion");
style: UM.Theme.styles.checkbox;
enabled: base.settingsEnabled
checked: platformAdhesionType.properties.value == "brim"
checked: platformAdhesionType.properties.value != "skirt"
MouseArea {
id: brimMouseArea
id: adhesionMouseArea
anchors.fill: parent
hoverEnabled: true
enabled: base.settingsEnabled
onClicked:
{
platformAdhesionType.setPropertyValue("value", !parent.checked ? "brim" : "skirt")
var adhesionType = "skirt";
if(!parent.checked)
{
// Remove the "user" setting to see if the rest of the stack prescribes a brim or a raft
platformAdhesionType.removeFromContainer(0);
adhesionType = platformAdhesionType.properties.value;
if(adhesionType == "skirt")
{
// If the rest of the stack doesn't prescribe an adhesion-type, default to a brim
adhesionType = "brim";
}
}
platformAdhesionType.setPropertyValue("value", adhesionType);
}
onEntered:
{
base.showTooltip(brimCheckBox, Qt.point(-brimCheckBox.x, 0),
catalog.i18nc("@label", "Enable printing a brim. This will add a single-layer-thick flat area around your object which is easy to cut off afterwards."));
base.showTooltip(adhesionCheckBox, Qt.point(-adhesionCheckBox.x, 0),
catalog.i18nc("@label", "Enable printing a brim or raft. This will add a flat area around or under your object which is easy to cut off afterwards."));
}
onExited:
{
@ -264,7 +276,7 @@ Item
anchors.verticalCenter: supportCheckBox.verticalCenter
width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width
//: Support label
text: catalog.i18nc("@label:listbox", "Support:");
text: "";
font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text");
}
@ -274,7 +286,7 @@ Item
visible: machineExtruderCount.properties.value <= 1
property alias _hovered: supportMouseArea.containsMouse
anchors.top: brimCheckBox.bottom
anchors.top: adhesionCheckBox.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: supportHelperLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
@ -311,7 +323,7 @@ Item
visible: machineExtruderCount.properties.value > 1
model: extruderModel
anchors.top: brimCheckBox.bottom
anchors.top: adhesionCheckBox.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: supportHelperLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
@ -354,12 +366,11 @@ Item
Component.onCompleted: populateExtruderModel()
}
//: Invisible list used to populate the extrudelModel
ListView
//: Model used to populate the extrudelModel
Cura.ExtrudersModel
{
id: extruders
model: Cura.ExtrudersModel { onModelChanged: populateExtruderModel() }
visible: false
onModelChanged: populateExtruderModel()
}
}
@ -370,10 +381,10 @@ Item
text: catalog.i18nc("@label", "Don't print support"),
color: ""
})
for(var extruderNumber = 0; extruderNumber < extruders.model.rowCount() ; extruderNumber++) {
for(var extruderNumber = 0; extruderNumber < extruders.rowCount() ; extruderNumber++) {
extruderModel.append({
text: catalog.i18nc("@label", "Print using %1").arg(extruders.model.getItem(extruderNumber).name),
color: extruders.model.getItem(extruderNumber).color
text: catalog.i18nc("@label", "Print support using %1").arg(extruders.getItem(extruderNumber).name),
color: extruders.getItem(extruderNumber).color
})
}
}

View file

@ -5,6 +5,7 @@ definition = fdmprinter
[metadata]
type = quality
quality_type = high
weight = -3
[values]

View file

@ -5,6 +5,7 @@ definition = fdmprinter
[metadata]
type = quality
quality_type = low
weight = -1
[values]

View file

@ -5,6 +5,7 @@ definition = fdmprinter
[metadata]
type = quality
quality_type = normal
weight = -2
[values]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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