diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index dc5594dc7b..aca91f866a 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -41,7 +41,7 @@ class PlatformPhysics: def _onSceneChanged(self, source): self._change_timer.start() - def _onChangeTimerFinished(self): + def _onChangeTimerFinished(self, was_triggered_by_tool=False): if not self._enabled: return @@ -71,14 +71,15 @@ class PlatformPhysics: # Check if this is the first time a project file node was loaded (disable auto drop in that case), defaults to True should_auto_drop = node.getSetting("auto_drop", True) + # This should NOT happen if the scene change was triggered by a tool (like translate), only on project load + if was_triggered_by_tool: + should_auto_drop = True + # If a node is grouped or it's loaded from a project file (auto-drop disabled), don't move it down if Preferences.getInstance().getValue("physics/automatic_drop_down") and not (node.getParent() and node.getParent().callDecoration("isGroup")) and node.isEnabled() and should_auto_drop: z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0 move_vector = move_vector.set(y=-bbox.bottom + z_offset) - # Enable auto-drop after processing the project file node for the first time - node.setSetting("auto_drop", False) - # If there is no convex hull for the node, start calculating it and continue. if not node.getDecorator(ConvexHullDecorator): node.addDecorator(ConvexHullDecorator()) @@ -167,4 +168,4 @@ class PlatformPhysics: node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator) self._enabled = True - self._onChangeTimerFinished() + self._onChangeTimerFinished(True) diff --git a/cura/Settings/MaterialSettingsVisibilityHandler.py b/cura/Settings/MaterialSettingsVisibilityHandler.py index a533a0cabd..b97987a18e 100644 --- a/cura/Settings/MaterialSettingsVisibilityHandler.py +++ b/cura/Settings/MaterialSettingsVisibilityHandler.py @@ -11,6 +11,7 @@ class MaterialSettingsVisibilityHandler(UM.Settings.Models.SettingVisibilityHand "default_material_print_temperature", "material_bed_temperature", "material_standby_temperature", + "material_flow_temp_graph", "cool_fan_speed", "retraction_amount", "retraction_speed", diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 66dfb6130e..b947c4eb39 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -77,7 +77,10 @@ class ThreeMFReader(MeshReader): # \returns Uranium SceneNode. def _convertSavitarNodeToUMNode(self, savitar_node): um_node = SceneNode() - um_node.setSetting("auto_drop", False) # Disable the auto-drop feature when loading a project file and processing the nodes for the first time + + # Disable the auto-drop feature when loading a project file and processing the nodes for the first time + um_node.setSetting("auto_drop", False) + transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) um_node.setTransformation(transformation) mesh_builder = MeshBuilder() diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py index 108cfa4c0d..31ce137ed7 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py @@ -54,30 +54,32 @@ class FirmwareUpdateCheckerJob(Job): # Nothing to parse, just get the string # TODO: In the future may be done by parsing a JSON file with diferent version for each printer model current_version = reader(current_version_file).readline().rstrip() - Logger.log("i", "Reading firmware version of %s: %s", machine_name, current_version) - # If it is the first time the version is checked, the checked_version is None + # If it is the first time the version is checked, the checked_version is '' checked_version = Preferences.getInstance().getValue("info/latest_checked_firmware") # If the checked_version is '', it's because is the first time we check firmware and in this case # we will not show the notification, but we will store it for the next time + Preferences.getInstance().setValue("info/latest_checked_firmware", current_version) + Logger.log("i", "Reading firmware version of %s: checked = %s - latest = %s", machine_name, checked_version, current_version) + + # The first time we want to store the current version, the notification will not be shown, + # because the new version of Cura will be release before the firmware and we don't want to + # notify the user when no new firmware version is available. if (checked_version != "") and (checked_version != current_version): - message = Message(i18n_catalog.i18nc("@info", "New %s firmware available

To ensure that your " - "%s is equiped with the latest features it is recommended " - "to update the firmware regularly. This can be done on the " - "%s (when connected to the network) or via USB." - % (machine_name, machine_name, machine_name))) + Logger.log("i", "SHOWING FIRMWARE UPDATE MESSAGE") + message = Message(i18n_catalog.i18nc("@info", "To ensure that your %s is equipped with the latest " + "features it is recommended to update the firmware " + "regularly. This can be done on the %s (when connected " + "to the network) or via USB." + % (machine_name, machine_name)), + title = i18n_catalog.i18nc("@info:title", "New %s firmware available" % machine_name)) message.addAction("download", i18n_catalog.i18nc("@action:button", "Download"), "[no_icon]", "[no_description]") # If we do this in a cool way, the download url should be available in the JSON file self._download_url = "https://ultimaker.com/en/resources/20500-upgrade-firmware" message.actionTriggered.connect(self.actionTriggered) - Application.getInstance().showMessage(message) - - # The first time we want to store the current version, the notification will not be shown, - # because the new version of Cura will be release before the firmware and we don't want to - # notify the user when no new firmware version is available. - Preferences.getInstance().setValue("info/latest_checked_firmware", current_version) + message.show() except Exception as e: Logger.log("w", "Failed to check for new version: %s", e) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index d0e77a15fe..5c3dc44f24 100755 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -5756,6 +5756,16 @@ "limit_to_extruder": "top_bottom_extruder_nr", "settable_per_mesh": true }, + "ironing_only_highest_layer": + { + "label": "Iron Only Highest Layer", + "description": "Only perform ironing on the very last layer of the mesh. This saves time if the lower layers don't need a smooth surface finish.", + "type": "bool", + "default_value": false, + "enabled": "ironing_enabled", + "limit_to_extruder": "top_bottom_extruder_nr", + "settable_per_mesh": true + }, "ironing_pattern": { "label": "Ironing Pattern", diff --git a/resources/definitions/prusa_i3_mk2.def.json b/resources/definitions/prusa_i3_mk2.def.json index d4425728d4..ef3ef8159e 100644 --- a/resources/definitions/prusa_i3_mk2.def.json +++ b/resources/definitions/prusa_i3_mk2.def.json @@ -41,7 +41,7 @@ "machine_max_jerk_e": { "default_value": 2.5 }, "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nM104 S{material_print_temperature} ; set extruder temp\nM140 S{material_bed_temperature} ; set bed temp\nM190 S{material_bed_temperature} ; wait for bed temp\nM109 S{material_print_temperature} ; wait for extruder temp\nG92 E0.0 ; reset extruder distance position\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E21.5 F1000.0 ; intro line\nG92 E0.0 ; reset extruder distance position" + "default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nM104 S{material_print_temperature} ; set extruder temp\nM140 S{material_bed_temperature} ; set bed temp\nM190 S{material_bed_temperature} ; wait for bed temp\nM109 S{material_print_temperature} ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG92 E0.0 ; reset extruder distance position\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E21.5 F1000.0 ; intro line\nG92 E0.0 ; reset extruder distance position" }, "machine_end_gcode": { "default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y210; home X axis and push Y forward\nM84 ; disable motors" diff --git a/resources/definitions/ultimaker2.def.json b/resources/definitions/ultimaker2.def.json index 1931e5f8e3..0a9a7bf7ce 100644 --- a/resources/definitions/ultimaker2.def.json +++ b/resources/definitions/ultimaker2.def.json @@ -89,9 +89,6 @@ "machine_max_feedrate_z": { "default_value": 40 }, - "machine_max_feedrate_e": { - "default_value": 45 - }, "machine_acceleration": { "default_value": 3000 }, diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index 728501e5ef..f65b436acc 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -402,19 +402,21 @@ Item Item { id: infillCellLeft + anchors.top: speedLabel.top - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 1.2 + anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 1.2 // FIXME better margin value anchors.left: parent.left + width: UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width - height: childrenRect.height + height: UM.Theme.getSize("sidebar_margin").height Text { id: infillLabel - //: Infill selection label - text: catalog.i18nc("@label", "Infill"); - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); + text: catalog.i18nc("@label", "Infill") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + anchors.top: parent.top anchors.topMargin: UM.Theme.getSize("sidebar_margin").height anchors.left: parent.left @@ -422,214 +424,246 @@ Item } } - Row + Item { id: infillCellRight - height: childrenRect.height; + height: infillSlider.height + enableGradualInfillCheckBox.height + (UM.Theme.getSize("sidebar_margin").height * 2) width: UM.Theme.getSize("sidebar").width * .55 - spacing: UM.Theme.getSize("sidebar_margin").width - anchors.left: infillCellLeft.right anchors.top: infillCellLeft.top anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - Repeater + Text { + id: selectedInfillRateText + + anchors.top: parent.top + anchors.left: infillSlider.left + anchors.leftMargin: (infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 + anchors.right: parent.right + + text: infillSlider.value + "%" + horizontalAlignment: Text.AlignLeft + + color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + } + + Slider { - id: infillListView - property int activeIndex: - { - for(var i = 0; i < infillModel.count; ++i) - { - var density = parseInt(infillDensity.properties.value); - var steps = parseInt(infillSteps.properties.value); - if(density > infillModel.get(i).percentageMin && density <= infillModel.get(i).percentageMax && steps > infillModel.get(i).stepsMin && steps <= infillModel.get(i).stepsMax) - { - return i; - } - } + id: infillSlider - return -1; + anchors.top: selectedInfillRateText.bottom + anchors.left: parent.left + UM.Theme.getSize("sidebar_margin").widt + + height: UM.Theme.getSize("sidebar_margin").height + width: infillCellRight.width - infillIcon.width - UM.Theme.getSize("sidebar_margin").width + + minimumValue: 0 + maximumValue: 100 + stepSize: 10 + tickmarksEnabled: true + + // disable slider when gradual support is enabled + enabled: parseInt(infillSteps.properties.value) == 0 + + // set initial value from stack + value: parseInt(infillDensity.properties.value) + + onValueChanged: { + infillDensity.setPropertyValue("value", infillSlider.value) } - model: infillModel; - Item + style: SliderStyle { - width: childrenRect.width; - height: childrenRect.height; + groove: Rectangle { + id: groove + implicitWidth: 200 + implicitHeight: 2 + color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + radius: 1 + } - Rectangle - { - id: infillIconLining - - width: (infillCellRight.width - ((infillModel.count - 1) * UM.Theme.getSize("sidebar_margin").width)) / (infillModel.count); - height: width - - border.color: - { - if(!base.settingsEnabled) - { - return UM.Theme.getColor("setting_control_disabled_border") - } - else if(infillListView.activeIndex == index) - { - return UM.Theme.getColor("setting_control_selected") - } - else if(infillMouseArea.containsMouse) - { - return UM.Theme.getColor("setting_control_border_highlight") - } - return UM.Theme.getColor("setting_control_border") - } - border.width: UM.Theme.getSize("default_lining").width - color: - { - if(infillListView.activeIndex == index) - { - if(!base.settingsEnabled) - { - return UM.Theme.getColor("setting_control_disabled_text") - } - return UM.Theme.getColor("setting_control_selected") - } - return "transparent" - } - - UM.RecolorImage - { - id: infillIcon - anchors.fill: parent; - anchors.margins: 2 - - sourceSize.width: width - sourceSize.height: width - source: UM.Theme.getIcon(model.icon); - color: { - if(infillListView.activeIndex == index) - { - return UM.Theme.getColor("text_emphasis") - } - if(!base.settingsEnabled) - { - return UM.Theme.getColor("setting_control_disabled_text") - } - return UM.Theme.getColor("setting_control_disabled_text") - } - } - - MouseArea - { - id: infillMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: base.settingsEnabled - onClicked: { - if (infillListView.activeIndex != index) - { - infillDensity.setPropertyValue("value", model.percentage) - infillSteps.setPropertyValue("value", model.steps) - } - } - onEntered: - { - base.showTooltip(infillCellRight, Qt.point(-infillCellRight.x, 0), model.text); - } - onExited: - { - base.hideTooltip(); - } + handle: Item { + Rectangle { + id: handleButton + anchors.centerIn: parent + color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + implicitWidth: 10 + implicitHeight: 10 + radius: 10 } } - Text - { - id: infillLabel - width: (infillCellRight.width - ((infillModel.count - 1) * UM.Theme.getSize("sidebar_margin").width)) / (infillModel.count); - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - wrapMode: Text.WordWrap - font: UM.Theme.getFont("default") - anchors.top: infillIconLining.bottom - anchors.horizontalCenter: infillIconLining.horizontalCenter - color: infillListView.activeIndex == index ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_border") - text: name + + tickmarks: Repeater { + id: repeater + model: control.maximumValue / control.stepSize + 1 + Rectangle { + anchors.verticalCenter: parent.verticalCenter + color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + width: 1 + height: 6 + y: 0 + x: styleData.handleWidth / 2 + index * ((repeater.width - styleData.handleWidth) / (repeater.count-1)) + } } } } + Item + { + width: (infillCellRight.width / 5) - (UM.Theme.getSize("sidebar_margin").width) + height: width + + anchors.right: infillCellRight.right + anchors.top: infillSlider.top + + // we loop over all density icons and only show the one that has the current density and steps + Repeater + { + id: infillIconList + model: infillModel + + property int activeIndex: { + for (var i = 0; i < infillModel.count; i++) { + var density = parseInt(infillDensity.properties.value) + var steps = parseInt(infillSteps.properties.value) + var infillModelItem = infillModel.get(i) + + if (density >= infillModelItem.percentageMin + && density <= infillModelItem.percentageMax + && steps >= infillModelItem.stepsMin + && steps <= infillModelItem.stepsMax){ + return i + } + } + return -1 + } + + Item { + anchors.fill: parent + + Rectangle { + anchors.fill: parent + visible: infillIconList.activeIndex == index + + UM.RecolorImage { + id: infillIcon + anchors.fill: parent + sourceSize.width: width + sourceSize.height: width + source: UM.Theme.getIcon(model.icon) + color: UM.Theme.getColor("quality_slider_available") + } + } + } + } + } + + // Gradual Support Infill Checkbox + CheckBox { + id: enableGradualInfillCheckBox + property alias _hovered: enableGradualInfillMouseArea.containsMouse + + anchors.top: infillSlider.bottom + anchors.topMargin: UM.Theme.getSize("sidebar_margin").height + anchors.left: infillCellRight.left + + style: UM.Theme.styles.checkbox + enabled: base.settingsEnabled + checked: parseInt(infillSteps.properties.value) > 0 + + MouseArea { + id: enableGradualInfillMouseArea + + anchors.fill: parent + hoverEnabled: true + enabled: true + + onClicked: { + infillSteps.setPropertyValue("value", (parseInt(infillSteps.properties.value) == 0) ? 5 : 0) + infillDensity.setPropertyValue("value", 90) + } + + onEntered: { + base.showTooltip(enableGradualInfillCheckBox, Qt.point(-infillCellRight.x, 0), + catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top.")) + } + + onExited: { + base.hideTooltip() + } + } + + Text { + id: gradualInfillLabel + anchors.left: enableGradualInfillCheckBox.right + anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width / 2 // FIXME better margin value + text: catalog.i18nc("@label", "Enable gradual") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + } + } + + // Infill list model for mapping icon ListModel { id: infillModel - Component.onCompleted: { infillModel.append({ - name: catalog.i18nc("@label", "0%"), - percentage: 0, - steps: 0, percentageMin: -1, percentageMax: 0, stepsMin: -1, stepsMax: 0, - text: catalog.i18nc("@label", "Empty infill will leave your model hollow with low strength."), icon: "hollow" }) infillModel.append({ - name: catalog.i18nc("@label", "20%"), - percentage: 20, - steps: 0, percentageMin: 0, - percentageMax: 30, + percentageMax: 40, stepsMin: -1, stepsMax: 0, - text: catalog.i18nc("@label", "Light (20%) infill will give your model an average strength."), icon: "sparse" }) infillModel.append({ - name: catalog.i18nc("@label", "50%"), - percentage: 50, - steps: 0, - percentageMin: 30, - percentageMax: 70, + percentageMin: 40, + percentageMax: 89, stepsMin: -1, stepsMax: 0, - text: catalog.i18nc("@label", "Dense (50%) infill will give your model an above average strength."), icon: "dense" }) infillModel.append({ - name: catalog.i18nc("@label", "100%"), - percentage: 100, - steps: 0, - percentageMin: 70, + percentageMin: 90, percentageMax: 9999999999, stepsMin: -1, stepsMax: 0, - text: catalog.i18nc("@label", "Solid (100%) infill will make your model completely solid."), icon: "solid" }) infillModel.append({ - name: catalog.i18nc("@label", "Gradual"), - percentage: 90, - steps: 5, percentageMin: 0, percentageMax: 9999999999, - stepsMin: 0, + stepsMin: 1, stepsMax: 9999999999, - infill_layer_height: 1.5, - text: catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top."), icon: "gradual" }) } } } + // + // Enable support + // Text { id: enableSupportLabel visible: enableSupportCheckBox.visible + + anchors.top: infillCellRight.bottom + anchors.topMargin: UM.Theme.getSize("sidebar_margin").height anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.verticalCenter: enableSupportCheckBox.verticalCenter + text: catalog.i18nc("@label", "Generate Support"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); @@ -845,7 +879,6 @@ Item anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width anchors.top: parent.top wrapMode: Text.WordWrap - //: Tips label text: catalog.i18nc("@label", "Need help improving your prints?
Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting") font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); @@ -864,35 +897,9 @@ Item storeIndex: 0 } - Binding - { - target: infillDensity - property: "containerStackId" - value: - { - var activeMachineId = Cura.MachineManager.activeMachineId; - if (machineExtruderCount.properties.value > 1) - { - var infillExtruderNr = parseInt(infillExtruderNumber.properties.value); - if (infillExtruderNr >= 0) - { - activeMachineId = ExtruderManager.extruderIds[infillExtruderNumber.properties.value]; - } - else if (ExtruderManager.activeExtruderStackId) - { - activeMachineId = ExtruderManager.activeExtruderStackId; - } - } - - infillSteps.containerStackId = activeMachineId; - return activeMachineId; - } - } - UM.SettingPropertyProvider { id: infillDensity - containerStackId: Cura.MachineManager.activeStackId key: "infill_sparse_density" watchedProperties: [ "value" ] @@ -902,10 +909,9 @@ Item UM.SettingPropertyProvider { id: infillSteps - containerStackId: Cura.MachineManager.activeStackId key: "gradual_infill_steps" - watchedProperties: [ "value" ] + watchedProperties: ["value"] storeIndex: 0 }