Merge branch 'master' into upgrade_to_2.4

This commit is contained in:
Simon Edwards 2016-12-05 11:01:33 +01:00
commit 13af609830
12 changed files with 14160 additions and 91 deletions

View File

@ -765,7 +765,7 @@ class BuildVolume(SceneNode):
skirt_distance = self._getSettingFromAdhesionExtruder("skirt_gap")
skirt_line_count = self._getSettingFromAdhesionExtruder("skirt_line_count")
bed_adhesion_size = skirt_distance + (skirt_line_count * self._getSettingFromAdhesionExtruder("skirt_brim_line_width"))
if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1:
if len(ExtruderManager.getInstance().getUsedExtruderStacks()) > 1:
adhesion_extruder_nr = int(self._global_container_stack.getProperty("adhesion_extruder_nr", "value"))
extruder_values = ExtruderManager.getInstance().getAllExtruderValues("skirt_brim_line_width")
del extruder_values[adhesion_extruder_nr] # Remove the value of the adhesion extruder nr.

View File

@ -231,6 +231,8 @@ class CuraApplication(QtApplication):
shell
wall_thickness
top_bottom_thickness
z_seam_x
z_seam_y
infill
infill_sparse_density
material

View File

@ -35,6 +35,10 @@ class MachineManager(QObject):
self.globalContainerChanged.connect(self.activeQualityChanged)
self._stacks_have_errors = None
self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_variant")[0]
self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_material")[0]
self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_quality")[0]
self._empty_quality_changes_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_quality_changes")[0]
self._onGlobalContainerChanged()
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
@ -49,11 +53,6 @@ class MachineManager(QObject):
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged)
self.activeStackChanged.connect(self.activeStackValueChanged)
self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0]
self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0]
self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0]
self._empty_quality_changes_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality_changes")[0]
Preferences.getInstance().addPreference("cura/active_machine", "")
self._global_event_keys = set()

View File

@ -12,6 +12,8 @@ from UM.Job import Job
from UM.Preferences import Preferences
from .WorkspaceDialog import WorkspaceDialog
import xml.etree.ElementTree as ET
from cura.Settings.ExtruderManager import ExtruderManager
import zipfile
@ -52,7 +54,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
else:
Logger.log("w", "Could not find reader that was able to read the scene data for 3MF workspace")
return WorkspaceReader.PreReadResult.failed
machine_name = ""
# Check if there are any conflicts, so we can ask the user.
archive = zipfile.ZipFile(file_name, "r")
cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")]
@ -62,16 +64,19 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
quality_changes_conflict = False
for container_stack_file in container_stack_files:
container_id = self._stripFileToId(container_stack_file)
serialized = archive.open(container_stack_file).read().decode("utf-8")
if machine_name == "":
machine_name = self._getMachineNameFromSerializedStack(serialized)
stacks = self._container_registry.findContainerStacks(id=container_id)
if stacks:
# Check if there are any changes at all in any of the container stacks.
id_list = self._getContainerIdListFromSerialized(archive.open(container_stack_file).read().decode("utf-8"))
id_list = self._getContainerIdListFromSerialized(serialized)
for index, container_id in enumerate(id_list):
if stacks[0].getContainer(index).getId() != container_id:
machine_conflict = True
break
Job.yieldThread()
material_labels = []
material_conflict = False
xml_material_profile = self._getXmlProfileClass()
if self._material_container_suffix is None:
@ -81,12 +86,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
for material_container_file in material_container_files:
container_id = self._stripFileToId(material_container_file)
materials = self._container_registry.findInstanceContainers(id=container_id)
material_labels.append(self._getMaterialLabelFromSerialized(archive.open(material_container_file).read().decode("utf-8")))
if materials and not materials[0].isReadOnly(): # Only non readonly materials can be in conflict
material_conflict = True
Job.yieldThread()
# Check if any quality_changes instance container is in conflict.
instance_container_files = [name for name in cura_file_names if name.endswith(self._instance_container_suffix)]
quality_name = ""
quality_type = ""
num_settings_overriden_by_quality_changes = 0 # How many settings are changed by the quality changes
for instance_container_file in instance_container_files:
container_id = self._stripFileToId(instance_container_file)
instance_container = InstanceContainer(container_id)
@ -95,35 +103,58 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
instance_container.deserialize(archive.open(instance_container_file).read().decode("utf-8"))
container_type = instance_container.getMetaDataEntry("type")
if container_type == "quality_changes":
quality_name = instance_container.getName()
num_settings_overriden_by_quality_changes += len(instance_container._instances)
# Check if quality changes already exists.
quality_changes = self._container_registry.findInstanceContainers(id = container_id)
if quality_changes:
# Check if there really is a conflict by comparing the values
if quality_changes[0] != instance_container:
quality_changes_conflict = True
break
elif container_type == "quality":
# If the quality name is not set (either by quality or changes, set it now)
# Quality changes should always override this (as they are "on top")
if quality_name == "":
quality_name = instance_container.getName()
quality_type = instance_container.getName()
Job.yieldThread()
num_visible_settings = 0
try:
archive.open("Cura/preferences.cfg")
temp_preferences = Preferences()
temp_preferences.readFromFile(io.TextIOWrapper(archive.open("Cura/preferences.cfg"))) # We need to wrap it, else the archive parser breaks.
visible_settings_string = temp_preferences.getValue("general/visible_settings")
if visible_settings_string is not None:
num_visible_settings = len(visible_settings_string.split(";"))
active_mode = temp_preferences.getValue("cura/active_mode")
if not active_mode:
active_mode = Preferences.getInstance().getValue("cura/active_mode")
except KeyError:
# If there is no preferences file, it's not a workspace, so notify user of failure.
Logger.log("w", "File %s is not a valid workspace.", file_name)
return WorkspaceReader.PreReadResult.failed
if machine_conflict or quality_changes_conflict or material_conflict:
# There is a conflict; User should choose to either update the existing data, add everything as new data or abort
self._dialog.setMachineConflict(machine_conflict)
self._dialog.setQualityChangesConflict(quality_changes_conflict)
self._dialog.setMaterialConflict(material_conflict)
self._dialog.show()
# Show the dialog, informing the user what is about to happen.
self._dialog.setMachineConflict(machine_conflict)
self._dialog.setQualityChangesConflict(quality_changes_conflict)
self._dialog.setMaterialConflict(material_conflict)
self._dialog.setNumVisibleSettings(num_visible_settings)
self._dialog.setQualityName(quality_name)
self._dialog.setQualityType(quality_type)
self._dialog.setNumSettingsOverridenByQualityChanges(num_settings_overriden_by_quality_changes)
self._dialog.setActiveMode(active_mode)
self._dialog.setMachineName(machine_name)
self._dialog.setMaterialLabels(material_labels)
self._dialog.setHasObjectsOnPlate(Application.getInstance().getPlatformActivity)
self._dialog.show()
# Block until the dialog is closed.
self._dialog.waitForClose()
# Block until the dialog is closed.
self._dialog.waitForClose()
if self._dialog.getResult() == {}:
return WorkspaceReader.PreReadResult.cancelled
if self._dialog.getResult() == {}:
return WorkspaceReader.PreReadResult.cancelled
self._resolve_strategies = self._dialog.getResult()
self._resolve_strategies = self._dialog.getResult()
return WorkspaceReader.PreReadResult.accepted
@ -381,16 +412,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
ExtruderManager.getInstance().registerExtruder(None, global_stack.getId())
Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
# Notify everything/one that is to notify about changes.
for container in global_stack.getContainers():
global_stack.containersChanged.emit(container)
Job.yieldThread()
# Notify everything/one that is to notify about changes.
global_stack.containersChanged.emit(global_stack.getTop())
for stack in extruder_stacks:
stack.setNextStack(global_stack)
for container in stack.getContainers():
stack.containersChanged.emit(container)
Job.yieldThread()
stack.containersChanged.emit(stack.getTop())
# Actually change the active machine.
Application.getInstance().setGlobalContainerStack(global_stack)
@ -414,3 +442,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
container_string = parser["general"].get("containers", "")
container_list = container_string.split(",")
return [container_id for container_id in container_list if container_id != ""]
def _getMachineNameFromSerializedStack(self, serialized):
parser = configparser.ConfigParser(interpolation=None, empty_lines_in_values=False)
parser.read_string(serialized)
return parser["general"].get("name", "")
def _getMaterialLabelFromSerialized(self, serialized):
data = ET.fromstring(serialized)
metadata = data.iterfind("./um:metadata/um:name/um:label", {"um": "http://www.ultimaker.com/material"})
for entry in metadata:
return entry.text
pass

View File

@ -3,10 +3,13 @@ from PyQt5.QtQml import QQmlComponent, QQmlContext
from UM.PluginRegistry import PluginRegistry
from UM.Application import Application
from UM.Logger import Logger
from UM.i18n import i18nCatalog
from UM.Settings.ContainerRegistry import ContainerRegistry
import os
import threading
import time
i18n_catalog = i18nCatalog("cura")
class WorkspaceDialog(QObject):
showDialogSignal = pyqtSignal()
@ -28,10 +31,97 @@ class WorkspaceDialog(QObject):
self._has_quality_changes_conflict = False
self._has_machine_conflict = False
self._has_material_conflict = False
self._num_visible_settings = 0
self._active_mode = ""
self._quality_name = ""
self._num_settings_overriden_by_quality_changes = 0
self._quality_type = ""
self._machine_name = ""
self._material_labels = []
self._objects_on_plate = False
machineConflictChanged = pyqtSignal()
qualityChangesConflictChanged = pyqtSignal()
materialConflictChanged = pyqtSignal()
numVisibleSettingsChanged = pyqtSignal()
activeModeChanged = pyqtSignal()
qualityNameChanged = pyqtSignal()
numSettingsOverridenByQualityChangesChanged = pyqtSignal()
qualityTypeChanged = pyqtSignal()
machineNameChanged = pyqtSignal()
materialLabelsChanged = pyqtSignal()
objectsOnPlateChanged = pyqtSignal()
@pyqtProperty(bool, notify=objectsOnPlateChanged)
def hasObjectsOnPlate(self):
return self._objects_on_plate
def setHasObjectsOnPlate(self, objects_on_plate):
self._objects_on_plate = objects_on_plate
self.objectsOnPlateChanged.emit()
@pyqtProperty("QVariantList", notify = materialLabelsChanged)
def materialLabels(self):
return self._material_labels
def setMaterialLabels(self, material_labels):
self._material_labels = material_labels
self.materialLabelsChanged.emit()
@pyqtProperty(str, notify = machineNameChanged)
def machineName(self):
return self._machine_name
def setMachineName(self, machine_name):
self._machine_name = machine_name
self.machineNameChanged.emit()
@pyqtProperty(str, notify=qualityTypeChanged)
def qualityType(self):
return self._quality_type
def setQualityType(self, quality_type):
self._quality_type = quality_type
self.qualityTypeChanged.emit()
@pyqtProperty(int, notify=numSettingsOverridenByQualityChangesChanged)
def numSettingsOverridenByQualityChanges(self):
return self._num_settings_overriden_by_quality_changes
def setNumSettingsOverridenByQualityChanges(self, num_settings_overriden_by_quality_changes):
self._num_settings_overriden_by_quality_changes = num_settings_overriden_by_quality_changes
self.numSettingsOverridenByQualityChangesChanged.emit()
@pyqtProperty(str, notify=qualityNameChanged)
def qualityName(self):
return self._quality_name
def setQualityName(self, quality_name):
self._quality_name = quality_name
self.qualityNameChanged.emit()
@pyqtProperty(str, notify=activeModeChanged)
def activeMode(self):
return self._active_mode
def setActiveMode(self, active_mode):
if active_mode == 0:
self._active_mode = i18n_catalog.i18nc("@title:tab", "Recommended")
else:
self._active_mode = i18n_catalog.i18nc("@title:tab", "Custom")
self.activeModeChanged.emit()
@pyqtProperty(int, constant = True)
def totalNumberOfSettings(self):
return len(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0].getAllKeys())
@pyqtProperty(int, notify = numVisibleSettingsChanged)
def numVisibleSettings(self):
return self._num_visible_settings
def setNumVisibleSettings(self, num_visible_settings):
self._num_visible_settings = num_visible_settings
self.numVisibleSettingsChanged.emit()
@pyqtProperty(bool, notify = machineConflictChanged)
def machineConflict(self):
@ -95,8 +185,8 @@ class WorkspaceDialog(QObject):
@pyqtSlot()
## Used to notify the dialog so the lock can be released.
def notifyClosed(self):
if self._result is None:
self._result = {}
self._result = {}
self._visible = False
self._lock.release()
def hide(self):

View File

@ -10,16 +10,17 @@ import UM 1.1 as UM
UM.Dialog
{
title: catalog.i18nc("@title:window", "Import workspace conflict")
title: catalog.i18nc("@title:window", "Import Project")
width: 350 * Screen.devicePixelRatio;
minimumWidth: 350 * Screen.devicePixelRatio;
maximumWidth: 350 * Screen.devicePixelRatio;
height: 250 * Screen.devicePixelRatio;
minimumHeight: 250 * Screen.devicePixelRatio;
maximumHeight: 250 * Screen.devicePixelRatio;
width: 550
minimumWidth: 550
maximumWidth: 550
height: 350
minimumHeight: 350
maximumHeight: 350
property int comboboxHeight: 15
property int spacerHeight: 10
onClosing: manager.notifyClosed()
onVisibleChanged:
{
@ -48,7 +49,7 @@ UM.Dialog
// See http://stackoverflow.com/questions/7659442/listelement-fields-as-properties
Component.onCompleted:
{
append({"key": "override", "label": catalog.i18nc("@action:ComboBox option", "Override existing")});
append({"key": "override", "label": catalog.i18nc("@action:ComboBox option", "Update existing")});
append({"key": "new", "label": catalog.i18nc("@action:ComboBox option", "Create new")});
}
}
@ -56,36 +57,60 @@ UM.Dialog
Column
{
anchors.fill: parent
spacing: 2
Label
{
id: infoLabel
width: parent.width
text: catalog.i18nc("@action:label", "Cura detected a number of conflicts while importing the workspace. How would you like to resolve these?")
wrapMode: Text.Wrap
height: 50
id: titleLabel
text: catalog.i18nc("@action:title", "Summary - Cura Project")
font.pixelSize: 22
}
UM.TooltipArea
Rectangle
{
id: machineResolveTooltip
id: separator
color: "black"
width: parent.width
height: visible ? 25 : 0
text: catalog.i18nc("@info:tooltip", "How should the conflict in the machine be resolved?")
visible: manager.machineConflict
Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label","Machine")
width: 150
}
height: 1
}
Item // Spacer
{
height: spacerHeight
width: height
}
Label
{
text: catalog.i18nc("@action:label", "Printer settings")
font.bold: true
}
Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label", "Name")
width: parent.width / 3
}
Label
{
text: manager.machineName
width: parent.width / 3
}
UM.TooltipArea
{
id: machineResolveTooltip
width: parent.width / 3
height: visible ? comboboxHeight : 0
visible: manager.machineConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the machine be resolved?")
ComboBox
{
model: resolveStrategiesModel
textRole: "label"
id: machineResolveComboBox
width: parent.width
onActivated:
{
manager.setResolveStrategy("machine", resolveStrategiesModel.get(index).key)
@ -93,28 +118,46 @@ UM.Dialog
}
}
}
UM.TooltipArea
Item // Spacer
{
id: qualityChangesResolveTooltip
width: parent.width
height: visible ? 25 : 0
text: catalog.i18nc("@info:tooltip", "How should the conflict in the profile be resolved?")
visible: manager.qualityChangesConflict
Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label","Profile")
width: 150
}
height: spacerHeight
width: height
}
Label
{
text: catalog.i18nc("@action:label", "Profile settings")
font.bold: true
}
Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label", "Name")
width: parent.width / 3
}
Label
{
text: manager.qualityName
width: parent.width / 3
}
UM.TooltipArea
{
id: qualityChangesResolveTooltip
width: parent.width / 3
height: visible ? comboboxHeight : 0
visible: manager.qualityChangesConflict
text: catalog.i18nc("@info:tooltip", "How should the conflict in the profile be resolved?")
ComboBox
{
model: resolveStrategiesModel
textRole: "label"
id: qualityChangesResolveComboBox
width: parent.width
onActivated:
{
manager.setResolveStrategy("quality_changes", resolveStrategiesModel.get(index).key)
@ -122,28 +165,78 @@ UM.Dialog
}
}
}
UM.TooltipArea
Row
{
id: materialResolveTooltip
width: parent.width
height: visible ? 25 : 0
text: catalog.i18nc("@info:tooltip", "How should the conflict in the material(s) be resolved?")
visible: manager.materialConflict
Row
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label", "Derivative from")
width: parent.width / 3
}
Label
{
text: catalog.i18nc("@action:label", "%1, %2 override(s)" ).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
width: parent.width / 3
}
visible: manager.numSettingsOverridenByQualityChanges != 0
}
Item // Spacer
{
height: spacerHeight
width: height
}
Label
{
text: catalog.i18nc("@action:label", "Material settings")
font.bold: true
}
Repeater
{
model: manager.materialLabels
delegate: Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label","Material")
width: 150
text: catalog.i18nc("@action:label", "Name")
width: parent.width / 3
}
Label
{
text: modelData
width: parent.width / 3
}
}
}
Row
{
width: parent.width
height: childrenRect.height
visible: manager.materialConflict
Item
{
width: parent.width / 3 * 2
height: comboboxHeight
}
UM.TooltipArea
{
id: materialResolveTooltip
width: parent.width / 3
height: visible ? comboboxHeight : 0
text: catalog.i18nc("@info:tooltip", "How should the conflict in the material be resolved?")
ComboBox
{
model: resolveStrategiesModel
textRole: "label"
id: materialResolveComboBox
width: parent.width
onActivated:
{
manager.setResolveStrategy("material", resolveStrategiesModel.get(index).key)
@ -151,6 +244,60 @@ UM.Dialog
}
}
}
Item // Spacer
{
height: spacerHeight
width: height
}
Label
{
text: catalog.i18nc("@action:label", "Setting visibility")
font.bold: true
}
Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label", "Mode")
width: parent.width / 3
}
Label
{
text: manager.activeMode
width: parent.width / 3
}
}
Row
{
width: parent.width
height: childrenRect.height
Label
{
text: catalog.i18nc("@action:label", "Visible settings:")
width: parent.width / 3
}
Label
{
text: catalog.i18nc("@action:label", "%1 out of %2" ).arg(manager.numVisibleSettings).arg(manager.totalNumberOfSettings)
width: parent.width / 3
}
}
Item // Spacer
{
height: spacerHeight
width: height
}
Label
{
text: catalog.i18nc("@action:warning", "Loading a project will clear all models on the buildplate")
visible: manager.hasObjectsOnPlate
color: "red"
width: parent.width
wrapMode: Text.Wrap
}
}
}
rightButtons: [

View File

@ -961,17 +961,39 @@
"z_seam_type":
{
"label": "Z Seam Alignment",
"description": "Starting point of each path in a layer. When paths in consecutive layers start at the same point a vertical seam may show on the print. When aligning these at the back, the seam is easiest to remove. When placed randomly the inaccuracies at the paths' start will be less noticeable. When taking the shortest path the print will be quicker.",
"description": "Starting point of each path in a layer. When paths in consecutive layers start at the same point a vertical seam may show on the print. When aligning these near a user specified location, the seam is easiest to remove. When placed randomly the inaccuracies at the paths' start will be less noticeable. When taking the shortest path the print will be quicker.",
"type": "enum",
"options":
{
"back": "Back",
"back": "User Specified",
"shortest": "Shortest",
"random": "Random"
},
"default_value": "shortest",
"settable_per_mesh": true
},
"z_seam_x":
{
"label": "Z Seam X",
"description": "The X coordinate of the position near where to start printing each part in a layer.",
"unit": "mm",
"type": "float",
"default_value": 100.0,
"value": "machine_width / 2",
"enabled": "z_seam_type == 'back'",
"settable_per_mesh": true
},
"z_seam_y":
{
"label": "Z Seam Y",
"description": "The Y coordinate of the position near where to start printing each part in a layer.",
"unit": "mm",
"type": "float",
"default_value": 100.0,
"value": "machine_depth / 2",
"enabled": "z_seam_type == 'back'",
"settable_per_mesh": true
},
"skin_no_small_gaps_heuristic":
{
"label": "Ignore Small Z Gaps",
@ -1311,6 +1333,7 @@
"type": "float",
"resolve": "max(extruderValues('material_bed_temperature_layer_0'))",
"default_value": 60,
"value": "material_bed_temperature",
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
@ -3865,7 +3888,7 @@
"multiple_mesh_overlap":
{
"label": "Merged Meshes Overlap",
"description": "Make meshes which are placed directly close to each other overlap a bit. This makes them bond together better.",
"description": "Make meshes which are touching each other overlap a bit. This makes them bond together better.",
"type": "float",
"unit": "mm",
"default_value": 0.15,

View File

@ -0,0 +1,45 @@
{
"id": "printrbot_simple_extended",
"version": 2,
"name": "Printrbot Simple Metal Extended",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "samsector",
"manufacturer": "PrintrBot",
"category": "Other",
"platform": "printrbot_simple_metal_upgrade.stl",
"platform_offset": [0, -0.3, 0],
"file_formats": "text/x-gcode"
},
"overrides": {
"machine_name": { "default_value": "Printrbot Simple Metal Extended" },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 250 },
"machine_height": { "default_value": 235 },
"machine_depth": { "default_value": 150 },
"machine_center_is_zero": { "default_value": false },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": {
"default_value": [
[ 55, -20 ],
[ 55, 99999 ],
[ -49, 99999 ],
[ -49, -20 ]
]
},
"gantry_height": { "default_value": 99999 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM106 ;start with the fan on\nG28 X0 Y0 ;home X/Y\nG28 Z0 ;home Z\nG92 E0 ;zero the extruded length\nG29 ;initiate auto bed leveling sequence\n;start cleaning sequance\nG1 X250 Y150 Z15 F4000\nG1 X250 Y150 Z0.30 F1000\nG1 X1 Y150 Z0.25 E15.0 F2000\nG1 X1 Y150 Z0.25 E14.0 F4000\nG1 X1 Y1 Z0.25 F16000\nG1 X1 Y1 Z0.25 E15.0 F4000\nG92 E0\nM107 ;start with the fan off\n;end cleaning sequance\n;G92 X132.4 Y20 ;correct bed origin (G29 changes it)"
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM106 S0 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit\nG1 Z+1 E-5 F9000 ;move Z up a bit and retract even more\nG28 X0 Y0 ;home X/Y, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -290,7 +290,7 @@ Item
Action
{
id: loadWorkspaceAction
text: catalog.i18nc("@action:inmenu menubar:file","&Import project...");
text: catalog.i18nc("@action:inmenu menubar:file","&Open project...");
}
Action

View File

@ -71,13 +71,14 @@ UM.MainWindow
{
action: Cura.Actions.open;
}
RecentFilesMenu { }
MenuItem
{
action: Cura.Actions.loadWorkspace
}
RecentFilesMenu { }
MenuSeparator { }
MenuItem
@ -110,7 +111,7 @@ UM.MainWindow
MenuItem
{
id: saveWorkspaceMenu
text: catalog.i18nc("@title:menu menubar:file","Export project")
text: catalog.i18nc("@title:menu menubar:file","Save project")
onTriggered: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "file_type": "workspace" });
}

View File

@ -141,7 +141,7 @@ SettingItem
{
for(var i = 0; i < extruders_model.rowCount(); ++i)
{
if(extruders_model.getItem(i).index == propertyProvider.properties.value)
if(extruders_model.getItem(i).index == currentIndex)
{
control.color = extruders_model.getItem(i).color;
return;